From 32f1d2dd7381dbbabe450f9c9a8ace0a8595137b Mon Sep 17 00:00:00 2001 From: Robert Andreas Kyllo Date: Thu, 17 Sep 2026 20:53:36 +0200 Subject: [PATCH] feat: refine digital library visual design (#41) --- src/App.css | 108 +++++++++++++++++++------- src/components/BookCard.css | 58 ++++++++------ src/components/BookJumpList.css | 19 +++-- src/components/FavoriteButton.css | 29 +++++-- src/components/FavoritesView.css | 47 +++++++---- src/components/NavigationControls.css | 33 +++++--- src/components/SortSelect.css | 21 +++-- src/components/SubjectFilter.css | 21 +++-- src/index.css | 35 ++++++--- 9 files changed, 248 insertions(+), 123 deletions(-) diff --git a/src/App.css b/src/App.css index c16d5f4..777ffb3 100644 --- a/src/App.css +++ b/src/App.css @@ -2,38 +2,50 @@ display: flex; flex-direction: column; min-height: 100vh; + background-color: var(--color-paper); } .app-header { - background-color: #2c3e50; - color: #ffffff; - padding: 1.25rem 1.5rem; - text-align: center; + border-bottom: 0.3125rem solid var(--color-accent); + background-color: var(--color-ink); + color: var(--color-surface); + padding: clamp(1.5rem, 5vw, 3rem) clamp(1rem, 4vw, 2rem); + text-align: left; } .app-header h1 { - margin: 0; - font-size: 1.75rem; + max-width: 60rem; + margin: 0 auto; + font-family: var(--font-display); + font-size: clamp(2rem, 5vw, 3.25rem); + letter-spacing: -0.02em; + line-height: 1; } .app-header p { - margin: 0.25rem 0 0; + max-width: 60rem; + margin: var(--space-2) auto 0; color: #d5dde5; + font-size: 1.0625rem; } .app-main { flex: 1; width: 100%; - max-width: 60rem; + max-width: 66rem; margin: 0 auto; - padding: 1.5rem; + padding: clamp(1.5rem, 4vw, 3rem) clamp(1rem, 4vw, 2rem); } .library-controls { display: grid; - gap: 1rem; + gap: var(--space-4); max-width: 42rem; - margin: 0 auto 1.5rem; + margin: 0 auto 2rem; + padding: var(--space-4); + border-top: 1px solid var(--color-border); + border-bottom: 1px solid var(--color-border); + background-color: var(--color-surface-muted); } .library-controls .subject-filter, @@ -45,42 +57,54 @@ .view-navigation { display: flex; - gap: 0.5rem; + gap: var(--space-4); max-width: 32rem; - margin: 0 auto 1.5rem; + margin: 0 auto 2rem; + border-bottom: 1px solid var(--color-border); } .view-navigation button { flex: 1; - padding: 0.625rem 0.75rem; - border: 1px solid #cbd2d9; - border-radius: 0.375rem; - background-color: #ffffff; - color: #243b53; + margin-bottom: -1px; + padding: var(--space-3) var(--space-2); + border: 0; + border-bottom: 0.1875rem solid transparent; + background-color: transparent; + color: var(--color-ink-muted); font: inherit; font-weight: 600; + cursor: pointer; } .view-navigation button:hover { - background-color: #edf2f7; + color: var(--color-ink); } .view-navigation button[aria-pressed="true"] { - border-color: #2c3e50; - background-color: #2c3e50; - color: #ffffff; + border-bottom-color: var(--color-accent); + color: var(--color-ink); } .view-navigation button:focus-visible { - outline: 0.1875rem solid #2c3e50; + outline: 0.1875rem solid var(--color-focus); outline-offset: 0.125rem; } .book-viewer { - max-width: 32rem; + max-width: 40rem; margin: 0 auto; } +.app-main [role="status"] p:not(.visually-hidden), +.app-main [role="alert"] { + max-width: 40rem; + margin: 0 auto var(--space-4); + padding: var(--space-3) var(--space-4); + border-left: 0.25rem solid var(--color-accent); + background-color: var(--color-accent-soft); + color: var(--color-ink); +} + .visually-hidden { position: absolute; width: 1px; @@ -91,9 +115,11 @@ } .app-footer { - padding: 0.75rem; + margin-top: var(--space-5); + padding: var(--space-4); + border-top: 1px solid var(--color-border); text-align: center; - color: #616e7c; + color: var(--color-ink-muted); font-size: 0.875rem; } @@ -106,11 +132,35 @@ @media (max-width: 32rem) { .app-header, .app-main { - padding-right: 1rem; - padding-left: 1rem; + padding-right: var(--space-4); + padding-left: var(--space-4); } .app-header h1 { - font-size: 1.5rem; + font-size: 2rem; + } + + .library-controls { + padding: var(--space-3); + } + + .view-navigation { + flex-direction: column; + gap: 0; + border-bottom: 0; + } + + .view-navigation button { + flex: 0 0 auto; + margin-bottom: 0; + border-bottom: 1px solid var(--color-border); + border-left: 0.1875rem solid transparent; + text-align: left; + } + + .view-navigation button[aria-pressed="true"] { + border-bottom-color: var(--color-border); + border-left-color: var(--color-accent); + background-color: var(--color-surface-muted); } } diff --git a/src/components/BookCard.css b/src/components/BookCard.css index d47fc0e..66a4927 100644 --- a/src/components/BookCard.css +++ b/src/components/BookCard.css @@ -1,12 +1,12 @@ .book-card { display: grid; grid-template-columns: minmax(8rem, 12rem) minmax(0, 1fr); - gap: 1.5rem; + gap: var(--space-5); overflow: hidden; - border: 1px solid #d5dde5; - border-radius: 0.75rem; - background-color: #ffffff; - box-shadow: 0 0.25rem 0.75rem rgb(44 62 80 / 12%); + border: 1px solid var(--color-border); + border-radius: var(--radius-medium); + background-color: var(--color-surface); + box-shadow: var(--shadow-raised); } .book-card-cover { @@ -16,8 +16,8 @@ height: 18rem; min-width: 0; place-items: center; - background-color: #edf2f7; - color: #52606d; + background-color: var(--color-surface-muted); + color: var(--color-ink-muted); text-align: center; } @@ -36,27 +36,30 @@ .book-card-content { min-width: 0; - padding: 1.25rem 1.25rem 1.25rem 0; + padding: 1.5rem 1.5rem 1.5rem 0; } .book-card-metadata { - height: 7.5rem; + min-height: 10rem; overflow: visible; } .book-card-content h2 { margin: 0; max-height: 2.4em; - color: #243b53; + color: var(--color-ink); + font-family: var(--font-display); + font-size: clamp(1.5rem, 4vw, 2rem); + font-weight: 700; line-height: 1.2; overflow-wrap: anywhere; overflow: hidden; } .book-card-content p { - margin: 0.25rem 0 0; + margin: var(--space-2) 0 0; line-height: 1.2; - color: #52606d; + color: var(--color-ink-muted); } .book-card-authors { @@ -69,7 +72,7 @@ } .book-card-rating { - color: #243b53; + color: var(--color-ink); font-weight: 600; } @@ -84,7 +87,7 @@ flex-direction: column; height: 9rem; min-height: 9rem; - margin-top: 1.5rem; + margin-top: var(--space-5); } .book-card-subjects-section.is-expanded { @@ -96,7 +99,7 @@ display: flex; flex: 0 0 7rem; flex-wrap: wrap; - gap: 0.5rem; + gap: var(--space-2); align-content: flex-start; height: 7rem; min-height: 7rem; @@ -118,8 +121,9 @@ min-width: 0; max-width: 100%; border-radius: 999px; - background-color: #d9e2ec; - color: #243b53; + border: 1px solid var(--color-border); + background-color: var(--color-surface-muted); + color: var(--color-ink); padding: 0.25rem 0.625rem; font-size: 0.875rem; overflow: hidden; @@ -137,18 +141,22 @@ .book-card-subjects-controls button { max-width: 100%; border: 0; - border-radius: 999px; - background-color: #edf2f7; - color: #52606d; - padding: 0.25rem 0.625rem; + border-radius: 0; + background-color: transparent; + color: var(--color-accent); + padding: 0.25rem 0; font: inherit; font-weight: 600; overflow-wrap: anywhere; cursor: pointer; } +.book-card-subjects-controls button:hover { + color: var(--color-ink); +} + .book-card-subjects-controls button:focus-visible { - outline: 0.1875rem solid #2c3e50; + outline: 0.1875rem solid var(--color-focus); outline-offset: 0.125rem; } @@ -165,8 +173,8 @@ .book-card-content { position: relative; z-index: 1; - padding: 1rem 1.25rem 1.25rem; - border-top: 1px solid #d5dde5; - background-color: #ffffff; + padding: 1.25rem; + border-top: 1px solid var(--color-border); + background-color: var(--color-surface); } } diff --git a/src/components/BookJumpList.css b/src/components/BookJumpList.css index 0e54246..64f8ec1 100644 --- a/src/components/BookJumpList.css +++ b/src/components/BookJumpList.css @@ -1,10 +1,10 @@ .book-jump-list { display: flex; flex-direction: column; - gap: 0.5rem; + gap: var(--space-2); width: 100%; max-width: 24rem; - color: #243b53; + color: var(--color-ink); font-weight: 600; } @@ -12,15 +12,20 @@ width: 100%; min-height: 2.75rem; padding: 0.625rem 0.75rem; - border: 1px solid #d5dde5; - border-radius: 0.5rem; - background-color: #ffffff; - color: #1f2933; + border: 1px solid var(--color-border); + border-radius: var(--radius-small); + background-color: var(--color-surface); + color: var(--color-ink); font: inherit; font-weight: 400; + cursor: pointer; +} + +.book-jump-list select:hover { + border-color: var(--color-ink-muted); } .book-jump-list select:focus-visible { - outline: 0.1875rem solid #2c3e50; + outline: 0.1875rem solid var(--color-focus); outline-offset: 0.125rem; } diff --git a/src/components/FavoriteButton.css b/src/components/FavoriteButton.css index e443cfe..a1878d6 100644 --- a/src/components/FavoriteButton.css +++ b/src/components/FavoriteButton.css @@ -1,19 +1,32 @@ .favorite-button { align-self: flex-start; - margin-top: 1rem; - padding: 0.5rem 0.75rem; - border: 1px solid #cbd2d9; - border-radius: 0.375rem; - background-color: #ffffff; - color: #1f2933; + margin-top: var(--space-4); + padding: 0.625rem 0.875rem; + border: 1px solid var(--color-ink); + border-radius: var(--radius-small); + background-color: var(--color-surface); + color: var(--color-ink); font: inherit; + font-weight: 600; + cursor: pointer; } .favorite-button:hover { - background-color: #f5f7fa; + background-color: var(--color-surface-muted); +} + +.favorite-button[aria-pressed="true"] { + border-color: var(--color-accent); + background-color: var(--color-accent); + color: #ffffff; +} + +.favorite-button[aria-pressed="true"]:hover { + border-color: var(--color-ink); + background-color: var(--color-ink); } .favorite-button:focus-visible { - outline: 0.1875rem solid #2c3e50; + outline: 0.1875rem solid var(--color-focus); outline-offset: 0.125rem; } diff --git a/src/components/FavoritesView.css b/src/components/FavoritesView.css index 577feaf..60f8364 100644 --- a/src/components/FavoritesView.css +++ b/src/components/FavoritesView.css @@ -1,19 +1,22 @@ .favorites-view { max-width: 32rem; - margin: 2rem auto 0; - padding-top: 1.5rem; - border-top: 1px solid #d5dde5; + margin: 2.5rem auto 0; + padding-top: var(--space-5); + border-top: 2px solid var(--color-ink); } .favorites-view h2 { margin: 0; - color: #243b53; + color: var(--color-ink); + font-family: var(--font-display); + font-size: clamp(1.75rem, 5vw, 2.25rem); + line-height: 1.1; } .favorites-view ul { display: grid; - gap: 0.75rem; - margin: 1rem 0 0; + gap: 0; + margin: var(--space-4) 0 0; padding: 0; list-style: none; } @@ -22,10 +25,9 @@ display: flex; align-items: center; justify-content: space-between; - gap: 1rem; - padding: 0.75rem; - border: 1px solid #d5dde5; - border-radius: 0.5rem; + gap: var(--space-4); + padding: var(--space-4) 0; + border-bottom: 1px solid var(--color-border); } .favorites-view h3, @@ -33,25 +35,36 @@ margin: 0; } +.favorites-view h3 { + color: var(--color-ink); + font-family: var(--font-display); + font-size: 1.25rem; + line-height: 1.2; +} + .favorites-view p { - color: #616e7c; + margin-top: var(--space-1); + color: var(--color-ink-muted); } .favorites-view button { + flex: 0 0 auto; padding: 0.5rem 0.75rem; - border: 1px solid #cbd2d9; - border-radius: 0.375rem; - background-color: #ffffff; - color: #1f2933; + border: 1px solid var(--color-border); + border-radius: var(--radius-small); + background-color: var(--color-surface); + color: var(--color-ink); font: inherit; + font-weight: 600; + cursor: pointer; } .favorites-view button:hover { - background-color: #f5f7fa; + background-color: var(--color-surface-muted); } .favorites-view button:focus-visible { - outline: 0.1875rem solid #2c3e50; + outline: 0.1875rem solid var(--color-focus); outline-offset: 0.125rem; } diff --git a/src/components/NavigationControls.css b/src/components/NavigationControls.css index c8e73b1..040d498 100644 --- a/src/components/NavigationControls.css +++ b/src/components/NavigationControls.css @@ -2,34 +2,45 @@ display: flex; align-items: center; justify-content: space-between; - gap: 1rem; - margin: 1rem 0 0; + gap: var(--space-3); + margin: var(--space-5) 0 0; } .navigation-progress { margin: 0; - color: #616e7c; + color: var(--color-ink-muted); + font-weight: 600; font-variant-numeric: tabular-nums; } .navigation-controls button { - padding: 0.5rem 1rem; - border: 1px solid #cbd2d9; - border-radius: 0.375rem; - background-color: #ffffff; - color: #1f2933; + min-width: 6.5rem; + padding: 0.625rem 1rem; + border: 1px solid var(--color-ink); + border-radius: var(--radius-small); + background-color: var(--color-surface); + color: var(--color-ink); + font: inherit; + font-weight: 600; + cursor: pointer; } .navigation-controls button:hover:not([aria-disabled="true"]) { - background-color: #f5f7fa; + background-color: var(--color-surface-muted); } .navigation-controls button:focus-visible { - outline: 2px solid #2c3e50; - outline-offset: 2px; + outline: 0.1875rem solid var(--color-focus); + outline-offset: 0.125rem; } .navigation-controls button[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; } + +@media (max-width: 32rem) { + .navigation-controls button { + min-width: 0; + } +} diff --git a/src/components/SortSelect.css b/src/components/SortSelect.css index 92b0d6c..bd8209e 100644 --- a/src/components/SortSelect.css +++ b/src/components/SortSelect.css @@ -1,25 +1,30 @@ .sort-select { display: flex; flex-direction: column; - gap: 0.5rem; + gap: var(--space-2); max-width: 20rem; - margin: 0 auto 1.5rem; - color: #243b53; + margin: 0 auto var(--space-5); + color: var(--color-ink); font-weight: 600; } .sort-select select { min-height: 2.75rem; padding: 0.625rem 0.75rem; - border: 1px solid #d5dde5; - border-radius: 0.5rem; - background-color: #ffffff; - color: #1f2933; + border: 1px solid var(--color-border); + border-radius: var(--radius-small); + background-color: var(--color-surface); + color: var(--color-ink); font: inherit; font-weight: 400; + cursor: pointer; +} + +.sort-select select:hover { + border-color: var(--color-ink-muted); } .sort-select select:focus-visible { - outline: 0.1875rem solid #2c3e50; + outline: 0.1875rem solid var(--color-focus); outline-offset: 0.125rem; } diff --git a/src/components/SubjectFilter.css b/src/components/SubjectFilter.css index 5baffe6..831370a 100644 --- a/src/components/SubjectFilter.css +++ b/src/components/SubjectFilter.css @@ -1,25 +1,30 @@ .subject-filter { display: flex; flex-direction: column; - gap: 0.5rem; + gap: var(--space-2); max-width: 20rem; - margin: 0 auto 1.5rem; - color: #243b53; + margin: 0 auto var(--space-5); + color: var(--color-ink); font-weight: 600; } .subject-filter select { min-height: 2.75rem; padding: 0.625rem 0.75rem; - border: 1px solid #d5dde5; - border-radius: 0.5rem; - background-color: #ffffff; - color: #1f2933; + border: 1px solid var(--color-border); + border-radius: var(--radius-small); + background-color: var(--color-surface); + color: var(--color-ink); font: inherit; font-weight: 400; + cursor: pointer; +} + +.subject-filter select:hover { + border-color: var(--color-ink-muted); } .subject-filter select:focus-visible { - outline: 0.1875rem solid #2c3e50; + outline: 0.1875rem solid var(--color-focus); outline-offset: 0.125rem; } diff --git a/src/index.css b/src/index.css index c42878d..03f050f 100644 --- a/src/index.css +++ b/src/index.css @@ -1,3 +1,25 @@ +:root { + --color-ink: #243b53; + --color-ink-muted: #52606d; + --color-paper: #f7f5f0; + --color-surface: #ffffff; + --color-surface-muted: #edf2f7; + --color-border: #d5dde5; + --color-focus: #2c3e50; + --color-accent: #9c6644; + --color-accent-soft: #f1e7dc; + --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + --font-display: Georgia, "Times New Roman", serif; + --space-1: 0.25rem; + --space-2: 0.5rem; + --space-3: 0.75rem; + --space-4: 1rem; + --space-5: 1.5rem; + --radius-small: 0.375rem; + --radius-medium: 0.75rem; + --shadow-raised: 0 0.25rem 0.75rem rgb(44 62 80 / 12%); +} + *, *::before, *::after { @@ -5,14 +27,7 @@ } html { - font-family: - system-ui, - -apple-system, - "Segoe UI", - Roboto, - "Helvetica Neue", - Arial, - sans-serif; + font-family: var(--font-sans); line-height: 1.5; -webkit-text-size-adjust: 100%; } @@ -20,8 +35,8 @@ html { body { margin: 0; min-height: 100vh; - background-color: #f7f5f0; - color: #1f2933; + background-color: var(--color-paper); + color: var(--color-ink); } img {