max / goingson
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
23 files changed,
+110 insertions,
-107 deletions
| @@ -3396,9 +3396,9 @@ | |||
| 3396 | 3396 | ||
| 3397 | 3397 | [[package]] | |
| 3398 | 3398 | name = "makeover-webview" | |
| 3399 | - | version = "0.4.0" | |
| 3399 | + | version = "0.5.0" | |
| 3400 | 3400 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3401 | - | checksum = "f9b3d9f5b5e7f6bc4ded9b6c14185ce5348d02882ec3260642ce400a5ad0a89f" | |
| 3401 | + | checksum = "c14aeac61c38f8413d049a1e2bb7ebc3541a116e9a2a730b1ae02b33bd72eb93" | |
| 3402 | 3402 | dependencies = [ | |
| 3403 | 3403 | "makeover-layout", | |
| 3404 | 3404 | ] |
| @@ -197,10 +197,10 @@ | |||
| 197 | 197 | <div class="page-header"> | |
| 198 | 198 | <h2 class="page-title">Problems</h2> | |
| 199 | 199 | <div class="row-flex row-flex-peer"> | |
| 200 | - | <select id="problems-source-filter" class="form-select form-select--compact" aria-label="Filter by source" data-change="problems.setSourceFilter"> | |
| 200 | + | <select id="problems-source-filter" class="field field--compact" aria-label="Filter by source" data-change="problems.setSourceFilter"> | |
| 201 | 201 | <option value="">All sources</option> | |
| 202 | 202 | </select> | |
| 203 | - | <select id="problems-status-filter" class="form-select form-select--compact" aria-label="Filter by status" data-change="problems.setStatusFilter"> | |
| 203 | + | <select id="problems-status-filter" class="field field--compact" aria-label="Filter by status" data-change="problems.setStatusFilter"> | |
| 204 | 204 | <option value="Open" selected>Open</option> | |
| 205 | 205 | <option value="Promoted">Promoted</option> | |
| 206 | 206 | <option value="Dismissed">Dismissed</option> | |
| @@ -478,11 +478,11 @@ | |||
| 478 | 478 | </div> | |
| 479 | 479 | </div> | |
| 480 | 480 | <div class="email-filter-row mb-peer"> | |
| 481 | - | <input type="text" class="form-input" id="email-search" placeholder="Search emails..." data-input="emails.search"> | |
| 482 | - | <select class="form-select" id="email-folder-filter" data-change="emails.filterByFolder"> | |
| 481 | + | <input type="text" class="field" id="email-search" placeholder="Search emails..." data-input="emails.search"> | |
| 482 | + | <select class="field" id="email-folder-filter" data-change="emails.filterByFolder"> | |
| 483 | 483 | <option value="">All folders</option> | |
| 484 | 484 | </select> | |
| 485 | - | <select class="form-select" id="email-label-filter" data-change="emails.filterByLabel"> | |
| 485 | + | <select class="field" id="email-label-filter" data-change="emails.filterByLabel"> | |
| 486 | 486 | <option value="">All labels</option> | |
| 487 | 487 | </select> | |
| 488 | 488 | <span id="email-count" class="filter-count" aria-live="polite"></span> | |
| @@ -518,7 +518,7 @@ | |||
| 518 | 518 | <div class="page-header"> | |
| 519 | 519 | <h2 class="page-title">Contacts</h2> | |
| 520 | 520 | <div class="contacts-filter-row"> | |
| 521 | - | <input type="text" class="form-input" id="contacts-search" placeholder="Search contacts..." data-input="contacts.filterBySearch"> | |
| 521 | + | <input type="text" class="field" id="contacts-search" placeholder="Search contacts..." data-input="contacts.filterBySearch"> | |
| 522 | 522 | <select class="filter-select" id="contacts-tag-filter" data-change="contacts.filterByTag"> | |
| 523 | 523 | <option value="">All Tags</option> | |
| 524 | 524 | </select> |
| @@ -8,11 +8,11 @@ | |||
| 8 | 8 | 2. Use a LAYOUT PRIMITIVE to position content (.row-flex + .row-flex-{peer, | |
| 9 | 9 | group,section}, .row, | |
| 10 | 10 | .stack-{peer,group,section}) | |
| 11 | - | 3. Use a COMPONENT PRIMITIVE for a UI element (.card, .button, .form-input, | |
| 12 | - | .form-select, .modal, .badge, | |
| 11 | + | 3. Use a COMPONENT PRIMITIVE for a UI element (.card, .button, .field, | |
| 12 | + | .modal, .badge, | |
| 13 | 13 | .tag, .toggle-switch) | |
| 14 | 14 | 4. Extend a primitive with a modifier (.button--primary, .button--sm, | |
| 15 | - | .form-select--compact, | |
| 15 | + | .field--compact, | |
| 16 | 16 | .subtask-item--linked) | |
| 17 | 17 | 5. ONLY THEN consider a new class | and add it to the right | |
| 18 | 18 | BAND below | |
| @@ -29,7 +29,7 @@ | |||
| 29 | 29 | encodes intent in browser flex-shrink math rather than in CSS that reads | |
| 30 | 30 | as intent, especially fragile when the row contains a native `<select>`, | |
| 31 | 31 | whose intrinsic-min-content sizing fights `flex: 1`. Smell test: if you | |
| 32 | - | find yourself reaching for `.form-select--compact`, `style="width: auto;"`, | |
| 32 | + | find yourself reaching for `.field--compact`, `style="width: auto;"`, | |
| 33 | 33 | or `min-width: 0 !important` to make a row lay out right, the layout | |
| 34 | 34 | itself wants a name. See `.email-filter-row`, `.contacts-filter-row`, and | |
| 35 | 35 | `.work-hours-row` (all 2026-05-24) for the canonical form. | |
| @@ -66,8 +66,8 @@ | |||
| 66 | 66 | 17. Email List | |
| 67 | 67 | 18. Toast Notifications | |
| 68 | 68 | 19. Modals | |
| 69 | - | 20. Form Elements | .form-input, | |
| 70 | - | .form-select, + | |
| 69 | + | 20. Form Elements | .field + kind by | |
| 70 | + | element, + | |
| 71 | 71 | JS-rendered layout | |
| 72 | 72 | utilities tail | |
| 73 | 73 | 21. Footer | |
| @@ -151,8 +151,8 @@ | |||
| 151 | 151 | COMPONENT PRIMITIVES | |
| 152 | 152 | .button + .button--primary / --secondary / --danger / --sm | |
| 153 | 153 | .card + .card--list-item / --shell / --muted (compact / container / info-panel) | |
| 154 | - | .form-input + .form-input--ghost | |
| 155 | - | .form-select + .form-select--compact / --ghost | |
| 154 | + | .field + .field--ghost / --compact (kind rides on the element: | |
| 155 | + | input / select / textarea) | |
| 156 | 156 | .modal + .modal-overlay | |
| 157 | 157 | .badge + variants ([data-color], --xs / --sm / --filled) | |
| 158 | 158 | .tag + variants ([data-color]) | |
| @@ -167,7 +167,7 @@ | |||
| 167 | 167 | CONTROL MODIFIERS | |
| 168 | 168 | Sizes: .button--sm | |
| 169 | 169 | Intents: .button--primary / --secondary / --danger | |
| 170 | - | Shapes: .form-select--compact / --ghost, .form-input--ghost | |
| 170 | + | Shapes: .field--compact / --ghost | |
| 171 | 171 | ||
| 172 | 172 | UI MODE STRATEGY (do not casually merge) | |
| 173 | 173 | ||
| @@ -367,7 +367,7 @@ | |||
| 367 | 367 | .mb-peer { margin-bottom: var(--gap-peer); } | |
| 368 | 368 | ||
| 369 | 369 | /* --- FORM SIZING UTILITIES */ | |
| 370 | - | .form-select--compact { width: auto; min-width: 120px; } | |
| 370 | + | .field--compact { width: auto; min-width: 120px; } | |
| 371 | 371 | .settings-heading { margin-bottom: var(--gap-section); font-family: var(--font-heading); } | |
| 372 | 372 | .settings-desc { font-size: var(--font-size-base); color: var(--content-secondary); margin-bottom: var(--gap-section); } | |
| 373 | 373 | ||
| @@ -731,7 +731,7 @@ | |||
| 731 | 731 | } | |
| 732 | 732 | ||
| 733 | 733 | /* 10. (vacated: Quick Add Input was deleted 2026-05-24; the modal at | |
| 734 | - | keyboard.js:openQuickAddModal uses .form-input, not a custom | |
| 734 | + | keyboard.js:openQuickAddModal uses .field, not a custom | |
| 735 | 735 | primitive. Section number kept for stable navigation.) */ | |
| 736 | 736 | ||
| 737 | 737 | /* 11. Cards */ | |
| @@ -1829,8 +1829,7 @@ | |||
| 1829 | 1829 | display: none; | |
| 1830 | 1830 | } | |
| 1831 | 1831 | ||
| 1832 | - | .recurrence-config .form-input, | |
| 1833 | - | .recurrence-config .form-select { | |
| 1832 | + | .recurrence-config .field { | |
| 1834 | 1833 | font-size: var(--font-size-base); | |
| 1835 | 1834 | padding: var(--gap-bound) var(--gap-peer); | |
| 1836 | 1835 | } | |
| @@ -1843,47 +1842,55 @@ | |||
| 1843 | 1842 | margin-bottom: var(--gap-bound); | |
| 1844 | 1843 | } | |
| 1845 | 1844 | ||
| 1846 | - | .form-input, | |
| 1847 | - | .form-select, | |
| 1848 | - | .form-textarea { | |
| 1845 | + | /* One class for all three kinds, which is what the shared rule always was. | |
| 1846 | + | Surface and inset edge come from the generated layout.css: a field is a | |
| 1847 | + | Depth::Well, so it is filled with --surface-well. | |
| 1848 | + | ||
| 1849 | + | This file used to say `background-color: var(--surface-raised)` under | |
| 1850 | + | `box-shadow: var(--bevel-inset)` -- a raised fill beneath a recessed edge, on | |
| 1851 | + | every input, select and textarea in the app, with :focus re-asserting it. That | |
| 1852 | + | is the exact disagreement Depth exists to make unrepresentable, and taking the | |
| 1853 | + | depth from one place is what fixes it. */ | |
| 1854 | + | .field { | |
| 1849 | 1855 | width: 100%; | |
| 1850 | 1856 | padding: var(--gap-peer) var(--gap-group); | |
| 1851 | 1857 | border: var(--border-width-sm) solid var(--border); | |
| 1852 | 1858 | border-radius: var(--radius-sm); | |
| 1853 | - | background-color: var(--surface-raised); | |
| 1854 | 1859 | color: var(--content); | |
| 1855 | 1860 | font-size: var(--font-size-lg); | |
| 1856 | - | box-shadow: var(--bevel-inset); | |
| 1857 | 1861 | } | |
| 1858 | 1862 | ||
| 1859 | - | /* The focus ring sits outside the well, so the inset bevel stays under it. */ | |
| 1860 | - | .form-input:focus, | |
| 1861 | - | .form-select:focus, | |
| 1862 | - | .form-textarea:focus { | |
| 1863 | + | /* The focus ring sits outside the well, so the inset bevel stays under it. | |
| 1864 | + | Composed rather than replacing, because box-shadow is not additive. */ | |
| 1865 | + | .field:focus { | |
| 1863 | 1866 | outline: none; | |
| 1864 | - | background-color: var(--surface-raised); | |
| 1865 | 1867 | box-shadow: var(--bevel-inset), 0 0 0 2px var(--action); | |
| 1866 | 1868 | } | |
| 1867 | 1869 | ||
| 1868 | - | .form-textarea { | |
| 1870 | + | /* Kind rides on the element, not on a second class. Every one of the 55 call | |
| 1871 | + | sites had the old .form-input class on an <input>, .form-select on a | |
| 1872 | + | <select> and .form-textarea on a <textarea>, with no exceptions, so the class | |
| 1873 | + | was saying what the tag already said. An element selector cannot be forgotten at a call | |
| 1874 | + | site the way a modifier class can. */ | |
| 1875 | + | textarea.field { | |
| 1869 | 1876 | min-height: 100px; | |
| 1870 | 1877 | resize: vertical; | |
| 1871 | 1878 | } | |
| 1872 | 1879 | ||
| 1873 | 1880 | /* Ghost variants, borderless / transparent inputs used in toolbar | |
| 1874 | 1881 | contexts (compose header rows). Strips chrome and reduces padding. */ | |
| 1875 | - | .form-input--ghost { | |
| 1882 | + | .field--ghost { | |
| 1876 | 1883 | background: transparent; | |
| 1877 | 1884 | border: none; | |
| 1878 | 1885 | box-shadow: none; | |
| 1879 | 1886 | padding: var(--gap-peer); | |
| 1880 | 1887 | font-size: var(--font-size-base); | |
| 1881 | 1888 | } | |
| 1882 | - | .form-input--ghost:focus { background: transparent; box-shadow: none; } | |
| 1883 | - | .form-select--ghost { | |
| 1889 | + | .field--ghost:focus { background: transparent; box-shadow: none; } | |
| 1890 | + | /* A ghost select still needs a surface: it keeps its native dropdown arrow, | |
| 1891 | + | which needs something behind it. */ | |
| 1892 | + | select.field--ghost { | |
| 1884 | 1893 | background: var(--surface-page); | |
| 1885 | - | padding: var(--gap-peer); | |
| 1886 | - | font-size: var(--font-size-base); | |
| 1887 | 1894 | } | |
| 1888 | 1895 | ||
| 1889 | 1896 | .form-actions { | |
| @@ -1894,16 +1901,15 @@ | |||
| 1894 | 1901 | } | |
| 1895 | 1902 | ||
| 1896 | 1903 | /* Form Validation */ | |
| 1897 | - | .form-input[aria-invalid="true"], | |
| 1898 | - | .form-select[aria-invalid="true"], | |
| 1899 | - | .form-textarea[aria-invalid="true"] { | |
| 1904 | + | /* The generated layout.css carries .field[aria-invalid="true"], keyed on the | |
| 1905 | + | ARIA attribute so the visual and accessible states cannot drift, and composing | |
| 1906 | + | the danger ring after the bevel so the well stays under it. Left here: the | |
| 1907 | + | border colour, and the stronger ring while focused. */ | |
| 1908 | + | .field[aria-invalid="true"] { | |
| 1900 | 1909 | border-color: var(--danger); | |
| 1901 | - | box-shadow: var(--bevel-inset), 0 0 0 2px color-mix(in srgb, var(--danger) 30%, transparent); | |
| 1902 | 1910 | } | |
| 1903 | 1911 | ||
| 1904 | - | .form-input[aria-invalid="true"]:focus, | |
| 1905 | - | .form-select[aria-invalid="true"]:focus, | |
| 1906 | - | .form-textarea[aria-invalid="true"]:focus { | |
| 1912 | + | .field[aria-invalid="true"]:focus { | |
| 1907 | 1913 | box-shadow: var(--bevel-inset), 0 0 0 2px var(--danger); | |
| 1908 | 1914 | } | |
| 1909 | 1915 | ||
| @@ -2771,7 +2777,7 @@ | |||
| 2771 | 2777 | NOTE on naming: .header-row / .header-label refer to the compose | |
| 2772 | 2778 | form's "header fields" (To, Cc, Subject), NOT the app header. Don't | |
| 2773 | 2779 | rename without grepping composeForm.buildFieldsHtml. The input/select | |
| 2774 | - | inside each row use .form-input--ghost / .form-select--ghost. */ | |
| 2780 | + | inside each row use .field--ghost / .field--ghost. */ | |
| 2775 | 2781 | .header-row { | |
| 2776 | 2782 | display: flex; | |
| 2777 | 2783 | align-items: center; | |
| @@ -3458,9 +3464,7 @@ | |||
| 3458 | 3464 | /* 28. Focus & Keyboard Accessibility */ | |
| 3459 | 3465 | .tab:focus-visible, | |
| 3460 | 3466 | .button:focus-visible, | |
| 3461 | - | .form-input:focus-visible, | |
| 3462 | - | .form-select:focus-visible, | |
| 3463 | - | .form-textarea:focus-visible, | |
| 3467 | + | .field:focus-visible, | |
| 3464 | 3468 | .card:focus-visible, | |
| 3465 | 3469 | .email-item:focus-visible, | |
| 3466 | 3470 | .task-row:focus-visible, | |
| @@ -5194,18 +5198,17 @@ | |||
| 5194 | 5198 | gap: var(--gap-peer); | |
| 5195 | 5199 | align-items: center; | |
| 5196 | 5200 | } | |
| 5197 | - | .email-filter-row > .form-input, | |
| 5198 | - | .email-filter-row > .form-select { | |
| 5201 | + | .email-filter-row > .field { | |
| 5199 | 5202 | width: 100%; | |
| 5200 | 5203 | min-width: 0; | |
| 5201 | 5204 | } | |
| 5202 | - | .email-filter-row > .form-select { | |
| 5205 | + | .email-filter-row > select.field { | |
| 5203 | 5206 | width: 9rem; | |
| 5204 | 5207 | } | |
| 5205 | 5208 | ||
| 5206 | 5209 | /* Contacts filter row: same shape as .email-filter-row (search fills, | |
| 5207 | 5210 | filter sizes to content, action button sizes to content). Tag filter | |
| 5208 | - | uses .filter-select rather than .form-select, but the layout rule is | |
| 5211 | + | uses .filter-select rather than .field, but the layout rule is | |
| 5209 | 5212 | identical. */ | |
| 5210 | 5213 | .contacts-filter-row { | |
| 5211 | 5214 | display: grid; | |
| @@ -5213,7 +5216,7 @@ | |||
| 5213 | 5216 | gap: var(--gap-peer); | |
| 5214 | 5217 | align-items: center; | |
| 5215 | 5218 | } | |
| 5216 | - | .contacts-filter-row > .form-input { | |
| 5219 | + | .contacts-filter-row > .field { | |
| 5217 | 5220 | width: 100%; | |
| 5218 | 5221 | min-width: 0; | |
| 5219 | 5222 | } | |
| @@ -5231,7 +5234,7 @@ | |||
| 5231 | 5234 | gap: var(--gap-bound); | |
| 5232 | 5235 | align-items: center; | |
| 5233 | 5236 | } | |
| 5234 | - | .work-hours-row > .form-select { | |
| 5237 | + | .work-hours-row > select.field { | |
| 5235 | 5238 | width: auto; | |
| 5236 | 5239 | } | |
| 5237 | 5240 | ||
| @@ -7570,12 +7573,12 @@ | |||
| 7570 | 7573 | } | |
| 7571 | 7574 | ||
| 7572 | 7575 | /* Email filter row: let selects shrink and wrap instead of forcing 120px. */ | |
| 7573 | - | .ui-mode-mobile #emails-view .form-select[id^="email-"] { | |
| 7576 | + | .ui-mode-mobile #emails-view select.field[id^="email-"] { | |
| 7574 | 7577 | min-width: 0 !important; | |
| 7575 | 7578 | flex: 1; | |
| 7576 | 7579 | } | |
| 7577 | 7580 | ||
| 7578 | - | .ui-mode-mobile .form-textarea { | |
| 7581 | + | .ui-mode-mobile textarea.field { | |
| 7579 | 7582 | min-height: 72px; | |
| 7580 | 7583 | } | |
| 7581 | 7584 | .ui-mode-mobile .modal-header h2, .ui-mode-mobile .modal-title { | |
| @@ -8900,7 +8903,7 @@ | |||
| 8900 | 8903 | margin-top: var(--gap-peer); | |
| 8901 | 8904 | } | |
| 8902 | 8905 | ||
| 8903 | - | .task-overview-add-form .form-input { | |
| 8906 | + | .task-overview-add-form .field { | |
| 8904 | 8907 | flex: 1; | |
| 8905 | 8908 | } | |
| 8906 | 8909 | ||
| @@ -9434,7 +9437,7 @@ | |||
| 9434 | 9437 | ||
| 9435 | 9438 | /* Saved Views modal (Run #27 UX) */ | |
| 9436 | 9439 | .saved-views-save { display: flex; gap: var(--gap-peer); align-items: center; flex-wrap: wrap; margin-bottom: var(--gap-section); } | |
| 9437 | - | .saved-views-save .form-input { flex: 1 1 auto; min-width: 160px; } | |
| 9440 | + | .saved-views-save .field { flex: 1 1 auto; min-width: 160px; } | |
| 9438 | 9441 | .saved-views-row { display: flex; gap: var(--gap-peer); align-items: center; } | |
| 9439 | 9442 | .saved-views-row .saved-views-apply { flex: 1 1 auto; text-align: left; } | |
| 9440 | 9443 | .saved-views-empty { color: var(--content-muted); } |
| @@ -433,7 +433,7 @@ | |||
| 433 | 433 | <p class="confirm-message">${esc(message)}</p> | |
| 434 | 434 | </div> | |
| 435 | 435 | <div class="form-group"> | |
| 436 | - | <input type="text" class="form-input" id="${inputId}" | |
| 436 | + | <input type="text" class="field" id="${inputId}" | |
| 437 | 437 | value="${escAttr(defaultValue)}" | |
| 438 | 438 | placeholder="${escAttr(placeholder)}" | |
| 439 | 439 | ${suggestions.length ? `list="${listId}" autocomplete="off"` : ''} |
| @@ -184,7 +184,7 @@ | |||
| 184 | 184 | ||
| 185 | 185 | switch (kind) { | |
| 186 | 186 | case 'textarea': | |
| 187 | - | inputHtml = `<textarea class="form-textarea" id="${inputId}" name="${field.name}" ${required} ${placeholder} ${extraAttrs}>${esc(value)}</textarea>`; | |
| 187 | + | inputHtml = `<textarea class="field" id="${inputId}" name="${field.name}" ${required} ${placeholder} ${extraAttrs}>${esc(value)}</textarea>`; | |
| 188 | 188 | break; | |
| 189 | 189 | case 'select': { | |
| 190 | 190 | const options = field.options || []; | |
| @@ -206,7 +206,7 @@ | |||
| 206 | 206 | const selected = (opt.selected || opt.value === value) ? 'selected' : ''; | |
| 207 | 207 | return `<option value="${escAttr(opt.value)}" ${selected}>${esc(opt.label)}</option>`; | |
| 208 | 208 | }).join(''); | |
| 209 | - | inputHtml = `<select class="form-select" id="${inputId}" name="${field.name}" ${required} ${extraAttrs}>${strayHtml}${optionsHtml}</select>`; | |
| 209 | + | inputHtml = `<select class="field" id="${inputId}" name="${field.name}" ${required} ${extraAttrs}>${strayHtml}${optionsHtml}</select>`; | |
| 210 | 210 | break; | |
| 211 | 211 | } | |
| 212 | 212 | case 'checkbox': | |
| @@ -214,7 +214,7 @@ | |||
| 214 | 214 | inputHtml = `<label class="form-checkbox-label"><input type="checkbox" id="${inputId}" name="${field.name}" ${value ? 'checked' : ''} ${extraAttrs}><span>${esc(field.label || '')}</span></label>`; | |
| 215 | 215 | break; | |
| 216 | 216 | default: | |
| 217 | - | inputHtml = `<input type="${kind}" class="form-input" id="${inputId}" name="${field.name}" ${required} ${placeholder} value="${escAttr(value)}" ${extraAttrs}>`; | |
| 217 | + | inputHtml = `<input type="${kind}" class="field" id="${inputId}" name="${field.name}" ${required} ${placeholder} value="${escAttr(value)}" ${extraAttrs}>`; | |
| 218 | 218 | } | |
| 219 | 219 | ||
| 220 | 220 | const hintText = field.hint ? `<div class="form-hint">${esc(field.hint)}</div>` : ''; |
| @@ -187,26 +187,26 @@ | |||
| 187 | 187 | return ` | |
| 188 | 188 | <div class="header-row"> | |
| 189 | 189 | <label class="header-label" for="from-account">From:</label> | |
| 190 | - | <select class="form-select form-select--ghost flex-1" id="from-account" name="from-account" required> | |
| 190 | + | <select class="field field--ghost flex-1" id="from-account" name="from-account" required> | |
| 191 | 191 | ${accountOptionsHtml} | |
| 192 | 192 | </select> | |
| 193 | 193 | </div> | |
| 194 | 194 | <div class="header-row"> | |
| 195 | 195 | <label class="header-label" for="to-address">To:</label> | |
| 196 | 196 | <div class="autocomplete-wrapper"> | |
| 197 | - | <input type="text" class="form-input form-input--ghost flex-1" id="to-address" name="to-address" placeholder="recipient@example.com (comma-separated)" required autocomplete="off" value="${escAttr(prefill.to || '')}"> | |
| 197 | + | <input type="text" class="field field--ghost flex-1" id="to-address" name="to-address" placeholder="recipient@example.com (comma-separated)" required autocomplete="off" value="${escAttr(prefill.to || '')}"> | |
| 198 | 198 | </div> | |
| 199 | 199 | </div> | |
| 200 | 200 | <div class="header-row${ccRowHidden}" id="cc-row"> | |
| 201 | 201 | <label class="header-label" for="cc-address">CC:</label> | |
| 202 | 202 | <div class="autocomplete-wrapper"> | |
| 203 | - | <input type="text" class="form-input form-input--ghost flex-1" id="cc-address" name="cc-address" placeholder="cc@example.com (comma-separated)" autocomplete="off" value="${escAttr(prefill.cc || '')}"> | |
| 203 | + | <input type="text" class="field field--ghost flex-1" id="cc-address" name="cc-address" placeholder="cc@example.com (comma-separated)" autocomplete="off" value="${escAttr(prefill.cc || '')}"> | |
| 204 | 204 | </div> | |
| 205 | 205 | </div> | |
| 206 | 206 | <div class="header-row${ccRowHidden}" id="bcc-row"> | |
| 207 | 207 | <label class="header-label" for="bcc-address">BCC:</label> | |
| 208 | 208 | <div class="autocomplete-wrapper"> | |
| 209 | - | <input type="text" class="form-input form-input--ghost flex-1" id="bcc-address" name="bcc-address" placeholder="bcc@example.com (comma-separated)" autocomplete="off" value="${escAttr(prefill.bcc || '')}"> | |
| 209 | + | <input type="text" class="field field--ghost flex-1" id="bcc-address" name="bcc-address" placeholder="bcc@example.com (comma-separated)" autocomplete="off" value="${escAttr(prefill.bcc || '')}"> | |
| 210 | 210 | </div> | |
| 211 | 211 | </div> | |
| 212 | 212 | <div class="header-row header-row--tight"> | |
| @@ -215,7 +215,7 @@ | |||
| 215 | 215 | </div> | |
| 216 | 216 | <div class="header-row"> | |
| 217 | 217 | <label class="header-label" for="subject">Subject:</label> | |
| 218 | - | <input type="text" class="form-input form-input--ghost flex-1" id="subject" name="subject" placeholder="Subject" value="${escAttr(prefill.subject || '')}"> | |
| 218 | + | <input type="text" class="field field--ghost flex-1" id="subject" name="subject" placeholder="Subject" value="${escAttr(prefill.subject || '')}"> | |
| 219 | 219 | </div> | |
| 220 | 220 | <div class="body-container"> | |
| 221 | 221 | <textarea class="body-textarea" id="body" name="body"${bodyRowsAttr} placeholder="Write your message...">${esc(prefill.body || '')}</textarea> |
| @@ -289,7 +289,7 @@ | |||
| 289 | 289 | return ` | |
| 290 | 290 | <div class="form-group"> | |
| 291 | 291 | <label class="form-label" for="${escAttr(f.id)}">${esc(f.label)}</label> | |
| 292 | - | <input type="${escAttr(f.type)}" class="form-input" id="${escAttr(f.id)}" name="${escAttr(f.name)}"${f.required ? ' required' : ''}${f.placeholder ? ` placeholder="${escAttr(f.placeholder)}"` : ''}> | |
| 292 | + | <input type="${escAttr(f.type)}" class="field" id="${escAttr(f.id)}" name="${escAttr(f.name)}"${f.required ? ' required' : ''}${f.placeholder ? ` placeholder="${escAttr(f.placeholder)}"` : ''}> | |
| 293 | 293 | </div>`; | |
| 294 | 294 | }).join(''); | |
| 295 | 295 |
| @@ -119,7 +119,7 @@ | |||
| 119 | 119 | <form id="painted-event-form"> | |
| 120 | 120 | <div class="form-group"> | |
| 121 | 121 | <label class="form-label">What to create</label> | |
| 122 | - | <select class="form-select" name="item_mode" data-change="dayPlan.togglePaintMode" data-a1="@el"> | |
| 122 | + | <select class="field" name="item_mode" data-change="dayPlan.togglePaintMode" data-a1="@el"> | |
| 123 | 123 | <option value="event">Event</option> | |
| 124 | 124 | <option value="block">Time Block</option> | |
| 125 | 125 | <option value="task">Link to Task</option> | |
| @@ -129,7 +129,7 @@ | |||
| 129 | 129 | <div id="paint-task-fields" class="hidden"> | |
| 130 | 130 | <div class="form-group"> | |
| 131 | 131 | <label class="form-label">Task</label> | |
| 132 | - | <select class="form-select" name="linked_task_id"> | |
| 132 | + | <select class="field" name="linked_task_id"> | |
| 133 | 133 | <option value="">-- Select a task --</option> | |
| 134 | 134 | ${taskOptions} | |
| 135 | 135 | </select> | |
| @@ -139,7 +139,7 @@ | |||
| 139 | 139 | <div id="paint-block-fields" class="hidden"> | |
| 140 | 140 | <div class="form-group"> | |
| 141 | 141 | <label class="form-label">Block Type</label> | |
| 142 | - | <select class="form-select" name="block_type"> | |
| 142 | + | <select class="field" name="block_type"> | |
| 143 | 143 | <option value="free_time">Free Time</option> | |
| 144 | 144 | <option value="personal">Personal</option> | |
| 145 | 145 | <option value="vacation">Vacation</option> | |
| @@ -151,11 +151,11 @@ | |||
| 151 | 151 | <div id="standalone-event-fields"> | |
| 152 | 152 | <div class="form-group"> | |
| 153 | 153 | <label class="form-label">Title</label> | |
| 154 | - | <input type="text" class="form-input" name="title" placeholder="Event title"> | |
| 154 | + | <input type="text" class="field" name="title" placeholder="Event title"> | |
| 155 | 155 | </div> | |
| 156 | 156 | <div class="form-group" id="paint-description-group"> | |
| 157 | 157 | <label class="form-label">Description</label> | |
| 158 | - | <textarea class="form-textarea" name="description" placeholder="Details..."></textarea> | |
| 158 | + | <textarea class="field" name="description" placeholder="Details..."></textarea> | |
| 159 | 159 | </div> | |
| 160 | 160 | </div> | |
| 161 | 161 | ||
| @@ -163,19 +163,19 @@ | |||
| 163 | 163 | <div class="form-row" style="display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-group);"> | |
| 164 | 164 | <div class="form-group"> | |
| 165 | 165 | <label class="form-label">Start</label> | |
| 166 | - | <input type="datetime-local" class="form-input" name="start_time" value="${startISO}" | |
| 166 | + | <input type="datetime-local" class="field" name="start_time" value="${startISO}" | |
| 167 | 167 | data-change="dayPlan.updatePaintTimePreview"> | |
| 168 | 168 | </div> | |
| 169 | 169 | <div class="form-group"> | |
| 170 | 170 | <label class="form-label">End</label> | |
| 171 | - | <input type="datetime-local" class="form-input" name="end_time" value="${endISO}" | |
| 171 | + | <input type="datetime-local" class="field" name="end_time" value="${endISO}" | |
| 172 | 172 | data-change="dayPlan.updatePaintTimePreview"> | |
| 173 | 173 | </div> | |
| 174 | 174 | </div> | |
| 175 | 175 | ||
| 176 | 176 | <div class="form-group" id="paint-location-group"> | |
| 177 | 177 | <label class="form-label">Location</label> | |
| 178 | - | <input type="text" class="form-input" name="location" placeholder="Zoom / Office / etc."> | |
| 178 | + | <input type="text" class="field" name="location" placeholder="Zoom / Office / etc."> | |
| 179 | 179 | </div> | |
| 180 | 180 | ||
| 181 | 181 | <div class="form-actions"> |
| @@ -49,7 +49,7 @@ | |||
| 49 | 49 | ||
| 50 | 50 | <div class="form-group"> | |
| 51 | 51 | <label class="form-label" for="schedule-datetime">Or Choose Custom</label> | |
| 52 | - | <input type="datetime-local" id="schedule-datetime" class="form-input" | |
| 52 | + | <input type="datetime-local" id="schedule-datetime" class="field" | |
| 53 | 53 | min="${now.toISOString().slice(0, 16)}" | |
| 54 | 54 | value="${now.toISOString().slice(0, 16)}"> | |
| 55 | 55 | </div> |
| @@ -81,7 +81,7 @@ | |||
| 81 | 81 | ${ff({ kind: 'text', name: 'account_name', id: `${idPrefix}-name`, label: 'Account Name', value: values.accountName || '', placeholder: 'Personal, Work, etc.', required: true })} | |
| 82 | 82 | <div class="form-group"> | |
| 83 | 83 | <label class="form-label" for="${idPrefix}-email">Email Address</label> | |
| 84 | - | <input type="email" class="form-input" id="${idPrefix}-email" name="email_address" required placeholder="you@example.com" value="${escAttr(values.emailAddress || '')}"> | |
| 84 | + | <input type="email" class="field" id="${idPrefix}-email" name="email_address" required placeholder="you@example.com" value="${escAttr(values.emailAddress || '')}"> | |
| 85 | 85 | <div id="${idPrefix}-detect-status" class="email-detect-status"></div> | |
| 86 | 86 | <div id="${idPrefix}-detect-note" class="email-detect-note hidden"></div> | |
| 87 | 87 | </div> |
| @@ -104,7 +104,7 @@ | |||
| 104 | 104 | <form id="label-form" data-submit="emails._saveLabels" data-a1="${escAttr(emailId)}"> | |
| 105 | 105 | <div class="form-group"> | |
| 106 | 106 | <label class="form-label">Labels (comma-separated)</label> | |
| 107 | - | <input type="text" class="form-input" id="label-input" value="${escAttr((currentLabels || []).join(', '))}" | |
| 107 | + | <input type="text" class="field" id="label-input" value="${escAttr((currentLabels || []).join(', '))}" | |
| 108 | 108 | placeholder="work, important, follow-up" autofocus> | |
| 109 | 109 | ${existing.length > 0 ? `<div class="label-existing-line">Existing: ${existing.map(l => esc(l)).join(', ')}</div>` : ''} | |
| 110 | 110 | </div> | |
| @@ -146,7 +146,7 @@ | |||
| 146 | 146 | <form data-submit="emails._doMoveToFolder" data-a1="${escAttr(emailId)}"> | |
| 147 | 147 | <div class="form-group"> | |
| 148 | 148 | <label class="form-label">Move to folder</label> | |
| 149 | - | <input type="text" class="form-input" id="move-folder-input" placeholder="INBOX, Archive, Sent, ..." | |
| 149 | + | <input type="text" class="field" id="move-folder-input" placeholder="INBOX, Archive, Sent, ..." | |
| 150 | 150 | list="folder-suggestions" autofocus> | |
| 151 | 151 | <datalist id="folder-suggestions"> | |
| 152 | 152 | ${folders.map(f => `<option value="${escAttr(f)}">`).join('')} |
| @@ -627,7 +627,7 @@ | |||
| 627 | 627 | extraContent: (project ? ` | |
| 628 | 628 | <div class="form-group"> | |
| 629 | 629 | <label class="form-label">Project</label> | |
| 630 | - | <input type="text" class="form-input" value="${escAttr(project.name)}" disabled> | |
| 630 | + | <input type="text" class="field" value="${escAttr(project.name)}" disabled> | |
| 631 | 631 | </div> | |
| 632 | 632 | ` : '') + buildRemindersHtml(null), | |
| 633 | 633 | }); |
| @@ -305,7 +305,7 @@ | |||
| 305 | 305 | <form id="quick-add-form" data-submit="keyboard.submitQuickAdd" data-a1="@event"> | |
| 306 | 306 | <div class="form-group"> | |
| 307 | 307 | <label class="form-label">Quick Add Task</label> | |
| 308 | - | <input type="text" class="form-input" name="text" required | |
| 308 | + | <input type="text" class="field" name="text" required | |
| 309 | 309 | placeholder="Fix login bug @backend #urgent +H due:friday" | |
| 310 | 310 | autofocus | |
| 311 | 311 | data-input="keyboard._onQuickAddInput" data-a1="@el"> |
| @@ -68,7 +68,7 @@ | |||
| 68 | 68 | const fields = prompts.map(p => ` | |
| 69 | 69 | <div class="reflection-prompt"> | |
| 70 | 70 | <label class="form-label" for="${idPrefix}-${p.key}">${esc(p.label)}</label> | |
| 71 | - | <textarea id="${idPrefix}-${p.key}" class="reflection-textarea form-textarea" rows="3" | |
| 71 | + | <textarea id="${idPrefix}-${p.key}" class="reflection-textarea field" rows="3" | |
| 72 | 72 | placeholder="${escAttr(p.placeholder || '')}">${esc(p.value || '')}</textarea> | |
| 73 | 73 | </div> | |
| 74 | 74 | `).join(''); |
| @@ -401,7 +401,7 @@ | |||
| 401 | 401 | <form id="link-email-form" data-submit="projects.submitLinkEmail" data-a1="@event"> | |
| 402 | 402 | <div class="form-group"> | |
| 403 | 403 | <label class="form-label">Select Email to Link</label> | |
| 404 | - | <select class="form-select" name="email_id" required> | |
| 404 | + | <select class="field" name="email_id" required> | |
| 405 | 405 | <option value="">Choose an email...</option> | |
| 406 | 406 | ${emailOptions} | |
| 407 | 407 | </select> | |
| @@ -478,7 +478,7 @@ | |||
| 478 | 478 | <form id="share-project-form" data-submit="projects.submitShare" data-a1="@event" data-a2="${escAttr(id)}"> | |
| 479 | 479 | <div class="form-group"> | |
| 480 | 480 | <label class="form-label">Share with group</label> | |
| 481 | - | <select class="form-select" name="group_id" required>${options}</select> | |
| 481 | + | <select class="field" name="group_id" required>${options}</select> | |
| 482 | 482 | <p class="form-hint">The whole project (tasks, events, milestones, and attachments) becomes visible to that group's members.</p> | |
| 483 | 483 | </div> | |
| 484 | 484 | <div class="form-actions"> |
| @@ -57,7 +57,7 @@ | |||
| 57 | 57 | let html = ` | |
| 58 | 58 | <div class="saved-views-modal"> | |
| 59 | 59 | <div class="saved-views-save"> | |
| 60 | - | <input type="text" id="saved-view-name" class="form-input" placeholder="Name these filters" maxlength="100"> | |
| 60 | + | <input type="text" id="saved-view-name" class="field" placeholder="Name these filters" maxlength="100"> | |
| 61 | 61 | <label class="form-checkbox-label"><input type="checkbox" id="saved-view-pin"> <span>Pin</span></label> | |
| 62 | 62 | <button type="button" class="button button--primary" data-act="savedViews._save">Save current filters</button> | |
| 63 | 63 | </div>`; |