-
+
- + + Texts + + +
diff --git a/public/css/app.css b/public/css/app.css new file mode 100644 index 0000000..767dddd --- /dev/null +++ b/public/css/app.css @@ -0,0 +1,527 @@ +/* ========================================================================= + Daily Goals - app.css + Single shared stylesheet. Sectioned for readability. + ========================================================================= */ + +/* ------------------------------------------------------------------------- + 1. Reset + ------------------------------------------------------------------------- */ + +*, +*::before, +*::after { + box-sizing: border-box; +} + +html, +body { + margin: 0; + padding: 0; +} + +img, +svg { + display: block; + max-width: 100%; +} + +button { + font: inherit; + color: inherit; + cursor: pointer; +} + +input, +textarea, +select { + font: inherit; + color: inherit; +} + +/* ------------------------------------------------------------------------- + 2. Design tokens + ------------------------------------------------------------------------- */ + +:root { + /* Color: warm, readable palette */ + --color-bg: #faf7f2; + --color-surface: #ffffff; + --color-surface-alt: #f3ede2; + --color-text: #2b2622; + --color-text-muted: #6b5d52; + --color-primary: #5a7a4f; + --color-primary-hover: #486340; + --color-accent: #8a5a3b; + --color-accent-hover: #6f4730; + --color-border: #e3dccf; + --color-border-strong: #c9bfae; + --color-danger: #a94442; + --color-success: #4f7a5a; + + /* Typography */ + --font-serif: Georgia, "Iowan Old Style", "Source Serif Pro", serif; + --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, + sans-serif; + --font-size-base: 1rem; + --font-size-sm: 0.875rem; + --font-size-lg: 1.125rem; + --font-size-h1: 2rem; + --font-size-h2: 1.5rem; + --font-size-h3: 1.25rem; + --line-height-base: 1.6; + --line-height-tight: 1.25; + + /* Spacing scale */ + --space-1: 0.25rem; + --space-2: 0.5rem; + --space-3: 0.75rem; + --space-4: 1rem; + --space-5: 1.5rem; + --space-6: 2rem; + --space-7: 3rem; + + /* Layout */ + --max-width: 42rem; + --max-width-wide: 60rem; + + /* Radii */ + --radius-sm: 4px; + --radius-md: 8px; + --radius-lg: 12px; + + /* Shadows */ + --shadow-sm: 0 1px 2px rgba(43, 38, 34, 0.06); + --shadow-md: 0 4px 12px rgba(43, 38, 34, 0.1); + --shadow-lg: 0 12px 32px rgba(43, 38, 34, 0.18); + + /* Transitions */ + --transition-fast: 120ms ease; + --transition-base: 200ms ease; +} + +/* ------------------------------------------------------------------------- + 3. Base elements + ------------------------------------------------------------------------- */ + +body { + background-color: var(--color-bg); + color: var(--color-text); + font-family: var(--font-sans); + font-size: var(--font-size-base); + line-height: var(--line-height-base); + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: var(--font-serif); + font-weight: 600; + line-height: var(--line-height-tight); + margin: 0; + color: var(--color-text); +} + +h1 { + font-size: var(--font-size-h1); +} + +h2 { + font-size: var(--font-size-h2); +} + +h3 { + font-size: var(--font-size-h3); +} + +p { + margin: 0; +} + +a { + color: var(--color-accent); + text-decoration: none; + transition: color var(--transition-fast); +} + +a:hover, +a:focus { + color: var(--color-accent-hover); + text-decoration: underline; +} + +ul, +ol { + margin: 0; + padding: 0; + list-style: none; +} + +label { + display: block; + font-size: var(--font-size-sm); + color: var(--color-text-muted); + font-weight: 500; +} + +input[type="text"], +input[type="email"], +input[type="password"], +input[type="date"], +input[type="number"], +textarea, +select { + display: block; + width: 100%; + margin-top: var(--space-1); + padding: var(--space-2) var(--space-3); + background-color: var(--color-surface); + color: var(--color-text); + border: 1px solid var(--color-border-strong); + border-radius: var(--radius-sm); + transition: border-color var(--transition-fast), + box-shadow var(--transition-fast); +} + +input:focus, +textarea:focus, +select:focus { + outline: none; + border-color: var(--color-primary); + box-shadow: 0 0 0 3px rgba(90, 122, 79, 0.15); +} + +button { + display: inline-block; + padding: var(--space-2) var(--space-4); + background-color: var(--color-surface); + color: var(--color-text); + border: 1px solid var(--color-border-strong); + border-radius: var(--radius-sm); + font-weight: 500; + transition: background-color var(--transition-fast), + border-color var(--transition-fast), color var(--transition-fast); +} + +button:hover, +button:focus { + background-color: var(--color-surface-alt); + border-color: var(--color-text-muted); +} + +form { + margin: 0; +} + +/* ------------------------------------------------------------------------- + 4. Layout primitives + ------------------------------------------------------------------------- */ + +.container { + width: 100%; + max-width: var(--max-width); + margin-inline: auto; + padding: var(--space-5) var(--space-4); +} + +.container-wide { + max-width: var(--max-width-wide); +} + +.stack > * + * { + margin-top: var(--space-4); +} + +.stack-sm > * + * { + margin-top: var(--space-2); +} + +.stack-lg > * + * { + margin-top: var(--space-6); +} + +.cluster { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--space-3); +} + +.cluster-end { + justify-content: flex-end; +} + +.cluster-between { + justify-content: space-between; +} + +.center { + display: flex; + align-items: center; + justify-content: center; +} + +/* ------------------------------------------------------------------------- + 5. Components + ------------------------------------------------------------------------- */ + +.site-header { + border-bottom: 1px solid var(--color-border); + padding: var(--space-3) var(--space-4); + background-color: var(--color-surface); +} + +.site-header .site-header-inner { + width: 100%; + max-width: var(--max-width); + margin-inline: auto; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: var(--space-3); +} + +.btn { + display: inline-block; + padding: var(--space-2) var(--space-4); + border-radius: var(--radius-sm); + border: 1px solid var(--color-border-strong); + background-color: var(--color-surface); + color: var(--color-text); + font-weight: 500; + text-decoration: none; + transition: background-color var(--transition-fast), + border-color var(--transition-fast), color var(--transition-fast); +} + +.btn:hover, +.btn:focus { + background-color: var(--color-surface-alt); + border-color: var(--color-text-muted); + text-decoration: none; +} + +.btn-primary { + background-color: var(--color-primary); + border-color: var(--color-primary); + color: #ffffff; +} + +.btn-primary:hover, +.btn-primary:focus { + background-color: var(--color-primary-hover); + border-color: var(--color-primary-hover); + color: #ffffff; +} + +.btn-secondary { + background-color: transparent; + border-color: var(--color-border-strong); + color: var(--color-text); +} + +.btn-danger { + background-color: transparent; + border-color: var(--color-danger); + color: var(--color-danger); +} + +.btn-danger:hover, +.btn-danger:focus { + background-color: var(--color-danger); + color: #ffffff; +} + +.card { + background-color: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + padding: var(--space-4); + box-shadow: var(--shadow-sm); +} + +.card-link { + display: block; + color: inherit; + text-decoration: none; + transition: border-color var(--transition-fast), + box-shadow var(--transition-fast), + transform var(--transition-fast); +} + +.card-link:hover, +.card-link:focus { + border-color: var(--color-border-strong); + box-shadow: var(--shadow-md); + text-decoration: none; +} + +.list-cards { + display: flex; + flex-direction: column; + gap: var(--space-3); +} + +.modal { + position: fixed; + inset: 0; + z-index: 50; + display: flex; + align-items: center; + justify-content: center; + padding: var(--space-4); + background-color: rgba(43, 38, 34, 0.45); +} + +.modal[hidden] { + display: none; +} + +.modal-content { + width: 100%; + max-width: 28rem; + background-color: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + box-shadow: var(--shadow-lg); + padding: var(--space-5); +} + +.error { + color: var(--color-danger); + font-size: var(--font-size-sm); +} + +.auth-shell { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding: var(--space-5) var(--space-4); +} + +.auth-card { + width: 100%; + max-width: 24rem; + background-color: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + box-shadow: var(--shadow-md); + padding: var(--space-6); +} + +.muted { + color: var(--color-text-muted); +} + +/* ------------------------------------------------------------------------- + 6. Utilities + ------------------------------------------------------------------------- */ + +.full-width { + width: 100%; +} + +.text-center { + text-align: center; +} + +[hidden] { + display: none !important; +} + +/* ------------------------------------------------------------------------- + 7. Page-specific: node tree (text detail) + ------------------------------------------------------------------------- + The tree DOM is rendered as plain ul/li with buttons and inputs as + direct children of each li. Cypress assertions rely on this exact + structure, so we style it via descendant selectors only - no wrapper + elements added. +*/ + +.node-tree > ul { + border-left: 2px solid var(--color-border); + padding-left: var(--space-4); +} + +.node-tree ul ul { + border-left: 1px solid var(--color-border); + margin-top: var(--space-2); + margin-left: var(--space-2); + padding-left: var(--space-4); +} + +.node-tree li { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--space-2); + padding: var(--space-2) 0; +} + +.node-tree li > ul { + flex-basis: 100%; + margin-top: var(--space-2); +} + +.node-tree li > span { + font-weight: 500; +} + +.node-tree li > button { + padding: var(--space-1) var(--space-3); + font-size: var(--font-size-sm); + background-color: var(--color-surface); + border: 1px solid var(--color-border-strong); + border-radius: var(--radius-sm); +} + +.node-tree li > button.toggle-children { + padding: var(--space-1) var(--space-2); + background-color: transparent; + border-color: transparent; + color: var(--color-text-muted); + font-size: var(--font-size-base); +} + +.node-tree li > button.toggle-children:hover, +.node-tree li > button.toggle-children:focus { + color: var(--color-text); + background-color: var(--color-surface-alt); +} + +.node-tree li > button.add-child { + color: var(--color-primary); + border-color: var(--color-primary); +} + +.node-tree li > button.add-child:hover, +.node-tree li > button.add-child:focus { + background-color: var(--color-primary); + color: #ffffff; +} + +.node-tree li > button.bulk-add-children { + color: var(--color-accent); + border-color: var(--color-accent); +} + +.node-tree li > button.bulk-add-children:hover, +.node-tree li > button.bulk-add-children:focus { + background-color: var(--color-accent); + color: #ffffff; +} + +.node-tree li > input { + width: auto; + margin-top: 0; +} + +.node-tree li > input.bulk-count { + max-width: 6rem; +} diff --git a/public/js/home.js b/public/js/home.js index e7abc7c..ecf8268 100644 --- a/public/js/home.js +++ b/public/js/home.js @@ -9,9 +9,11 @@ document.addEventListener('DOMContentLoaded', () => { const texts = await response.json(); textsList.innerHTML = texts .map(text => - '
You do not have permission to access this page.
- Back to Home +Already have an account? Login
++ Nothing scheduled for today. +
+