Fix annotation hoverUnverified
b7c422e parent: 10cff72 modified
docs/design.md +67 -63 | @@ -12,53 +12,55 @@ Surfaces breathe through rounded geometry: pill buttons (`9999px`), `12px` card | ||
| 12 | 12 | |
| 13 | 13 | **Color-block rhythm (landing page):** Cream/forest hero → white card sections → House Green (`#1E3932`) feature band with white text → cream utility zone → House Green footer. |
| 14 | 14 | |
| 15 | +Logo is a stylized bee: body with horizontal stripes (like text lines on a page), semi-transparent wings that evoke open book pages, round eyes, curved antennae, and a small smile. The bee represents gleaning (collecting nectar/knowledge), social behavior (hives/communities), and reading (the striped body reads like lines of text, wings like turning pages). | |
| 16 | + | |
| 15 | 17 | ## 2. Color Palette |
| 16 | 18 | |
| 17 | 19 | ### Primary Greens |
| 18 | 20 | |
| 19 | -| Name | Hex | Role | | |
| 20 | -| --------------- | --------- | ------------------------------------------------ | | |
| 21 | -| Green Accent | `#00754A` | CTAs, active states, link hovers, brand accent | | |
| 22 | -| Green Dark | `#006241` | Headings on landing page, stronger brand moments | | |
| 23 | -| House Green | `#1E3932` | Dark bands, footer, feature sections | | |
| 24 | -| Green Uplift | `#2b5148` | Decorative accents, mid-dark green | | |
| 25 | -| Green Light | `#d4e9e2` | Light green utility surfaces, valid-state tints | | |
| 21 | +| Name | Hex | Role | | |
| 22 | +| ------------ | --------- | ------------------------------------------------ | | |
| 23 | +| Green Accent | `#00754A` | CTAs, active states, link hovers, brand accent | | |
| 24 | +| Green Dark | `#006241` | Headings on landing page, stronger brand moments | | |
| 25 | +| House Green | `#1E3932` | Dark bands, footer, feature sections | | |
| 26 | +| Green Uplift | `#2b5148` | Decorative accents, mid-dark green | | |
| 27 | +| Green Light | `#d4e9e2` | Light green utility surfaces, valid-state tints | | |
| 26 | 28 | |
| 27 | 29 | ### Dark Theme (default) |
| 28 | 30 | |
| 29 | -| Token | Value | Use | | |
| 30 | -| ------------------ | ------------------------------ | ------------------------------------ | | |
| 31 | -| `--spot-bg` | `#0f1f1a` | Page background, sidebar | | |
| 32 | -| `--spot-surface` | `#152b24` | Card background | | |
| 33 | -| `--spot-hover` | `#1a362e` | Hover state, input background | | |
| 34 | -| `--spot-text` | `#ffffff` | Primary text | | |
| 35 | -| `--spot-secondary` | `rgba(255,255,255,0.70)` | Secondary/metadata text | | |
| 36 | -| `--spot-body` | `rgba(255,255,255,0.87)` | Body copy, article content | | |
| 37 | -| `--spot-muted` | `rgba(255,255,255,0.25)` | Disabled/tertiary text | | |
| 38 | -| `--spot-divider` | `rgba(255,255,255,0.08)` | Borders, dividers | | |
| 39 | -| `--spot-outline` | `rgba(255,255,255,0.20)` | Button borders, input borders | | |
| 31 | +| Token | Value | Use | | |
| 32 | +| ------------------ | ------------------------ | ----------------------------- | | |
| 33 | +| `--spot-bg` | `#0f1f1a` | Page background, sidebar | | |
| 34 | +| `--spot-surface` | `#152b24` | Card background | | |
| 35 | +| `--spot-hover` | `#1a362e` | Hover state, input background | | |
| 36 | +| `--spot-text` | `#ffffff` | Primary text | | |
| 37 | +| `--spot-secondary` | `rgba(255,255,255,0.70)` | Secondary/metadata text | | |
| 38 | +| `--spot-body` | `rgba(255,255,255,0.87)` | Body copy, article content | | |
| 39 | +| `--spot-muted` | `rgba(255,255,255,0.25)` | Disabled/tertiary text | | |
| 40 | +| `--spot-divider` | `rgba(255,255,255,0.08)` | Borders, dividers | | |
| 41 | +| `--spot-outline` | `rgba(255,255,255,0.20)` | Button borders, input borders | | |
| 40 | 42 | |
| 41 | 43 | ### Light Theme |
| 42 | 44 | |
| 43 | -| Token | Value | Use | | |
| 44 | -| ------------------ | ------------------------------ | ------------------------------------ | | |
| 45 | -| `--spot-bg` | `#f2f0eb` | Page canvas (warm cream) | | |
| 46 | -| `--spot-surface` | `#ffffff` | Card background | | |
| 47 | -| `--spot-hover` | `#edebe9` | Hover state (ceramic) | | |
| 48 | -| `--spot-text` | `rgba(0,0,0,0.87)` | Primary text (warm black) | | |
| 49 | -| `--spot-secondary` | `rgba(0,0,0,0.58)` | Secondary/metadata text | | |
| 50 | -| `--spot-body` | `rgba(0,0,0,0.70)` | Body copy | | |
| 51 | -| `--spot-muted` | `rgba(0,0,0,0.25)` | Disabled/tertiary text | | |
| 52 | -| `--spot-divider` | `rgba(0,0,0,0.08)` | Borders, dividers | | |
| 53 | -| `--spot-outline` | `rgba(0,0,0,0.15)` | Button borders, input borders | | |
| 45 | +| Token | Value | Use | | |
| 46 | +| ------------------ | ------------------ | ----------------------------- | | |
| 47 | +| `--spot-bg` | `#f2f0eb` | Page canvas (warm cream) | | |
| 48 | +| `--spot-surface` | `#ffffff` | Card background | | |
| 49 | +| `--spot-hover` | `#edebe9` | Hover state (ceramic) | | |
| 50 | +| `--spot-text` | `rgba(0,0,0,0.87)` | Primary text (warm black) | | |
| 51 | +| `--spot-secondary` | `rgba(0,0,0,0.58)` | Secondary/metadata text | | |
| 52 | +| `--spot-body` | `rgba(0,0,0,0.70)` | Body copy | | |
| 53 | +| `--spot-muted` | `rgba(0,0,0,0.25)` | Disabled/tertiary text | | |
| 54 | +| `--spot-divider` | `rgba(0,0,0,0.08)` | Borders, dividers | | |
| 55 | +| `--spot-outline` | `rgba(0,0,0,0.15)` | Button borders, input borders | | |
| 54 | 56 | |
| 55 | 57 | ### Semantic |
| 56 | 58 | |
| 57 | -| Name | Hex | Use | | |
| 58 | -| ----- | --------- | ---------------- | | |
| 59 | -| Red | `#c82014` | Errors, likes | | |
| 60 | -| Orange| `#ffa42b` | Ratings, warnings| | |
| 61 | -| Blue | `#539df5` | External links | | |
| 59 | +| Name | Hex | Use | | |
| 60 | +| ------ | --------- | ----------------- | | |
| 61 | +| Red | `#c82014` | Errors, likes | | |
| 62 | +| Orange | `#ffa42b` | Ratings, warnings | | |
| 63 | +| Blue | `#539df5` | External links | | |
| 62 | 64 | |
| 63 | 65 | ## 3. Typography |
| 64 | 66 | |
| @@ -66,14 +68,14 @@ Surfaces breathe through rounded geometry: pill buttons (`9999px`), `12px` card | ||
| 66 | 68 | |
| 67 | 69 | **Global:** `letter-spacing: -0.01em` on body |
| 68 | 70 | |
| 69 | -| Role | Size | Weight | Tailwind Class | | |
| 70 | -| ------------- | ---------- | ------ | ------------------ | | |
| 71 | -| Page title | 24px | 700 | `text-2xl font-bold` | | |
| 72 | -| Section title | 18px | 600 | `text-lg font-semibold` | | |
| 73 | -| Body | 14px | 400 | `text-sm` | | |
| 74 | -| Small/meta | 12px | 400 | `text-xs` | | |
| 75 | -| Button label | 14px | 700 | `text-sm font-bold uppercase tracking-button` | | |
| 76 | -| Micro | 10px | 400 | `text-[10px]` | | |
| 71 | +| Role | Size | Weight | Tailwind Class | | |
| 72 | +| ------------- | ---- | ------ | --------------------------------------------- | | |
| 73 | +| Page title | 24px | 700 | `text-2xl font-bold` | | |
| 74 | +| Section title | 18px | 600 | `text-lg font-semibold` | | |
| 75 | +| Body | 14px | 400 | `text-sm` | | |
| 76 | +| Small/meta | 12px | 400 | `text-xs` | | |
| 77 | +| Button label | 14px | 700 | `text-sm font-bold uppercase tracking-button` | | |
| 78 | +| Micro | 10px | 400 | `text-[10px]` | | |
| 77 | 79 | |
| 78 | 80 | ## 4. Components |
| 79 | 81 | |
| @@ -82,11 +84,13 @@ Surfaces breathe through rounded geometry: pill buttons (`9999px`), `12px` card | ||
| 82 | 84 | All buttons use full-pill radius (`rounded-pill` = `9999px`). |
| 83 | 85 | |
| 84 | 86 | **Primary Filled:** |
| 87 | + | |
| 85 | 88 | ``` |
| 86 | 89 | bg-spot-green text-white rounded-pill px-5 py-2 text-sm font-bold uppercase tracking-button hover:brightness-110 transition |
| 87 | 90 | ``` |
| 88 | 91 | |
| 89 | 92 | **Primary Outlined:** |
| 93 | + | |
| 90 | 94 | ``` |
| 91 | 95 | border border-spot-outline text-spot-text rounded-pill px-4 py-1.5 text-xs font-bold uppercase tracking-button hover:border-spot-text transition |
| 92 | 96 | ``` |
| @@ -101,10 +105,10 @@ bg-spot-surface rounded-xl p-4 shadow-spot hover:bg-spot-hover-50 transition | ||
| 101 | 105 | |
| 102 | 106 | ### Shadows |
| 103 | 107 | |
| 104 | -| Token | Value | Use | | |
| 105 | -| -------------- | ---------------------------------------------------- | ------------ | | |
| 106 | -| `shadow-spot` | `0 0 0.5px rgba(0,0,0,0.14), 0 1px 1px rgba(0,0,0,0.24)` | Cards | | |
| 107 | -| `shadow-spot-heavy` | `0 0 6px rgba(0,0,0,0.24), 0 8px 12px rgba(0,0,0,0.14)` | Modals, hero | | |
| 108 | +| Token | Value | Use | | |
| 109 | +| ------------------- | -------------------------------------------------------- | ------------ | | |
| 110 | +| `shadow-spot` | `0 0 0.5px rgba(0,0,0,0.14), 0 1px 1px rgba(0,0,0,0.24)` | Cards | | |
| 111 | +| `shadow-spot-heavy` | `0 0 6px rgba(0,0,0,0.24), 0 8px 12px rgba(0,0,0,0.14)` | Modals, hero | | |
| 108 | 112 | |
| 109 | 113 | ### Navigation |
| 110 | 114 | |
| @@ -134,11 +138,11 @@ bg-spot-surface rounded-xl p-4 shadow-spot hover:bg-spot-hover-50 transition | ||
| 134 | 138 | |
| 135 | 139 | ### Responsive Breakpoints |
| 136 | 140 | |
| 137 | -| Name | Width | Nav behavior | | |
| 138 | -| ------- | --------- | ----------------------------------- | | |
| 139 | -| Mobile | < 768px | Bottom tab nav, stacked layouts | | |
| 140 | -| Tablet | 768–1023px| Bottom nav, wider gutters | | |
| 141 | -| Desktop | 1024px+ | Sidebar nav, 3-column grids | | |
| 141 | +| Name | Width | Nav behavior | | |
| 142 | +| ------- | ---------- | ------------------------------- | | |
| 143 | +| Mobile | < 768px | Bottom tab nav, stacked layouts | | |
| 144 | +| Tablet | 768–1023px | Bottom nav, wider gutters | | |
| 145 | +| Desktop | 1024px+ | Sidebar nav, 3-column grids | | |
| 142 | 146 | |
| 143 | 147 | ## 6. Tailwind Config |
| 144 | 148 | |
| @@ -154,15 +158,15 @@ All custom colors live under the `spot` namespace in `tailwind.config.js`. CSS v | ||
| 154 | 158 | |
| 155 | 159 | ## 8. Page Structure |
| 156 | 160 | |
| 157 | -| Page | Layout | Key Features | | |
| 158 | -| -------------- | ------------------------------ | --------------------------------------- | | |
| 159 | -| Index (landing)| Full-width, no sidebar | Hero with mockup, feature cols, dark band, CTA | | |
| 160 | -| Login | Centered card | Bluesky + Atmosphere sign-in buttons | | |
| 161 | -| Dashboard | 2/3 + 1/3 grid | Articles + trending/recommendations sidebar | | |
| 162 | -| Articles | Full-width list | Keyboard nav (j/k/o/m), mark-all-read | | |
| 163 | -| Article Detail | `max-w-3xl` centered | Content, like/share/read buttons, annotations | | |
| 164 | -| Feeds | 2/3 + 1/3 grid | Feed list with categories + add/import sidebar | | |
| 165 | -| Trending | Full-width list | Like/annotation counts on each article | | |
| 166 | -| Discover | Mixed grid | Recommendations + people + browse all | | |
| 167 | -| Annotations | Full-width list | Filter by article URL, load more | | |
| 168 | -| Profile | `max-w-2xl` centered | Avatar, stats, feeds, annotations | | |
| 161 | +| Page | Layout | Key Features | | |
| 162 | +| --------------- | ---------------------- | ---------------------------------------------- | | |
| 163 | +| Index (landing) | Full-width, no sidebar | Hero with mockup, feature cols, dark band, CTA | | |
| 164 | +| Login | Centered card | Bluesky + Atmosphere sign-in buttons | | |
| 165 | +| Dashboard | 2/3 + 1/3 grid | Articles + trending/recommendations sidebar | | |
| 166 | +| Articles | Full-width list | Keyboard nav (j/k/o/m), mark-all-read | | |
| 167 | +| Article Detail | `max-w-3xl` centered | Content, like/share/read buttons, annotations | | |
| 168 | +| Feeds | 2/3 + 1/3 grid | Feed list with categories + add/import sidebar | | |
| 169 | +| Trending | Full-width list | Like/annotation counts on each article | | |
| 170 | +| Discover | Mixed grid | Recommendations + people + browse all | | |
| 171 | +| Annotations | Full-width list | Filter by article URL, load more | | |
| 172 | +| Profile | `max-w-2xl` centered | Avatar, stats, feeds, annotations | | |
| @@ -12,53 +12,55 @@ Surfaces breathe through rounded geometry: pill buttons (`9999px`), `12px` card | |||
| 12 | 12 | ||
| 13 | **Color-block rhythm (landing page):** Cream/forest hero → white card sections → House Green (`#1E3932`) feature band with white text → cream utility zone → House Green footer. | 13 | **Color-block rhythm (landing page):** Cream/forest hero → white card sections → House Green (`#1E3932`) feature band with white text → cream utility zone → House Green footer. |
| 14 | 14 | ||
| 15 | +Logo is a stylized bee: body with horizontal stripes (like text lines on a page), semi-transparent wings that evoke open book pages, round eyes, curved antennae, and a small smile. The bee represents gleaning (collecting nectar/knowledge), social behavior (hives/communities), and reading (the striped body reads like lines of text, wings like turning pages). | ||
| 16 | + | ||
| 15 | ## 2. Color Palette | 17 | ## 2. Color Palette |
| 16 | 18 | ||
| 17 | ### Primary Greens | 19 | ### Primary Greens |
| 18 | 20 | ||
| 19 | -| Name | Hex | Role | | 21 | +| Name | Hex | Role | |
| 20 | -| --------------- | --------- | ------------------------------------------------ | | 22 | +| ------------ | --------- | ------------------------------------------------ | |
| 21 | -| Green Accent | `#00754A` | CTAs, active states, link hovers, brand accent | | 23 | +| Green Accent | `#00754A` | CTAs, active states, link hovers, brand accent | |
| 22 | -| Green Dark | `#006241` | Headings on landing page, stronger brand moments | | 24 | +| Green Dark | `#006241` | Headings on landing page, stronger brand moments | |
| 23 | -| House Green | `#1E3932` | Dark bands, footer, feature sections | | 25 | +| House Green | `#1E3932` | Dark bands, footer, feature sections | |
| 24 | -| Green Uplift | `#2b5148` | Decorative accents, mid-dark green | | 26 | +| Green Uplift | `#2b5148` | Decorative accents, mid-dark green | |
| 25 | -| Green Light | `#d4e9e2` | Light green utility surfaces, valid-state tints | | 27 | +| Green Light | `#d4e9e2` | Light green utility surfaces, valid-state tints | |
| 26 | 28 | ||
| 27 | ### Dark Theme (default) | 29 | ### Dark Theme (default) |
| 28 | 30 | ||
| 29 | -| Token | Value | Use | | 31 | +| Token | Value | Use | |
| 30 | -| ------------------ | ------------------------------ | ------------------------------------ | | 32 | +| ------------------ | ------------------------ | ----------------------------- | |
| 31 | -| `--spot-bg` | `#0f1f1a` | Page background, sidebar | | 33 | +| `--spot-bg` | `#0f1f1a` | Page background, sidebar | |
| 32 | -| `--spot-surface` | `#152b24` | Card background | | 34 | +| `--spot-surface` | `#152b24` | Card background | |
| 33 | -| `--spot-hover` | `#1a362e` | Hover state, input background | | 35 | +| `--spot-hover` | `#1a362e` | Hover state, input background | |
| 34 | -| `--spot-text` | `#ffffff` | Primary text | | 36 | +| `--spot-text` | `#ffffff` | Primary text | |
| 35 | -| `--spot-secondary` | `rgba(255,255,255,0.70)` | Secondary/metadata text | | 37 | +| `--spot-secondary` | `rgba(255,255,255,0.70)` | Secondary/metadata text | |
| 36 | -| `--spot-body` | `rgba(255,255,255,0.87)` | Body copy, article content | | 38 | +| `--spot-body` | `rgba(255,255,255,0.87)` | Body copy, article content | |
| 37 | -| `--spot-muted` | `rgba(255,255,255,0.25)` | Disabled/tertiary text | | 39 | +| `--spot-muted` | `rgba(255,255,255,0.25)` | Disabled/tertiary text | |
| 38 | -| `--spot-divider` | `rgba(255,255,255,0.08)` | Borders, dividers | | 40 | +| `--spot-divider` | `rgba(255,255,255,0.08)` | Borders, dividers | |
| 39 | -| `--spot-outline` | `rgba(255,255,255,0.20)` | Button borders, input borders | | 41 | +| `--spot-outline` | `rgba(255,255,255,0.20)` | Button borders, input borders | |
| 40 | 42 | ||
| 41 | ### Light Theme | 43 | ### Light Theme |
| 42 | 44 | ||
| 43 | -| Token | Value | Use | | 45 | +| Token | Value | Use | |
| 44 | -| ------------------ | ------------------------------ | ------------------------------------ | | 46 | +| ------------------ | ------------------ | ----------------------------- | |
| 45 | -| `--spot-bg` | `#f2f0eb` | Page canvas (warm cream) | | 47 | +| `--spot-bg` | `#f2f0eb` | Page canvas (warm cream) | |
| 46 | -| `--spot-surface` | `#ffffff` | Card background | | 48 | +| `--spot-surface` | `#ffffff` | Card background | |
| 47 | -| `--spot-hover` | `#edebe9` | Hover state (ceramic) | | 49 | +| `--spot-hover` | `#edebe9` | Hover state (ceramic) | |
| 48 | -| `--spot-text` | `rgba(0,0,0,0.87)` | Primary text (warm black) | | 50 | +| `--spot-text` | `rgba(0,0,0,0.87)` | Primary text (warm black) | |
| 49 | -| `--spot-secondary` | `rgba(0,0,0,0.58)` | Secondary/metadata text | | 51 | +| `--spot-secondary` | `rgba(0,0,0,0.58)` | Secondary/metadata text | |
| 50 | -| `--spot-body` | `rgba(0,0,0,0.70)` | Body copy | | 52 | +| `--spot-body` | `rgba(0,0,0,0.70)` | Body copy | |
| 51 | -| `--spot-muted` | `rgba(0,0,0,0.25)` | Disabled/tertiary text | | 53 | +| `--spot-muted` | `rgba(0,0,0,0.25)` | Disabled/tertiary text | |
| 52 | -| `--spot-divider` | `rgba(0,0,0,0.08)` | Borders, dividers | | 54 | +| `--spot-divider` | `rgba(0,0,0,0.08)` | Borders, dividers | |
| 53 | -| `--spot-outline` | `rgba(0,0,0,0.15)` | Button borders, input borders | | 55 | +| `--spot-outline` | `rgba(0,0,0,0.15)` | Button borders, input borders | |
| 54 | 56 | ||
| 55 | ### Semantic | 57 | ### Semantic |
| 56 | 58 | ||
| 57 | -| Name | Hex | Use | | 59 | +| Name | Hex | Use | |
| 58 | -| ----- | --------- | ---------------- | | 60 | +| ------ | --------- | ----------------- | |
| 59 | -| Red | `#c82014` | Errors, likes | | 61 | +| Red | `#c82014` | Errors, likes | |
| 60 | -| Orange| `#ffa42b` | Ratings, warnings| | 62 | +| Orange | `#ffa42b` | Ratings, warnings | |
| 61 | -| Blue | `#539df5` | External links | | 63 | +| Blue | `#539df5` | External links | |
| 62 | 64 | ||
| 63 | ## 3. Typography | 65 | ## 3. Typography |
| 64 | 66 | ||
| @@ -66,14 +68,14 @@ Surfaces breathe through rounded geometry: pill buttons (`9999px`), `12px` card | |||
| 66 | 68 | ||
| 67 | **Global:** `letter-spacing: -0.01em` on body | 69 | **Global:** `letter-spacing: -0.01em` on body |
| 68 | 70 | ||
| 69 | -| Role | Size | Weight | Tailwind Class | | 71 | +| Role | Size | Weight | Tailwind Class | |
| 70 | -| ------------- | ---------- | ------ | ------------------ | | 72 | +| ------------- | ---- | ------ | --------------------------------------------- | |
| 71 | -| Page title | 24px | 700 | `text-2xl font-bold` | | 73 | +| Page title | 24px | 700 | `text-2xl font-bold` | |
| 72 | -| Section title | 18px | 600 | `text-lg font-semibold` | | 74 | +| Section title | 18px | 600 | `text-lg font-semibold` | |
| 73 | -| Body | 14px | 400 | `text-sm` | | 75 | +| Body | 14px | 400 | `text-sm` | |
| 74 | -| Small/meta | 12px | 400 | `text-xs` | | 76 | +| Small/meta | 12px | 400 | `text-xs` | |
| 75 | -| Button label | 14px | 700 | `text-sm font-bold uppercase tracking-button` | | 77 | +| Button label | 14px | 700 | `text-sm font-bold uppercase tracking-button` | |
| 76 | -| Micro | 10px | 400 | `text-[10px]` | | 78 | +| Micro | 10px | 400 | `text-[10px]` | |
| 77 | 79 | ||
| 78 | ## 4. Components | 80 | ## 4. Components |
| 79 | 81 | ||
| @@ -82,11 +84,13 @@ Surfaces breathe through rounded geometry: pill buttons (`9999px`), `12px` card | |||
| 82 | All buttons use full-pill radius (`rounded-pill` = `9999px`). | 84 | All buttons use full-pill radius (`rounded-pill` = `9999px`). |
| 83 | 85 | ||
| 84 | **Primary Filled:** | 86 | **Primary Filled:** |
| 87 | + | ||
| 85 | ``` | 88 | ``` |
| 86 | bg-spot-green text-white rounded-pill px-5 py-2 text-sm font-bold uppercase tracking-button hover:brightness-110 transition | 89 | bg-spot-green text-white rounded-pill px-5 py-2 text-sm font-bold uppercase tracking-button hover:brightness-110 transition |
| 87 | ``` | 90 | ``` |
| 88 | 91 | ||
| 89 | **Primary Outlined:** | 92 | **Primary Outlined:** |
| 93 | + | ||
| 90 | ``` | 94 | ``` |
| 91 | border border-spot-outline text-spot-text rounded-pill px-4 py-1.5 text-xs font-bold uppercase tracking-button hover:border-spot-text transition | 95 | border border-spot-outline text-spot-text rounded-pill px-4 py-1.5 text-xs font-bold uppercase tracking-button hover:border-spot-text transition |
| 92 | ``` | 96 | ``` |
| @@ -101,10 +105,10 @@ bg-spot-surface rounded-xl p-4 shadow-spot hover:bg-spot-hover-50 transition | |||
| 101 | 105 | ||
| 102 | ### Shadows | 106 | ### Shadows |
| 103 | 107 | ||
| 104 | -| Token | Value | Use | | 108 | +| Token | Value | Use | |
| 105 | -| -------------- | ---------------------------------------------------- | ------------ | | 109 | +| ------------------- | -------------------------------------------------------- | ------------ | |
| 106 | -| `shadow-spot` | `0 0 0.5px rgba(0,0,0,0.14), 0 1px 1px rgba(0,0,0,0.24)` | Cards | | 110 | +| `shadow-spot` | `0 0 0.5px rgba(0,0,0,0.14), 0 1px 1px rgba(0,0,0,0.24)` | Cards | |
| 107 | -| `shadow-spot-heavy` | `0 0 6px rgba(0,0,0,0.24), 0 8px 12px rgba(0,0,0,0.14)` | Modals, hero | | 111 | +| `shadow-spot-heavy` | `0 0 6px rgba(0,0,0,0.24), 0 8px 12px rgba(0,0,0,0.14)` | Modals, hero | |
| 108 | 112 | ||
| 109 | ### Navigation | 113 | ### Navigation |
| 110 | 114 | ||
| @@ -134,11 +138,11 @@ bg-spot-surface rounded-xl p-4 shadow-spot hover:bg-spot-hover-50 transition | |||
| 134 | 138 | ||
| 135 | ### Responsive Breakpoints | 139 | ### Responsive Breakpoints |
| 136 | 140 | ||
| 137 | -| Name | Width | Nav behavior | | 141 | +| Name | Width | Nav behavior | |
| 138 | -| ------- | --------- | ----------------------------------- | | 142 | +| ------- | ---------- | ------------------------------- | |
| 139 | -| Mobile | < 768px | Bottom tab nav, stacked layouts | | 143 | +| Mobile | < 768px | Bottom tab nav, stacked layouts | |
| 140 | -| Tablet | 768–1023px| Bottom nav, wider gutters | | 144 | +| Tablet | 768–1023px | Bottom nav, wider gutters | |
| 141 | -| Desktop | 1024px+ | Sidebar nav, 3-column grids | | 145 | +| Desktop | 1024px+ | Sidebar nav, 3-column grids | |
| 142 | 146 | ||
| 143 | ## 6. Tailwind Config | 147 | ## 6. Tailwind Config |
| 144 | 148 | ||
| @@ -154,15 +158,15 @@ All custom colors live under the `spot` namespace in `tailwind.config.js`. CSS v | |||
| 154 | 158 | ||
| 155 | ## 8. Page Structure | 159 | ## 8. Page Structure |
| 156 | 160 | ||
| 157 | -| Page | Layout | Key Features | | 161 | +| Page | Layout | Key Features | |
| 158 | -| -------------- | ------------------------------ | --------------------------------------- | | 162 | +| --------------- | ---------------------- | ---------------------------------------------- | |
| 159 | -| Index (landing)| Full-width, no sidebar | Hero with mockup, feature cols, dark band, CTA | | 163 | +| Index (landing) | Full-width, no sidebar | Hero with mockup, feature cols, dark band, CTA | |
| 160 | -| Login | Centered card | Bluesky + Atmosphere sign-in buttons | | 164 | +| Login | Centered card | Bluesky + Atmosphere sign-in buttons | |
| 161 | -| Dashboard | 2/3 + 1/3 grid | Articles + trending/recommendations sidebar | | 165 | +| Dashboard | 2/3 + 1/3 grid | Articles + trending/recommendations sidebar | |
| 162 | -| Articles | Full-width list | Keyboard nav (j/k/o/m), mark-all-read | | 166 | +| Articles | Full-width list | Keyboard nav (j/k/o/m), mark-all-read | |
| 163 | -| Article Detail | `max-w-3xl` centered | Content, like/share/read buttons, annotations | | 167 | +| Article Detail | `max-w-3xl` centered | Content, like/share/read buttons, annotations | |
| 164 | -| Feeds | 2/3 + 1/3 grid | Feed list with categories + add/import sidebar | | 168 | +| Feeds | 2/3 + 1/3 grid | Feed list with categories + add/import sidebar | |
| 165 | -| Trending | Full-width list | Like/annotation counts on each article | | 169 | +| Trending | Full-width list | Like/annotation counts on each article | |
| 166 | -| Discover | Mixed grid | Recommendations + people + browse all | | 170 | +| Discover | Mixed grid | Recommendations + people + browse all | |
| 167 | -| Annotations | Full-width list | Filter by article URL, load more | | 171 | +| Annotations | Full-width list | Filter by article URL, load more | |
| 168 | -| Profile | `max-w-2xl` centered | Avatar, stats, feeds, annotations | | 172 | +| Profile | `max-w-2xl` centered | Avatar, stats, feeds, annotations | |
modified
internal/tmpl/article_detail.html +33 -9 | @@ -66,23 +66,25 @@ | ||
| 66 | 66 | <section> |
| 67 | 67 | <h2 class="text-lg font-semibold text-spot-text mb-4">Annotations</h2> |
| 68 | 68 | |
| 69 | - <form hx-post="/library/create" hx-target="#annotations-list" hx-swap="beforeend" | |
| 69 | + <form id="annotation-form" hx-post="/library/create" hx-target="#annotations-list" hx-swap="beforeend" | |
| 70 | 70 | hx-on::after-request="this.reset()" |
| 71 | 71 | class="bg-spot-surface rounded-xl shadow-spot p-4 mb-4 space-y-3"> |
| 72 | 72 | {{csrfInput .CSRFToken}} |
| 73 | 73 | <input type="hidden" name="feed_url" value="{{.Article.FeedURL}}"> |
| 74 | 74 | <input type="hidden" name="article_url" value="{{if .Article.URL.Valid}}{{.Article.URL.String}}{{end}}"> |
| 75 | + <div id="quote-highlight" class="hidden mb-2"> | |
| 76 | + <blockquote id="quote-preview" class="border-l-2 border-spot-green pl-3 text-sm text-spot-secondary italic"></blockquote> | |
| 77 | + </div> | |
| 78 | + <input type="hidden" name="quote" id="quote-input"> | |
| 75 | 79 | <div> |
| 76 | 80 | <textarea name="note" rows="2" placeholder="Add a note..." |
| 77 | 81 | class="w-full bg-spot-hover text-spot-text rounded-lg px-4 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder resize-none"></textarea> |
| 78 | 82 | </div> |
| 79 | 83 | <div class="flex gap-2"> |
| 80 | - <input type="text" name="quote" placeholder="Quote (optional)" | |
| 81 | - class="flex-1 bg-spot-hover text-spot-text rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder"> | |
| 82 | 84 | <input type="text" name="tags" placeholder="Tags (comma separated)" |
| 83 | 85 | class="flex-1 bg-spot-hover text-spot-text rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder"> |
| 86 | + <button type="submit" class="bg-spot-green text-white rounded-pill px-5 py-2 text-sm font-bold uppercase tracking-button hover:brightness-110 transition">Annotate</button> | |
| 84 | 87 | </div> |
| 85 | - <button type="submit" class="bg-spot-green text-white rounded-pill px-5 py-2 text-sm font-bold uppercase tracking-button hover:brightness-110 transition">Annotate</button> | |
| 86 | 88 | </form> |
| 87 | 89 | |
| 88 | 90 | <div id="annotations-list" class="space-y-3"> |
| @@ -97,11 +99,33 @@ | ||
| 97 | 99 | |
| 98 | 100 | <script> |
| 99 | 101 | (function() { |
| 100 | - var readScrollPos = 0; | |
| 101 | - var articleBody = document.querySelector('.article-body'); | |
| 102 | - if (articleBody) { | |
| 103 | - readScrollPos = window.scrollY; | |
| 104 | - } | |
| 102 | + var form = document.getElementById('annotation-form'); | |
| 103 | + var quoteInput = document.getElementById('quote-input'); | |
| 104 | + var quotePreview = document.getElementById('quote-preview'); | |
| 105 | + var quoteHighlight = document.getElementById('quote-highlight'); | |
| 106 | + | |
| 107 | + document.addEventListener('mouseup', function(e) { | |
| 108 | + var sel = window.getSelection(); | |
| 109 | + var text = sel.toString().trim(); | |
| 110 | + if (!text) return; | |
| 111 | + | |
| 112 | + var body = e.target.closest('.article-body'); | |
| 113 | + if (!body) return; | |
| 114 | + | |
| 115 | + if (text.length > 1000) text = text.substring(0, 1000); | |
| 116 | + quoteInput.value = text; | |
| 117 | + quotePreview.textContent = text; | |
| 118 | + quoteHighlight.classList.remove('hidden'); | |
| 119 | + form.scrollIntoView({ behavior: 'smooth', block: 'center' }); | |
| 120 | + form.querySelector('textarea[name="note"]').focus(); | |
| 121 | + }); | |
| 122 | + | |
| 123 | + var origReset = form.reset.bind(form); | |
| 124 | + form.reset = function() { | |
| 125 | + origReset(); | |
| 126 | + quoteInput.value = ''; | |
| 127 | + quoteHighlight.classList.add('hidden'); | |
| 128 | + }; | |
| 105 | 129 | |
| 106 | 130 | document.addEventListener('keydown', function(e) { |
| 107 | 131 | if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; |
| @@ -66,23 +66,25 @@ | |||
| 66 | <section> | 66 | <section> |
| 67 | <h2 class="text-lg font-semibold text-spot-text mb-4">Annotations</h2> | 67 | <h2 class="text-lg font-semibold text-spot-text mb-4">Annotations</h2> |
| 68 | 68 | ||
| 69 | - <form hx-post="/library/create" hx-target="#annotations-list" hx-swap="beforeend" | 69 | + <form id="annotation-form" hx-post="/library/create" hx-target="#annotations-list" hx-swap="beforeend" |
| 70 | hx-on::after-request="this.reset()" | 70 | hx-on::after-request="this.reset()" |
| 71 | class="bg-spot-surface rounded-xl shadow-spot p-4 mb-4 space-y-3"> | 71 | class="bg-spot-surface rounded-xl shadow-spot p-4 mb-4 space-y-3"> |
| 72 | {{csrfInput .CSRFToken}} | 72 | {{csrfInput .CSRFToken}} |
| 73 | <input type="hidden" name="feed_url" value="{{.Article.FeedURL}}"> | 73 | <input type="hidden" name="feed_url" value="{{.Article.FeedURL}}"> |
| 74 | <input type="hidden" name="article_url" value="{{if .Article.URL.Valid}}{{.Article.URL.String}}{{end}}"> | 74 | <input type="hidden" name="article_url" value="{{if .Article.URL.Valid}}{{.Article.URL.String}}{{end}}"> |
| 75 | + <div id="quote-highlight" class="hidden mb-2"> | ||
| 76 | + <blockquote id="quote-preview" class="border-l-2 border-spot-green pl-3 text-sm text-spot-secondary italic"></blockquote> | ||
| 77 | + </div> | ||
| 78 | + <input type="hidden" name="quote" id="quote-input"> | ||
| 75 | <div> | 79 | <div> |
| 76 | <textarea name="note" rows="2" placeholder="Add a note..." | 80 | <textarea name="note" rows="2" placeholder="Add a note..." |
| 77 | class="w-full bg-spot-hover text-spot-text rounded-lg px-4 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder resize-none"></textarea> | 81 | class="w-full bg-spot-hover text-spot-text rounded-lg px-4 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder resize-none"></textarea> |
| 78 | </div> | 82 | </div> |
| 79 | <div class="flex gap-2"> | 83 | <div class="flex gap-2"> |
| 80 | - <input type="text" name="quote" placeholder="Quote (optional)" | ||
| 81 | - class="flex-1 bg-spot-hover text-spot-text rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder"> | ||
| 82 | <input type="text" name="tags" placeholder="Tags (comma separated)" | 84 | <input type="text" name="tags" placeholder="Tags (comma separated)" |
| 83 | class="flex-1 bg-spot-hover text-spot-text rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder"> | 85 | class="flex-1 bg-spot-hover text-spot-text rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder"> |
| 86 | + <button type="submit" class="bg-spot-green text-white rounded-pill px-5 py-2 text-sm font-bold uppercase tracking-button hover:brightness-110 transition">Annotate</button> | ||
| 84 | </div> | 87 | </div> |
| 85 | - <button type="submit" class="bg-spot-green text-white rounded-pill px-5 py-2 text-sm font-bold uppercase tracking-button hover:brightness-110 transition">Annotate</button> | ||
| 86 | </form> | 88 | </form> |
| 87 | 89 | ||
| 88 | <div id="annotations-list" class="space-y-3"> | 90 | <div id="annotations-list" class="space-y-3"> |
| @@ -97,11 +99,33 @@ | |||
| 97 | 99 | ||
| 98 | <script> | 100 | <script> |
| 99 | (function() { | 101 | (function() { |
| 100 | - var readScrollPos = 0; | 102 | + var form = document.getElementById('annotation-form'); |
| 101 | - var articleBody = document.querySelector('.article-body'); | 103 | + var quoteInput = document.getElementById('quote-input'); |
| 102 | - if (articleBody) { | 104 | + var quotePreview = document.getElementById('quote-preview'); |
| 103 | - readScrollPos = window.scrollY; | 105 | + var quoteHighlight = document.getElementById('quote-highlight'); |
| 104 | - } | 106 | + |
| 107 | + document.addEventListener('mouseup', function(e) { | ||
| 108 | + var sel = window.getSelection(); | ||
| 109 | + var text = sel.toString().trim(); | ||
| 110 | + if (!text) return; | ||
| 111 | + | ||
| 112 | + var body = e.target.closest('.article-body'); | ||
| 113 | + if (!body) return; | ||
| 114 | + | ||
| 115 | + if (text.length > 1000) text = text.substring(0, 1000); | ||
| 116 | + quoteInput.value = text; | ||
| 117 | + quotePreview.textContent = text; | ||
| 118 | + quoteHighlight.classList.remove('hidden'); | ||
| 119 | + form.scrollIntoView({ behavior: 'smooth', block: 'center' }); | ||
| 120 | + form.querySelector('textarea[name="note"]').focus(); | ||
| 121 | + }); | ||
| 122 | + | ||
| 123 | + var origReset = form.reset.bind(form); | ||
| 124 | + form.reset = function() { | ||
| 125 | + origReset(); | ||
| 126 | + quoteInput.value = ''; | ||
| 127 | + quoteHighlight.classList.add('hidden'); | ||
| 128 | + }; | ||
| 105 | 129 | ||
| 106 | document.addEventListener('keydown', function(e) { | 130 | document.addEventListener('keydown', function(e) { |
| 107 | if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; | 131 | if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; |
modified
internal/tmpl/base.html +27 -7 | @@ -220,15 +220,35 @@ | ||
| 220 | 220 | } |
| 221 | 221 | updateThemeIcons(document.documentElement.getAttribute('data-theme') || 'dark'); |
| 222 | 222 | |
| 223 | - function toggleAnnotate(btn) { | |
| 224 | - var card = btn.closest('article'); | |
| 225 | - var form = card.querySelector('.annotate-form'); | |
| 226 | - form.classList.toggle('hidden'); | |
| 227 | - if (!form.classList.contains('hidden')) { | |
| 228 | - form.querySelector('input[name="quote"]').focus(); | |
| 229 | - } | |
| 223 | + function closeAnnotate(el) { | |
| 224 | + var form = el.closest('.annotate-form'); | |
| 225 | + form.classList.add('hidden'); | |
| 226 | + form.querySelector('form').reset(); | |
| 230 | 227 | } |
| 231 | 228 | |
| 229 | + function openAnnotate(article, quote) { | |
| 230 | + var form = article.querySelector('.annotate-form'); | |
| 231 | + var quoteInput = form.querySelector('input[name="quote"]'); | |
| 232 | + if (quote) quoteInput.value = quote; | |
| 233 | + form.classList.remove('hidden'); | |
| 234 | + (quote ? form.querySelector('input[name="note"]') : quoteInput).focus(); | |
| 235 | + } | |
| 236 | + | |
| 237 | + document.addEventListener('mouseup', function(e) { | |
| 238 | + var sel = window.getSelection(); | |
| 239 | + var text = sel.toString().trim(); | |
| 240 | + if (!text) return; | |
| 241 | + | |
| 242 | + var article = e.target.closest('article[data-article-id]'); | |
| 243 | + if (!article) return; | |
| 244 | + | |
| 245 | + var form = article.querySelector('.annotate-form'); | |
| 246 | + if (form && !form.classList.contains('hidden')) return; | |
| 247 | + | |
| 248 | + if (text.length > 500) text = text.substring(0, 500); | |
| 249 | + openAnnotate(article, text); | |
| 250 | + }); | |
| 251 | + | |
| 232 | 252 | document.addEventListener('keydown', function(e) { |
| 233 | 253 | if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; |
| 234 | 254 | if (e.key === 'g') window.location.href = '/dashboard'; |
| @@ -220,15 +220,35 @@ | |||
| 220 | } | 220 | } |
| 221 | updateThemeIcons(document.documentElement.getAttribute('data-theme') || 'dark'); | 221 | updateThemeIcons(document.documentElement.getAttribute('data-theme') || 'dark'); |
| 222 | 222 | ||
| 223 | - function toggleAnnotate(btn) { | 223 | + function closeAnnotate(el) { |
| 224 | - var card = btn.closest('article'); | 224 | + var form = el.closest('.annotate-form'); |
| 225 | - var form = card.querySelector('.annotate-form'); | 225 | + form.classList.add('hidden'); |
| 226 | - form.classList.toggle('hidden'); | 226 | + form.querySelector('form').reset(); |
| 227 | - if (!form.classList.contains('hidden')) { | ||
| 228 | - form.querySelector('input[name="quote"]').focus(); | ||
| 229 | - } | ||
| 230 | } | 227 | } |
| 231 | 228 | ||
| 229 | + function openAnnotate(article, quote) { | ||
| 230 | + var form = article.querySelector('.annotate-form'); | ||
| 231 | + var quoteInput = form.querySelector('input[name="quote"]'); | ||
| 232 | + if (quote) quoteInput.value = quote; | ||
| 233 | + form.classList.remove('hidden'); | ||
| 234 | + (quote ? form.querySelector('input[name="note"]') : quoteInput).focus(); | ||
| 235 | + } | ||
| 236 | + | ||
| 237 | + document.addEventListener('mouseup', function(e) { | ||
| 238 | + var sel = window.getSelection(); | ||
| 239 | + var text = sel.toString().trim(); | ||
| 240 | + if (!text) return; | ||
| 241 | + | ||
| 242 | + var article = e.target.closest('article[data-article-id]'); | ||
| 243 | + if (!article) return; | ||
| 244 | + | ||
| 245 | + var form = article.querySelector('.annotate-form'); | ||
| 246 | + if (form && !form.classList.contains('hidden')) return; | ||
| 247 | + | ||
| 248 | + if (text.length > 500) text = text.substring(0, 500); | ||
| 249 | + openAnnotate(article, text); | ||
| 250 | + }); | ||
| 251 | + | ||
| 232 | document.addEventListener('keydown', function(e) { | 252 | document.addEventListener('keydown', function(e) { |
| 233 | if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; | 253 | if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; |
| 234 | if (e.key === 'g') window.location.href = '/dashboard'; | 254 | if (e.key === 'g') window.location.href = '/dashboard'; |
modified
internal/tmpl/partials/article-card.html +7 -9 | @@ -1,5 +1,5 @@ | ||
| 1 | 1 | {{define "article-card.html"}} |
| 2 | -<article data-article-id="{{.ID}}" class="group bg-spot-surface rounded-xl px-5 py-4 hover:bg-spot-hover-50 transition shadow-spot relative"> | |
| 2 | +<article data-article-id="{{.ID}}" data-feed-url="{{.FeedURL}}" data-article-url="{{if .URL.Valid}}{{.URL.String}}{{end}}" class="bg-spot-surface rounded-xl px-5 py-4 hover:bg-spot-hover-50 transition shadow-spot relative"> | |
| 3 | 3 | <div class="flex items-start justify-between gap-4"> |
| 4 | 4 | <div class="min-w-0 flex-1"> |
| 5 | 5 | <a href="/articles/{{.ID}}" class="font-bold text-spot-text hover:text-spot-green transition text-lg leading-tight">{{.Title}}</a> |
| @@ -14,21 +14,19 @@ | ||
| 14 | 14 | </div> |
| 15 | 15 | <div class="flex flex-col items-center gap-1 shrink-0"> |
| 16 | 16 | {{template "like-button.html" .}} |
| 17 | - <button type="button" onclick="toggleAnnotate(this)" class="opacity-0 group-hover:opacity-100 text-spot-muted hover:text-spot-green text-xs transition mt-1" title="Annotate"> | |
| 18 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z"/></svg> | |
| 19 | - </button> | |
| 20 | 17 | </div> |
| 21 | 18 | </div> |
| 22 | 19 | <div class="annotate-form hidden mt-3 pt-3 border-t border-spot-divider"> |
| 23 | - <form hx-post="/library/create" hx-swap="none" hx-on::after-request="toggleAnnotate(this.closest('.annotate-form').previousElementSibling)"> | |
| 20 | + <form hx-post="/library/create" hx-swap="none" hx-on::after-request="closeAnnotate(this)" class="space-y-2"> | |
| 24 | 21 | <input type="hidden" name="feed_url" value="{{.FeedURL}}"> |
| 25 | 22 | <input type="hidden" name="article_url" value="{{if .URL.Valid}}{{.URL.String}}{{end}}"> |
| 23 | + <input type="text" name="quote" placeholder="Quote a passage..." | |
| 24 | + class="w-full bg-spot-hover text-spot-text rounded-pill px-4 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder"> | |
| 26 | 25 | <div class="flex gap-2"> |
| 27 | - <input type="text" name="quote" placeholder="Quote a passage..." | |
| 26 | + <input type="text" name="note" placeholder="Add a note..." | |
| 28 | 27 | class="flex-1 bg-spot-hover text-spot-text rounded-pill px-4 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder"> |
| 29 | - <input type="text" name="note" placeholder="Note (optional)" | |
| 30 | - class="flex-1 bg-spot-hover text-spot-text rounded-pill px-4 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder"> | |
| 31 | - <button type="submit" class="bg-spot-green text-white rounded-pill px-4 py-1.5 text-xs font-bold uppercase tracking-button hover:brightness-110 transition">Save</button> | |
| 28 | + <button type="submit" class="bg-spot-green text-white rounded-pill px-4 py-1.5 text-xs font-bold uppercase tracking-button hover:brightness-110 transition">Annotate</button> | |
| 29 | + <button type="button" onclick="closeAnnotate(this)" class="text-spot-secondary hover:text-spot-text px-2 text-sm transition">×</button> | |
| 32 | 30 | </div> |
| 33 | 31 | </form> |
| 34 | 32 | </div> |
| @@ -1,5 +1,5 @@ | |||
| 1 | {{define "article-card.html"}} | 1 | {{define "article-card.html"}} |
| 2 | -<article data-article-id="{{.ID}}" class="group bg-spot-surface rounded-xl px-5 py-4 hover:bg-spot-hover-50 transition shadow-spot relative"> | 2 | +<article data-article-id="{{.ID}}" data-feed-url="{{.FeedURL}}" data-article-url="{{if .URL.Valid}}{{.URL.String}}{{end}}" class="bg-spot-surface rounded-xl px-5 py-4 hover:bg-spot-hover-50 transition shadow-spot relative"> |
| 3 | <div class="flex items-start justify-between gap-4"> | 3 | <div class="flex items-start justify-between gap-4"> |
| 4 | <div class="min-w-0 flex-1"> | 4 | <div class="min-w-0 flex-1"> |
| 5 | <a href="/articles/{{.ID}}" class="font-bold text-spot-text hover:text-spot-green transition text-lg leading-tight">{{.Title}}</a> | 5 | <a href="/articles/{{.ID}}" class="font-bold text-spot-text hover:text-spot-green transition text-lg leading-tight">{{.Title}}</a> |
| @@ -14,21 +14,19 @@ | |||
| 14 | </div> | 14 | </div> |
| 15 | <div class="flex flex-col items-center gap-1 shrink-0"> | 15 | <div class="flex flex-col items-center gap-1 shrink-0"> |
| 16 | {{template "like-button.html" .}} | 16 | {{template "like-button.html" .}} |
| 17 | - <button type="button" onclick="toggleAnnotate(this)" class="opacity-0 group-hover:opacity-100 text-spot-muted hover:text-spot-green text-xs transition mt-1" title="Annotate"> | ||
| 18 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z"/></svg> | ||
| 19 | - </button> | ||
| 20 | </div> | 17 | </div> |
| 21 | </div> | 18 | </div> |
| 22 | <div class="annotate-form hidden mt-3 pt-3 border-t border-spot-divider"> | 19 | <div class="annotate-form hidden mt-3 pt-3 border-t border-spot-divider"> |
| 23 | - <form hx-post="/library/create" hx-swap="none" hx-on::after-request="toggleAnnotate(this.closest('.annotate-form').previousElementSibling)"> | 20 | + <form hx-post="/library/create" hx-swap="none" hx-on::after-request="closeAnnotate(this)" class="space-y-2"> |
| 24 | <input type="hidden" name="feed_url" value="{{.FeedURL}}"> | 21 | <input type="hidden" name="feed_url" value="{{.FeedURL}}"> |
| 25 | <input type="hidden" name="article_url" value="{{if .URL.Valid}}{{.URL.String}}{{end}}"> | 22 | <input type="hidden" name="article_url" value="{{if .URL.Valid}}{{.URL.String}}{{end}}"> |
| 23 | + <input type="text" name="quote" placeholder="Quote a passage..." | ||
| 24 | + class="w-full bg-spot-hover text-spot-text rounded-pill px-4 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder"> | ||
| 26 | <div class="flex gap-2"> | 25 | <div class="flex gap-2"> |
| 27 | - <input type="text" name="quote" placeholder="Quote a passage..." | 26 | + <input type="text" name="note" placeholder="Add a note..." |
| 28 | class="flex-1 bg-spot-hover text-spot-text rounded-pill px-4 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder"> | 27 | class="flex-1 bg-spot-hover text-spot-text rounded-pill px-4 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder"> |
| 29 | - <input type="text" name="note" placeholder="Note (optional)" | 28 | + <button type="submit" class="bg-spot-green text-white rounded-pill px-4 py-1.5 text-xs font-bold uppercase tracking-button hover:brightness-110 transition">Annotate</button> |
| 30 | - class="flex-1 bg-spot-hover text-spot-text rounded-pill px-4 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-spot-green placeholder:text-spot-placeholder"> | 29 | + <button type="button" onclick="closeAnnotate(this)" class="text-spot-secondary hover:text-spot-text px-2 text-sm transition">×</button> |
| 31 | - <button type="submit" class="bg-spot-green text-white rounded-pill px-4 py-1.5 text-xs font-bold uppercase tracking-button hover:brightness-110 transition">Save</button> | ||
| 32 | </div> | 30 | </div> |
| 33 | </form> | 31 | </form> |
| 34 | </div> | 32 | </div> |