diff --git a/src/Roux/Html.hs b/src/Roux/Html.hs index 4dde796..ea1548f 100644 --- a/src/Roux/Html.hs +++ b/src/Roux/Html.hs @@ -140,77 +140,96 @@ page title content = H.style $ H.toHtml $ T.unlines - [ "@import url('https://fonts.googleapis.com/css2?family=Lexend Peta&family=Quicksand:wght@300..700&display=swap');" + [ "@import url('https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,300;9..144,400;9..144,500;9..144,600&family=Quicksand:wght@300..700&display=swap');" , "" - , ":root { --roux-bg: #F5EFE0; --roux-text: #3D2C1E; --roux-accent: #B85C38; }" - , ".lexend-peta { font-family: \"Lexend Peta\", sans-serif; font-weight: 400; font-style: normal; }" + , ":root { --roux-bg: #F5EFE0; --roux-text: #3D2C1E; --roux-accent: #B85C38; --roux-ochre: #BF9428; --roux-sage: #7A9A7A; --roux-paper: #F5EFE0; }" + , ".fraunces { font-family: \"Fraunces\", serif; font-optical-sizing: auto; font-style: normal; }" , ".quicksand { font-family: \"Quicksand\", sans-serif; font-optical-sizing: auto; font-style: normal; }" , "" , "body { background: var(--roux-bg); color: var(--roux-text); font-family: \"Quicksand\", sans-serif; }" , "main.container { padding-top: 1.5rem; }" - , "h1, h3 { font-family: \"Lexend Peta\", sans-serif; font-weight: 400; }" - , "h1 { font-size: 2rem; font-weight: 500; margin: 0 0 0.5rem; line-height: 1.15; color: var(--roux-text); }" - , "h2 { font-family: \"Quicksand\", sans-serif; font-size: 0.7rem; font-weight: 600; margin: 0 0 1rem; letter-spacing: 0.05em; text-transform: uppercase; color: var(--roux-accent); }" + , "h1, h3, .roux-heading { font-family: \"Fraunces\", serif; font-optical-sizing: auto; }" + , "h1 { font-size: 2rem; font-weight: 500; margin: 0 0 0.5rem; line-height: 1.15; color: var(--roux-text); letter-spacing: -0.01em; }" + , "h2 { font-family: \"Fraunces\", serif; font-size: 0.75rem; font-weight: 600; margin: 0 0 1rem; letter-spacing: 0.04em; text-transform: uppercase; color: var(--roux-text); opacity: 0.6; }" , "h3 { font-size: 1rem; font-weight: 500; margin: 1.5rem 0 0.5rem; color: var(--roux-text); text-transform: uppercase; opacity: 0.75; }" - , "a { color: var(--roux-accent); text-decoration: none; }" - , "a:hover { text-decoration: underline; }" + , "a { color: var(--roux-text); text-decoration: none; transition: color 0.15s; }" + , "a:hover { color: var(--roux-accent); }" , "a[role=button] { --pico-color: var(--roux-accent); }" , "" - , "/* Search input */" - , "input[type=search] { background: var(--roux-bg); color: var(--roux-text); border-color: rgba(184, 92, 56, 0.3); }" - , "input[type=search]:focus { border-color: var(--roux-accent); box-shadow: 0 0 0 1px var(--roux-accent); }" - , ".roux-navbar { display: flex; justify-content: space-between; align-items: center; padding: 0.75rem 0; margin-bottom: 1rem; border-bottom: 0.5px solid rgba(184, 92, 56, 0.2); }" + , "/* Navbar */" + , ".roux-navbar { display: flex; justify-content: space-between; align-items: center; padding: 0.75rem 0; margin-bottom: 1rem; border-bottom: 1px solid rgba(61, 44, 30, 0.1); }" + , ".roux-navbar .roux-logo { font-family: \"Fraunces\", serif; font-size: 1.1rem; font-weight: 500; color: var(--roux-text); text-decoration: none; }" + , ".roux-navbar .roux-logo:hover { color: var(--roux-text); }" , ".roux-navbar ul { display: flex; gap: 1rem; list-style: none; margin: 0; padding: 0; }" , ".roux-navbar li { margin: 0; padding: 0; }" , ".roux-navbar a { font-size: 0.8rem; letter-spacing: 0.04em; text-transform: uppercase; }" , ".roux-navbar a.active { color: var(--roux-accent); font-weight: 500; }" , "" + , "/* Search input */" + , "input[type=search] { background: var(--roux-bg); color: var(--roux-text); border-color: rgba(61, 44, 30, 0.2); }" + , "input[type=search]:focus { border-color: var(--roux-accent); box-shadow: 0 0 0 1px var(--roux-accent); }" + , "" , "/* Recipe list on index page */" , ".roux-recipes { list-style: none; padding: 0; }" - , ".roux-recipes li { padding: 0.5rem 0; border-bottom: 0.5px solid rgba(184, 92, 56, 0.1); }" - , ".roux-recipes li:last-child { border-bottom: none; }" - , ".roux-recipes a { font-size: 1.1rem; display: block; }" + , ".roux-recipes li { padding: 0.4rem 0; }" + , ".roux-recipes a { font-size: 1rem; display: block; color: var(--roux-text); }" + , ".roux-recipes a:hover { color: var(--roux-accent); }" + , ".roux-letter-divider { font-family: \"Fraunces\", serif; font-size: 1.1rem; font-weight: 500; color: var(--roux-text); margin: 1.2rem 0 0.25rem; padding-bottom: 0.2rem; border-bottom: 0.5px solid rgba(61, 44, 30, 0.08); }" + , ".roux-recipe-meta { display: flex; gap: 0.4rem; flex-wrap: wrap; margin-top: 0.1rem; }" + , ".roux-recipe-meta .r-tag { font-size: 0.65rem; color: rgba(61, 44, 30, 0.5); letter-spacing: 0.02em; }" + , ".roux-recipes .r-course { font-size: 0.65rem; color: var(--roux-accent); opacity: 0.6; letter-spacing: 0.03em; text-transform: uppercase; }" , "" , "/* Recipe page */" - , ".roux-meta { display: flex; gap: 1.5rem; margin-bottom: 1.5rem; padding-bottom: 0.75rem; border-bottom: 0.5px solid rgba(184, 92, 56, 0.2); }" + , ".roux-meta { display: flex; gap: 1.5rem; margin-bottom: 1.5rem; padding-bottom: 0.75rem; border-bottom: 1px solid rgba(61, 44, 30, 0.08); }" , ".roux-meta-item { text-align: center; }" - , ".roux-meta-item .label { font-size: 0.65rem; color: var(--roux-accent); margin: 0 0 2px; letter-spacing: 0.04em; text-transform: uppercase; font-weight: 500; }" + , ".roux-meta-item .label { font-size: 0.65rem; color: rgba(61, 44, 30, 0.5); margin: 0 0 2px; letter-spacing: 0.04em; text-transform: uppercase; font-weight: 500; }" , ".roux-meta-item .value { font-size: 0.95rem; font-weight: 500; margin: 0; color: var(--roux-text); }" , "" - , ".roux-grid { display: grid; grid-template-columns: 260px 1fr; gap: 2rem; }" + , ".roux-grid { display: grid; grid-template-columns: 240px 1fr 180px; gap: 2rem; }" + , "@media (max-width: 1024px) { .roux-grid { grid-template-columns: 240px 1fr; } }" , "@media (max-width: 768px) { .roux-grid { grid-template-columns: 1fr; } }" , "" - , ".roux-subsection { font-size: 0.65rem; color: var(--roux-accent); margin: 0 0 6px; letter-spacing: 0.05em; text-transform: uppercase; font-weight: 500; opacity: 0.75; }" + , ".roux-marginalia { font-size: 0.8rem; line-height: 1.6; color: rgba(61, 44, 30, 0.6); }" + , ".roux-marginalia h2 { font-size: 0.65rem; letter-spacing: 0.03em; text-transform: uppercase; color: rgba(61, 44, 30, 0.4); margin: 0 0 0.75rem; }" + , ".roux-marginalia .note { padding: 0.75rem 0; border-bottom: 0.5px solid rgba(61, 44, 30, 0.06); }" + , ".roux-marginalia .note:last-child { border-bottom: none; }" + , ".roux-marginalia .ornament { color: var(--roux-accent); font-size: 1rem; margin-right: 0.3rem; }" + , "@media (max-width: 1024px) { .roux-marginalia { display: none; } }" , "" - , ".roux-ingredient-row { display: flex; align-items: flex-start; gap: 8px; padding: 4px 0; }" - , ".roux-ingredient-row input { margin-top: 5px; appearance: none; -webkit-appearance: none; width: 16px; height: 16px; border: 1.5px solid rgba(184,92,56,0.5); border-radius: 3px; background: transparent; cursor: pointer; flex-shrink: 0; position: relative; }" - , ".roux-ingredient-row input:checked { background: var(--roux-accent); border-color: var(--roux-accent); }" - , ".roux-ingredient-row input:checked::after { content: '✓'; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); font-size: 12px; font-weight: 700; color: #3D2C1E; line-height: 1; }" + , ".roux-source-link { font-size: 0.8rem; color: var(--roux-text); opacity: 0.5; white-space: nowrap; flex-shrink: 0; transition: opacity 0.15s; }" + , ".roux-source-link:hover { opacity: 1; color: var(--roux-accent); }" + , "" + , ".roux-subsection { font-size: 0.6rem; color: rgba(61, 44, 30, 0.4); margin: 0 0 6px; letter-spacing: 0.05em; text-transform: uppercase; font-weight: 500; }" + , "" + , ".roux-ingredient-row { display: flex; align-items: flex-start; gap: 8px; padding: 3px 0; }" + , ".roux-ingredient-row input { margin-top: 5px; appearance: none; -webkit-appearance: none; width: 15px; height: 15px; border: 1.5px solid rgba(61, 44, 30, 0.25); border-radius: 2px; background: transparent; cursor: pointer; flex-shrink: 0; position: relative; transform: rotate(0.5deg); transition: border-color 0.15s; }" + , ".roux-ingredient-row input:checked { border-color: rgba(61, 44, 30, 0.5); background: transparent; }" + , ".roux-ingredient-row input:checked::after { content: '✓'; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%) rotate(-0.5deg); font-size: 11px; font-weight: 400; color: var(--roux-text); opacity: 0.5; line-height: 1; }" , ".roux-ingredient-row .name { font-size: 0.9rem; line-height: 1.5; color: var(--roux-text); transition: opacity 0.15s; }" - , ".roux-ingredient-row .qty { font-size: 0.8rem; color: var(--roux-accent); margin-right: 4px; }" - , ".roux-ingredient-row:has(input:checked) { opacity: 0.45; }" + , ".roux-ingredient-row .qty { font-size: 0.8rem; color: var(--roux-text); opacity: 0.55; margin-right: 4px; }" + , ".roux-ingredient-row:has(input:checked) .name { opacity: 0.4; }" + , ".roux-ingredient-row .r-plain { font-size: 0.8rem; color: rgba(61, 44, 30, 0.55); font-style: italic; }" , "" , ".roux-step { display: flex; align-items: flex-start; gap: 12px; padding: 8px 0; transition: opacity 0.15s; }" - , ".roux-step input { margin-top: 6px; appearance: none; -webkit-appearance: none; width: 16px; height: 16px; border: 1.5px solid rgba(184,92,56,0.5); border-radius: 3px; background: transparent; cursor: pointer; flex-shrink: 0; position: relative; }" - , ".roux-step input:checked { background: var(--roux-accent); border-color: var(--roux-accent); }" - , ".roux-step input:checked::after { content: '✓'; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); font-size: 12px; font-weight: 700; color: #3D2C1E; line-height: 1; }" - , ".roux-step .step-label { font-size: 0.75rem; color: var(--roux-accent); font-weight: 500; margin: 0 0 2px; }" + , ".roux-step input { margin-top: 6px; appearance: none; -webkit-appearance: none; width: 15px; height: 15px; border: 1.5px solid rgba(61, 44, 30, 0.25); border-radius: 2px; background: transparent; cursor: pointer; flex-shrink: 0; position: relative; transform: rotate(-0.3deg); transition: border-color 0.15s; }" + , ".roux-step input:checked { border-color: rgba(61, 44, 30, 0.5); background: transparent; }" + , ".roux-step input:checked::after { content: '✓'; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%) rotate(0.3deg); font-size: 11px; font-weight: 400; color: var(--roux-text); opacity: 0.5; line-height: 1; }" + , ".roux-step .step-label { font-size: 0.7rem; color: var(--roux-accent); font-weight: 500; margin: 0 0 2px; letter-spacing: 0.01em; }" , ".roux-step .step-text { font-size: 0.9rem; line-height: 1.65; margin: 0; color: var(--roux-text); }" - , ".roux-step:has(input:checked) { opacity: 0.45; }" + , ".roux-step:has(input:checked) .step-text { opacity: 0.4; }" , "" - , ".roux-note { display: flex; gap: 12px; padding: 8px 0; }" - , ".roux-note .ornament { font-size: 1.4rem; color: var(--roux-accent); line-height: 1; margin-top: -1px; }" - , ".roux-note .text { font-size: 0.9rem; line-height: 1.65; margin: 0; color: var(--roux-text); }" - , "" - , ".roux-course { font-size: 0.65rem; color: var(--roux-accent); margin: 0 0 0.15rem; letter-spacing: 0.04em; text-transform: uppercase; font-weight: 500; }" + , ".roux-course { font-size: 0.6rem; color: var(--roux-accent); opacity: 0.65; margin: 0 0 0.15rem; letter-spacing: 0.04em; text-transform: uppercase; font-weight: 500; }" , ".roux-desc { font-size: 0.85rem; line-height: 1.6; color: var(--roux-text); margin: 0 0 1.5rem; max-width: 640px; opacity: 0.85; }" , "" - , ".roux-ingredient-tag { color: var(--roux-accent); font-weight: 500; }" - , ".roux-cookware-tag { font-style: italic; opacity: 0.85; }" - , ".roux-timer-tag { color: var(--roux-accent); font-style: italic; }" - , ".roux-comment-tag { opacity: 0.6; font-style: italic; }" - , ".tag { display: inline-block; background: rgba(184,92,56,0.1); padding: 0.1rem 0.5rem; margin: 0.1rem; border-radius: 4px; font-size: 0.7rem; color: var(--roux-accent); }" + , ".roux-ingredient-tag { border-bottom: 1.5px solid rgba(191, 148, 40, 0.35); font-weight: 500; }" + , ".roux-cookware-tag { font-style: italic; opacity: 0.75; }" + , ".roux-timer-tag { border-bottom: 1px dashed rgba(61, 44, 30, 0.25); font-style: italic; }" + , ".roux-comment-tag { opacity: 0.5; font-style: italic; font-size: 0.85em; }" + , ".tag { display: inline-block; border: 1px solid rgba(122, 154, 122, 0.35); padding: 0.1rem 0.5rem; margin: 0.1rem; border-radius: 4px; font-size: 0.7rem; color: var(--roux-sage); background: transparent; }" + , ".r-section-header { display: block; font-family: \"Fraunces\", serif; font-size: 0.85rem; font-weight: 500; color: var(--roux-text); opacity: 0.5; margin: 1rem 0 0.5rem; letter-spacing: 0.01em; border-top: 0.5px solid rgba(61, 44, 30, 0.06); padding-top: 0.75rem; }" + , ".r-section-header:first-child { border-top: none; margin-top: 0; padding-top: 0; }" ] + H.body $ H.main ! A.class_ "container" $ content -- --------------------------------------------------------------------------- @@ -263,11 +282,39 @@ searchJs = , " listEl.innerHTML = html;" , "}" , "" + , "function renderRecipeEntry(r) {" + , " let meta = '';" + , " if (r.tags && r.tags.length > 0) {" + , " meta += '' + r.tags.map(escapeHtml).join(' · ') + '';" + , " }" + , " if (r.course) {" + , " meta += '' + escapeHtml(r.course) + '';" + , " }" + , " let metaHtml = meta ? '
' : '';" + , " return 'No recipes found.
';" - , " let html = 'No recipes found.
';" + , " let html = '