mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 17:41:09 +02:00
feat(articles): reader UI polish — full-bleed + unified floating toolbar
Reader page is now a proper distraction-free reading surface instead of a padded card inside the (app) layout. Layout: - .detail-shell breaks out of the (app) layout's padded + max-width container via the 100vw + negative-margin-X trick, and additionally cancels the vertical padding (<main pt-2> + inner py-2) plus the bottom-chrome reservation. The reader theme therefore paints edge-to-edge including behind the PillNav. No more island-in-a-sea look. - Initial theme (light/sepia/dark) mirrors the global Mana theme at mount time by checking document.documentElement.classList.dark — so opening an article from a dark-mode app no longer flashes a white reader. User can still override per-article via the swatches. Toolbar unification: - Old two-bar layout (top: back + typography, bottom: actions) fused into one floating pill-bar at the bottom. Three groups divided by vertical rules: nav | typography | actions. flex-wrap handles narrow screens gracefully. - position: fixed + bottom: calc(--bottom-chrome-height + 1rem) so the bar floats above Mana's PillNav without overlap. The CSS var comes from <main>'s style attribute and cascades even into fixed descendants. - backdrop-filter: blur(10px) + theme-specific semi-transparent background so the bar feels aerial, not docked. - Custom CSS tooltips on every button (data-tip attribute + ::after pseudo). Replaces the native `title` attribute which has a ~1s delay and inherits OS chrome. Tooltip bubble colors adapt to the active reader theme. aria-label stays for screen-readers. - Active-state swatches get an outline-ring instead of a background- swap so the chip color stays visible as a theme-preview. Spacing: - meta-bar margin-top: 1.5rem → 4rem — clearer separation between the viewport edge and the article title. - ReaderView padding-bottom: 4rem → 14rem — last paragraph no longer visually attaches to the floating bar when scrolled to the end; there's a proper "you've reached the end" gap. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
470f3b1b6c
commit
46c03e6a5b
2 changed files with 341 additions and 198 deletions
|
|
@ -96,7 +96,11 @@
|
|||
<style>
|
||||
.reader {
|
||||
overflow-y: auto;
|
||||
padding: 1.5rem clamp(1rem, 5vw, 3rem) 4rem;
|
||||
/* Generous bottom padding — clears the floating toolbar (~4rem of */
|
||||
/* height + chrome) AND leaves a comfortable "you've reached the */
|
||||
/* end" gap so the last paragraph isn't visually attached to the */
|
||||
/* bar when the user hits the bottom of the scroll. */
|
||||
padding: 1.5rem clamp(1rem, 5vw, 3rem) 14rem;
|
||||
font-size: var(--reader-font-size);
|
||||
line-height: 1.65;
|
||||
max-width: 700px;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
-->
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { onMount } from 'svelte';
|
||||
import { TagField } from '@mana/shared-ui';
|
||||
import { useArticle, useArticleTagIds } from '../queries';
|
||||
import { articlesStore } from '../stores/articles.svelte';
|
||||
|
|
@ -38,9 +39,20 @@
|
|||
// Typography state — per-session only for now. Persisting into userSettings
|
||||
// comes later; M2 just gets the UX loop working.
|
||||
let fontSize = $state(1);
|
||||
// Default reader theme follows the global app theme so opening an
|
||||
// article from a dark-mode Mana doesn't flash a white reader. The
|
||||
// swatch buttons still let the user override per-article (e.g. sepia
|
||||
// for late-evening reading regardless of the app's theme).
|
||||
let theme = $state<'light' | 'dark' | 'sepia'>('light');
|
||||
let fontFamily = $state<'serif' | 'sans'>('serif');
|
||||
|
||||
onMount(() => {
|
||||
if (typeof document === 'undefined') return;
|
||||
if (document.documentElement.classList.contains('dark')) {
|
||||
theme = 'dark';
|
||||
}
|
||||
});
|
||||
|
||||
// Refs handed off to HighlightLayer: `shell` is the positioning anchor
|
||||
// for the floating menu, `readerScroller` is where text lives + where
|
||||
// selection events fire.
|
||||
|
|
@ -94,79 +106,6 @@
|
|||
</svelte:head>
|
||||
|
||||
<div class="detail-shell detail-{theme}" bind:this={shell}>
|
||||
<header class="topbar">
|
||||
<button type="button" class="topbtn" onclick={() => goto('/articles')} aria-label="Zurück">
|
||||
← Zurück
|
||||
</button>
|
||||
|
||||
{#if article}
|
||||
<div class="type-controls">
|
||||
<button
|
||||
type="button"
|
||||
class="topbtn"
|
||||
onclick={() => (fontSize = Math.max(0.85, fontSize - 0.075))}
|
||||
title="Kleiner"
|
||||
aria-label="Schrift kleiner"
|
||||
>
|
||||
A−
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="topbtn"
|
||||
onclick={() => (fontSize = Math.min(1.35, fontSize + 0.075))}
|
||||
title="Größer"
|
||||
aria-label="Schrift größer"
|
||||
>
|
||||
A+
|
||||
</button>
|
||||
<span class="divider"></span>
|
||||
<button
|
||||
type="button"
|
||||
class="topbtn"
|
||||
class:active={fontFamily === 'serif'}
|
||||
onclick={() => (fontFamily = 'serif')}
|
||||
title="Serif"
|
||||
>
|
||||
Serif
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="topbtn"
|
||||
class:active={fontFamily === 'sans'}
|
||||
onclick={() => (fontFamily = 'sans')}
|
||||
title="Sans"
|
||||
>
|
||||
Sans
|
||||
</button>
|
||||
<span class="divider"></span>
|
||||
<button
|
||||
type="button"
|
||||
class="topbtn swatch swatch-light"
|
||||
class:active={theme === 'light'}
|
||||
onclick={() => (theme = 'light')}
|
||||
aria-label="Heller Modus"
|
||||
title="Hell"
|
||||
></button>
|
||||
<button
|
||||
type="button"
|
||||
class="topbtn swatch swatch-sepia"
|
||||
class:active={theme === 'sepia'}
|
||||
onclick={() => (theme = 'sepia')}
|
||||
aria-label="Sepia-Modus"
|
||||
title="Sepia"
|
||||
></button>
|
||||
<button
|
||||
type="button"
|
||||
class="topbtn swatch swatch-dark"
|
||||
class:active={theme === 'dark'}
|
||||
onclick={() => (theme = 'dark')}
|
||||
aria-label="Dunkler Modus"
|
||||
title="Dunkel"
|
||||
></button>
|
||||
</div>
|
||||
{/if}
|
||||
</header>
|
||||
|
||||
{#if article$.loading}
|
||||
<p class="placeholder">Lädt…</p>
|
||||
{:else if !article}
|
||||
|
|
@ -214,36 +153,160 @@
|
|||
htmlVersion={article.htmlContent}
|
||||
/>
|
||||
|
||||
<footer class="actionbar">
|
||||
<button
|
||||
type="button"
|
||||
class="actionbtn"
|
||||
class:active={article.status === 'finished'}
|
||||
onclick={toggleRead}
|
||||
>
|
||||
{article.status === 'finished' ? '✓ Gelesen' : 'Als gelesen markieren'}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="actionbtn"
|
||||
class:active={article.isFavorite}
|
||||
onclick={toggleFavorite}
|
||||
aria-label="Favorit umschalten"
|
||||
>
|
||||
{article.isFavorite ? '★ Favorit' : '☆ Favorit'}
|
||||
</button>
|
||||
<button type="button" class="actionbtn" onclick={archive}>Archivieren</button>
|
||||
<a class="actionbtn" href={article.originalUrl} target="_blank" rel="noopener noreferrer">
|
||||
Original ↗
|
||||
</a>
|
||||
<span class="spacer"></span>
|
||||
<button type="button" class="actionbtn danger" onclick={deleteArticle}>Löschen</button>
|
||||
<footer class="floating-bar" aria-label="Lese-Werkzeuge">
|
||||
<div class="bar-group nav-group">
|
||||
<button
|
||||
type="button"
|
||||
class="bar-btn"
|
||||
onclick={() => goto('/articles')}
|
||||
aria-label="Zurück zur Liste"
|
||||
data-tip="Zurück zur Leseliste"
|
||||
>
|
||||
←
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<span class="bar-divider" aria-hidden="true"></span>
|
||||
|
||||
<div class="bar-group type-group">
|
||||
<button
|
||||
type="button"
|
||||
class="bar-btn"
|
||||
onclick={() => (fontSize = Math.max(0.85, fontSize - 0.075))}
|
||||
aria-label="Schrift kleiner"
|
||||
data-tip="Schrift kleiner"
|
||||
>
|
||||
A−
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="bar-btn"
|
||||
onclick={() => (fontSize = Math.min(1.35, fontSize + 0.075))}
|
||||
aria-label="Schrift größer"
|
||||
data-tip="Schrift größer"
|
||||
>
|
||||
A+
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="bar-btn"
|
||||
class:active={fontFamily === 'serif'}
|
||||
onclick={() => (fontFamily = 'serif')}
|
||||
data-tip="Serif-Schrift"
|
||||
>
|
||||
Serif
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="bar-btn"
|
||||
class:active={fontFamily === 'sans'}
|
||||
onclick={() => (fontFamily = 'sans')}
|
||||
data-tip="Sans-Serif-Schrift"
|
||||
>
|
||||
Sans
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="bar-btn swatch swatch-light"
|
||||
class:active={theme === 'light'}
|
||||
onclick={() => (theme = 'light')}
|
||||
aria-label="Heller Modus"
|
||||
data-tip="Heller Modus"
|
||||
></button>
|
||||
<button
|
||||
type="button"
|
||||
class="bar-btn swatch swatch-sepia"
|
||||
class:active={theme === 'sepia'}
|
||||
onclick={() => (theme = 'sepia')}
|
||||
aria-label="Sepia-Modus"
|
||||
data-tip="Sepia-Modus"
|
||||
></button>
|
||||
<button
|
||||
type="button"
|
||||
class="bar-btn swatch swatch-dark"
|
||||
class:active={theme === 'dark'}
|
||||
onclick={() => (theme = 'dark')}
|
||||
aria-label="Dunkler Modus"
|
||||
data-tip="Dunkler Modus"
|
||||
></button>
|
||||
</div>
|
||||
|
||||
<span class="bar-divider" aria-hidden="true"></span>
|
||||
|
||||
<div class="bar-group action-group">
|
||||
<button
|
||||
type="button"
|
||||
class="bar-btn"
|
||||
class:active={article.status === 'finished'}
|
||||
onclick={toggleRead}
|
||||
aria-label={article.status === 'finished'
|
||||
? 'Als ungelesen markieren'
|
||||
: 'Als gelesen markieren'}
|
||||
data-tip={article.status === 'finished'
|
||||
? 'Als ungelesen markieren'
|
||||
: 'Als gelesen markieren'}
|
||||
>
|
||||
{article.status === 'finished' ? '✓' : '○'}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="bar-btn"
|
||||
class:active={article.isFavorite}
|
||||
onclick={toggleFavorite}
|
||||
aria-label={article.isFavorite ? 'Favorit entfernen' : 'Als Favorit markieren'}
|
||||
data-tip={article.isFavorite ? 'Favorit entfernen' : 'Als Favorit markieren'}
|
||||
>
|
||||
{article.isFavorite ? '★' : '☆'}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="bar-btn"
|
||||
onclick={archive}
|
||||
aria-label="Artikel archivieren"
|
||||
data-tip="Artikel archivieren"
|
||||
>
|
||||
⤓
|
||||
</button>
|
||||
<a
|
||||
class="bar-btn"
|
||||
href={article.originalUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Original-Seite öffnen"
|
||||
data-tip="Original-Seite öffnen"
|
||||
>
|
||||
↗
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
class="bar-btn danger"
|
||||
onclick={deleteArticle}
|
||||
aria-label="Artikel löschen"
|
||||
data-tip="Artikel löschen"
|
||||
>
|
||||
🗑
|
||||
</button>
|
||||
</div>
|
||||
</footer>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.detail-shell {
|
||||
/* Break out of the (app) layout's padded container so the reader */
|
||||
/* fills the whole viewport edge-to-edge. The horizontal escape is */
|
||||
/* the `100vw` + negative-margin-X trick that cancels the centered */
|
||||
/* `max-w-7xl mx-auto px-3 sm:px-6 lg:px-8` wrapper. The vertical */
|
||||
/* escape uses equally-negative margins to consume <main>'s pt-2 */
|
||||
/* AND its dynamic padding-bottom (which was reserving space for the */
|
||||
/* bottom chrome). The reader theme then paints behind the floating */
|
||||
/* PillNav too — far better than a theme-background island floating */
|
||||
/* in a page-background sea. */
|
||||
width: 100vw;
|
||||
margin-left: calc(50% - 50vw);
|
||||
margin-right: calc(50% - 50vw);
|
||||
margin-top: calc(-1 * (0.5rem + 0.5rem)); /* <main pt-2> + inner py-2 */
|
||||
margin-bottom: calc(-1 * (var(--bottom-chrome-height, 0px) + 8px + 0.5rem));
|
||||
min-height: 100dvh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -263,68 +326,9 @@
|
|||
background: #0f172a;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
.topbar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
padding: 0.55rem 0.9rem;
|
||||
border-bottom: 1px solid color-mix(in srgb, currentColor 12%, transparent);
|
||||
background: inherit;
|
||||
}
|
||||
.type-controls {
|
||||
display: flex;
|
||||
gap: 0.3rem;
|
||||
margin-left: auto;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.divider {
|
||||
width: 1px;
|
||||
height: 1.2em;
|
||||
background: color-mix(in srgb, currentColor 25%, transparent);
|
||||
align-self: center;
|
||||
margin: 0 0.2rem;
|
||||
}
|
||||
.topbtn {
|
||||
font: inherit;
|
||||
font-size: 0.82rem;
|
||||
padding: 0.3rem 0.65rem;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
|
||||
border-radius: 0.45rem;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
line-height: 1.1;
|
||||
}
|
||||
.topbtn:hover {
|
||||
border-color: color-mix(in srgb, currentColor 35%, transparent);
|
||||
}
|
||||
.topbtn.active {
|
||||
background: color-mix(in srgb, currentColor 10%, transparent);
|
||||
border-color: color-mix(in srgb, currentColor 35%, transparent);
|
||||
}
|
||||
.swatch {
|
||||
width: 1.7rem;
|
||||
height: 1.7rem;
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.swatch-light {
|
||||
background: #ffffff;
|
||||
}
|
||||
.swatch-sepia {
|
||||
background: #f4ecd8;
|
||||
}
|
||||
.swatch-dark {
|
||||
background: #0f172a;
|
||||
}
|
||||
.meta-bar {
|
||||
max-width: 700px;
|
||||
margin: 1.2rem auto 0;
|
||||
margin: 4rem auto 0;
|
||||
padding: 0 clamp(1rem, 5vw, 3rem);
|
||||
width: 100%;
|
||||
}
|
||||
|
|
@ -343,49 +347,184 @@
|
|||
.tags-row {
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
.actionbar {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
gap: 0.4rem;
|
||||
padding: 0.55rem 0.9rem;
|
||||
border-top: 1px solid color-mix(in srgb, currentColor 12%, transparent);
|
||||
background: inherit;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
.actionbtn {
|
||||
font: inherit;
|
||||
font-size: 0.85rem;
|
||||
padding: 0.4rem 0.75rem;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
border: 1px solid color-mix(in srgb, currentColor 18%, transparent);
|
||||
border-radius: 0.45rem;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.actionbtn:hover {
|
||||
border-color: color-mix(in srgb, currentColor 35%, transparent);
|
||||
}
|
||||
.actionbtn.active {
|
||||
background: color-mix(in srgb, #f97316 85%, transparent);
|
||||
color: white;
|
||||
border-color: #f97316;
|
||||
}
|
||||
.actionbtn.danger {
|
||||
color: #ef4444;
|
||||
border-color: color-mix(in srgb, #ef4444 30%, transparent);
|
||||
}
|
||||
.actionbtn.danger:hover {
|
||||
background: color-mix(in srgb, #ef4444 10%, transparent);
|
||||
}
|
||||
.spacer {
|
||||
flex: 1;
|
||||
}
|
||||
.placeholder {
|
||||
text-align: center;
|
||||
margin: 3rem auto;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* ─── Floating unified toolbar ────────────────────────────
|
||||
*
|
||||
* One bar at the bottom replaces what used to be a top bar (back +
|
||||
* typography) and a bottom bar (article actions). Three groups
|
||||
* divided by vertical rules: nav | typography | actions.
|
||||
*
|
||||
* `position: fixed` + center-X transform produces the floating-pill
|
||||
* look; it stays put while the reader scrolls. `bottom: 1rem` leaves
|
||||
* enough gap from the viewport edge to feel like a pill, not a docked
|
||||
* toolbar. On narrow screens the groups wrap onto multiple rows via
|
||||
* flex-wrap — still readable, just taller.
|
||||
*/
|
||||
.floating-bar {
|
||||
position: fixed;
|
||||
/* Clear Mana's own bottom-stack (PillNavigation + QuickInputBar + */
|
||||
/* TagStrip). The layout publishes its total height as */
|
||||
/* `--bottom-chrome-height` on <main>, which cascades down into our */
|
||||
/* detail-shell even though we're position: fixed (inheritance is */
|
||||
/* DOM-based, not layout-based). Fallback 0 keeps the bar sensible */
|
||||
/* if this page ever renders outside the app shell (e.g. a test). */
|
||||
bottom: calc(var(--bottom-chrome-height, 0px) + 1rem);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 20;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
padding: 0.45rem 0.65rem;
|
||||
border-radius: 999px;
|
||||
background: color-mix(in srgb, currentColor 3%, Canvas);
|
||||
border: 1px solid color-mix(in srgb, currentColor 15%, transparent);
|
||||
box-shadow:
|
||||
0 8px 24px -8px color-mix(in srgb, currentColor 35%, transparent),
|
||||
0 2px 6px -2px color-mix(in srgb, currentColor 20%, transparent);
|
||||
backdrop-filter: blur(10px);
|
||||
max-width: calc(100vw - 2rem);
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
/* Reader-theme surface overrides — Canvas above is the browser-neutral
|
||||
* default; each theme pins a proper opaque backdrop so text on/around
|
||||
* the bar stays legible. */
|
||||
.detail-light .floating-bar {
|
||||
background: color-mix(in srgb, #ffffff 92%, transparent);
|
||||
}
|
||||
.detail-sepia .floating-bar {
|
||||
background: color-mix(in srgb, #f4ecd8 92%, transparent);
|
||||
}
|
||||
.detail-dark .floating-bar {
|
||||
background: color-mix(in srgb, #0f172a 88%, transparent);
|
||||
}
|
||||
.bar-group {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
align-items: center;
|
||||
}
|
||||
.bar-divider {
|
||||
width: 1px;
|
||||
height: 1.3rem;
|
||||
background: color-mix(in srgb, currentColor 20%, transparent);
|
||||
margin: 0 0.15rem;
|
||||
}
|
||||
.bar-btn {
|
||||
font: inherit;
|
||||
font-size: 0.82rem;
|
||||
min-width: 2rem;
|
||||
height: 2rem;
|
||||
padding: 0 0.55rem;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
line-height: 1;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
.bar-btn:hover {
|
||||
background: color-mix(in srgb, currentColor 8%, transparent);
|
||||
}
|
||||
/* Custom tooltip: small label bubble above the button on hover. The
|
||||
* native `title` tooltip has a ~1s delay and inherits the OS style,
|
||||
* which feels sluggish for a reader-toolbar where the user is
|
||||
* scanning icons. `data-tip` is set declaratively on each button so
|
||||
* swapping copy per state (read / unread, favorite / unmark) stays
|
||||
* a Svelte attribute reactivity concern, not a CSS one. */
|
||||
.bar-btn[data-tip]::after {
|
||||
content: attr(data-tip);
|
||||
position: absolute;
|
||||
bottom: calc(100% + 0.4rem);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 0.3rem 0.55rem;
|
||||
border-radius: 0.4rem;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
color: #f1f5f9;
|
||||
background: #0f172a;
|
||||
box-shadow: 0 4px 10px -2px rgba(0, 0, 0, 0.25);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 120ms ease;
|
||||
/* Keep the tooltip above the bar's own backdrop. */
|
||||
z-index: 1;
|
||||
}
|
||||
.bar-btn[data-tip]:hover::after,
|
||||
.bar-btn[data-tip]:focus-visible::after {
|
||||
opacity: 1;
|
||||
transition-delay: 120ms;
|
||||
}
|
||||
/* Light-mode readers get an inverted bubble so the tooltip doesn't
|
||||
* look like just a darker blob — pops off the light page. */
|
||||
.detail-light .bar-btn[data-tip]::after {
|
||||
color: #f1f5f9;
|
||||
background: #1e293b;
|
||||
}
|
||||
.detail-sepia .bar-btn[data-tip]::after {
|
||||
color: #f4ecd8;
|
||||
background: #433422;
|
||||
}
|
||||
.detail-dark .bar-btn[data-tip]::after {
|
||||
color: #0f172a;
|
||||
background: #e2e8f0;
|
||||
}
|
||||
.bar-btn.active {
|
||||
background: color-mix(in srgb, #f97316 18%, transparent);
|
||||
color: #ea580c;
|
||||
}
|
||||
.detail-dark .bar-btn.active {
|
||||
color: #fdba74;
|
||||
}
|
||||
.bar-btn.danger:hover {
|
||||
background: color-mix(in srgb, #ef4444 15%, transparent);
|
||||
color: #ef4444;
|
||||
}
|
||||
.swatch {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
min-width: 1.5rem;
|
||||
padding: 0;
|
||||
border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
|
||||
}
|
||||
.swatch:hover {
|
||||
border-color: color-mix(in srgb, currentColor 55%, transparent);
|
||||
}
|
||||
.swatch.active {
|
||||
background: currentColor;
|
||||
outline: 2px solid color-mix(in srgb, #f97316 80%, transparent);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
.swatch-light {
|
||||
background: #ffffff;
|
||||
}
|
||||
.swatch-sepia {
|
||||
background: #f4ecd8;
|
||||
}
|
||||
.swatch-dark {
|
||||
background: #0f172a;
|
||||
}
|
||||
/* Override `.swatch.active { background: currentColor }` so the color
|
||||
* chip stays the theme-preview color even when selected. */
|
||||
.swatch-light.active {
|
||||
background: #ffffff;
|
||||
}
|
||||
.swatch-sepia.active {
|
||||
background: #f4ecd8;
|
||||
}
|
||||
.swatch-dark.active {
|
||||
background: #0f172a;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue