290 lines
8.8 KiB
Markdown
290 lines
8.8 KiB
Markdown
# ADR-003: Front-end Technology Stack
|
|
|
|
## Status
|
|
Accepted
|
|
|
|
## Context
|
|
StarPunk requires a front-end for:
|
|
1. Public interface (homepage, note permalinks) - Server-side rendered
|
|
2. Admin interface (note creation/editing) - Requires some interactivity
|
|
3. Progressive enhancement principle - Core functionality must work without JavaScript
|
|
|
|
The front-end must be minimal, elegant, and align with the "no client-side complexity" principle stated in CLAUDE.MD.
|
|
|
|
## Decision
|
|
|
|
### Public Interface: Server-Side Rendered HTML
|
|
- **Template Engine**: Jinja2 (included with Flask)
|
|
- **CSS**: Custom CSS (no framework)
|
|
- **JavaScript**: None required for V1
|
|
- **Build Tools**: None required
|
|
|
|
### Admin Interface: Enhanced Server-Side Rendering
|
|
- **Template Engine**: Jinja2 (included with Flask)
|
|
- **CSS**: Custom CSS (shared with public interface)
|
|
- **JavaScript**: Minimal vanilla JavaScript for markdown preview only
|
|
- **Build Tools**: None required
|
|
|
|
### Asset Management
|
|
- **CSS**: Single stylesheet served statically
|
|
- **JavaScript**: Single optional file for markdown preview
|
|
- **No bundler**: Direct file serving
|
|
- **No transpilation**: Modern browsers only (ES6+)
|
|
|
|
## Rationale
|
|
|
|
### Server-Side Rendering (SSR)
|
|
**Simplicity Score: 10/10**
|
|
- Zero build process
|
|
- No JavaScript framework complexity
|
|
- Direct Flask template rendering
|
|
- Familiar Jinja2 syntax
|
|
|
|
**Fitness Score: 10/10**
|
|
- Perfect for content-first site
|
|
- Faster initial page load
|
|
- Better SEO (though not critical for single-user)
|
|
- Works without JavaScript
|
|
- Easier to implement microformats
|
|
|
|
**Maintenance Score: 10/10**
|
|
- Jinja2 is stable and mature
|
|
- No framework version updates
|
|
- No npm dependency hell
|
|
- Templates are simple HTML
|
|
|
|
### No CSS Framework
|
|
**Simplicity Score: 10/10**
|
|
- Custom CSS is ~200 lines for entire site
|
|
- No unused classes or styles
|
|
- Full control over appearance
|
|
- No framework learning curve
|
|
|
|
**Fitness Score: 9/10**
|
|
- StarPunk needs minimal, elegant design
|
|
- Single theme, no customization needed
|
|
- Mobile-responsive can be achieved with simple media queries
|
|
- No complex components needed
|
|
|
|
### Minimal JavaScript Approach
|
|
**Simplicity Score: 9/10**
|
|
- Vanilla JavaScript only (no React/Vue/Svelte)
|
|
- Single purpose: markdown preview in admin
|
|
- Optional progressive enhancement
|
|
- No build step required
|
|
|
|
**Fitness Score: 10/10**
|
|
- Markdown preview improves UX but isn't required
|
|
- All functionality works without JavaScript
|
|
- Can use fetch API for preview without library
|
|
- Modern browser features are sufficient
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
- Zero build time
|
|
- No node_modules directory
|
|
- Instant development setup
|
|
- Fast page loads
|
|
- Works with JavaScript disabled
|
|
- Easy to understand and modify
|
|
- Microformats implementation is straightforward
|
|
- Complete control over HTML output
|
|
|
|
### Negative
|
|
- No TypeScript type checking
|
|
- No hot module replacement (but Flask auto-reload works)
|
|
- Manual CSS organization required
|
|
- Must write responsive CSS manually
|
|
|
|
### Mitigation
|
|
- Keep JavaScript minimal and well-commented
|
|
- Organize CSS with clear sections
|
|
- Use CSS custom properties for theming
|
|
- Test manually in multiple browsers
|
|
- Validate HTML with W3C validator
|
|
|
|
## Frontend File Structure
|
|
|
|
```
|
|
static/
|
|
├── css/
|
|
│ └── style.css # Single stylesheet for entire site
|
|
└── js/
|
|
└── preview.js # Optional markdown preview (admin only)
|
|
|
|
templates/
|
|
├── base.html # Base template with HTML structure
|
|
├── index.html # Homepage (note list)
|
|
├── note.html # Single note permalink
|
|
└── admin/
|
|
├── base.html # Admin base template
|
|
├── dashboard.html # Admin dashboard
|
|
├── new.html # Create new note
|
|
└── edit.html # Edit existing note
|
|
```
|
|
|
|
## CSS Architecture
|
|
|
|
### Custom CSS Properties (Variables)
|
|
```css
|
|
:root {
|
|
--color-text: #333;
|
|
--color-bg: #fff;
|
|
--color-link: #0066cc;
|
|
--color-border: #ddd;
|
|
--font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
--font-mono: 'SF Mono', Monaco, monospace;
|
|
--spacing-unit: 1rem;
|
|
--max-width: 42rem;
|
|
}
|
|
```
|
|
|
|
### Mobile-First Responsive Design
|
|
```css
|
|
/* Base: Mobile styles */
|
|
body { padding: 1rem; }
|
|
|
|
/* Tablet and up */
|
|
@media (min-width: 768px) {
|
|
body { padding: 2rem; }
|
|
}
|
|
```
|
|
|
|
## JavaScript Architecture
|
|
|
|
### Markdown Preview Implementation
|
|
```javascript
|
|
// static/js/preview.js
|
|
// Simple markdown preview using marked.js CDN (no build step)
|
|
// Progressive enhancement - form works without this
|
|
```
|
|
|
|
**Decision**: Use marked.js from CDN for client-side preview
|
|
- **Justification**: Same library as server-side (consistency)
|
|
- **Simplicity**: No bundling required
|
|
- **Reliability**: CDN delivers cached version
|
|
- **Alternative**: No preview (acceptable fallback)
|
|
|
|
## Template Organization
|
|
|
|
### Jinja2 Template Strategy
|
|
- **Inheritance**: Use base templates for common structure
|
|
- **Blocks**: Define clear content blocks for overriding
|
|
- **Macros**: Create reusable microformat snippets
|
|
- **Filters**: Use Jinja2 filters for date formatting
|
|
|
|
### Example Base Template Structure
|
|
```jinja2
|
|
{# templates/base.html #}
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>{% block title %}{{ site.title }}{% endblock %}</title>
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
|
<link rel="alternate" type="application/rss+xml" href="{{ url_for('feed') }}">
|
|
{% block head %}{% endblock %}
|
|
</head>
|
|
<body>
|
|
{% block content %}{% endblock %}
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
## Microformats Integration
|
|
|
|
Server-side rendering makes microformats implementation straightforward:
|
|
|
|
```jinja2
|
|
{# Macro for h-entry note rendering #}
|
|
{% macro render_note(note) %}
|
|
<article class="h-entry">
|
|
<div class="e-content">
|
|
{{ note.content_html | safe }}
|
|
</div>
|
|
<footer>
|
|
<a class="u-url" href="{{ url_for('note', slug=note.slug) }}">
|
|
<time class="dt-published" datetime="{{ note.created_at.isoformat() }}">
|
|
{{ note.created_at.strftime('%B %d, %Y') }}
|
|
</time>
|
|
</a>
|
|
</footer>
|
|
</article>
|
|
{% endmacro %}
|
|
```
|
|
|
|
## Build and Development Workflow
|
|
|
|
### Development
|
|
1. Run Flask development server: `flask run`
|
|
2. Edit templates/CSS/JS directly
|
|
3. Browser auto-refresh on template changes
|
|
4. No build step required
|
|
|
|
### Production
|
|
1. Copy static files to production
|
|
2. Templates are rendered on-demand
|
|
3. Optionally enable Flask caching for rendered HTML
|
|
4. Serve static assets with nginx/Apache (optional)
|
|
|
|
## Browser Support
|
|
- Modern browsers (Chrome 90+, Firefox 88+, Safari 14+, Edge 90+)
|
|
- Mobile browsers (iOS Safari 14+, Chrome Android 90+)
|
|
- Progressive enhancement ensures basic functionality on older browsers
|
|
|
|
## Alternatives Considered
|
|
|
|
### React/Vue/Svelte (Rejected)
|
|
- **Simplicity**: 2/10 - Requires build tools, npm, bundlers
|
|
- **Fitness**: 3/10 - Massive overkill for content site
|
|
- **Maintenance**: 5/10 - Constant framework updates
|
|
- **Verdict**: Violates "no client-side complexity" principle
|
|
|
|
### htmx (Considered)
|
|
- **Simplicity**: 8/10 - Single JavaScript file, declarative
|
|
- **Fitness**: 6/10 - Useful for dynamic updates, but not needed in V1
|
|
- **Maintenance**: 8/10 - Stable, minimal dependencies
|
|
- **Verdict**: Interesting for V2, but V1 doesn't need dynamic updates
|
|
|
|
### Alpine.js (Considered)
|
|
- **Simplicity**: 8/10 - Lightweight, declarative
|
|
- **Fitness**: 5/10 - Good for small interactions, but we barely need any
|
|
- **Maintenance**: 8/10 - Well maintained
|
|
- **Verdict**: Too much for the minimal JS we need
|
|
|
|
### Tailwind CSS (Rejected)
|
|
- **Simplicity**: 4/10 - Requires build process, large configuration
|
|
- **Fitness**: 3/10 - Utility-first doesn't fit minimal design needs
|
|
- **Maintenance**: 7/10 - Well maintained but heavy
|
|
- **Verdict**: Build process violates simplicity; custom CSS is sufficient
|
|
|
|
### Bootstrap/Bulma (Rejected)
|
|
- **Simplicity**: 5/10 - Large framework with many unused features
|
|
- **Fitness**: 3/10 - Component-heavy, we need minimal custom design
|
|
- **Maintenance**: 9/10 - Very stable
|
|
- **Verdict**: Too much CSS for what we need
|
|
|
|
### PicoCSS/Water.css (Considered)
|
|
- **Simplicity**: 9/10 - Classless CSS, just include and go
|
|
- **Fitness**: 7/10 - Good starting point but may not match design vision
|
|
- **Maintenance**: 8/10 - Maintained, simple
|
|
- **Verdict**: Close consideration, but custom CSS gives full control
|
|
|
|
## Standards Compliance
|
|
- Semantic HTML5 elements
|
|
- Valid HTML (W3C validator)
|
|
- Accessible forms and navigation
|
|
- Proper heading hierarchy
|
|
- ARIA labels where needed
|
|
- Mobile-responsive (viewport meta tag)
|
|
- Progressive enhancement (works without JS)
|
|
|
|
## References
|
|
- Jinja2 Documentation: https://jinja.palletsprojects.com/
|
|
- MDN Web Docs: https://developer.mozilla.org/
|
|
- Microformats2: http://microformats.org/wiki/h-entry
|
|
- Progressive Enhancement: https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement
|
|
- Semantic HTML: https://developer.mozilla.org/en-US/docs/Glossary/Semantics
|