mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
ui: bring back the card mimetype accent
Two agents independently dropped it, each because our Card had no `color` prop and each citing the other's precedent -- which is how a deliberate feature quietly becomes a convention. Roland wanted it back. Card takes a token colour name and draws it as a 3px edge along the top rather than tinting the surface: surfaces stay flat per the design rules, and an edge survives night mode without becoming a bright patch. Because it is a token, the accent remaps per theme -- four hues in light and dark, a single one in night and amber, which is the point of those themes. Restored on every card that shows a file: the video, image and generic file cards in Files.js, and the archive card. All of them take it from `mimetypeColor(mimetype, path)`, the same helper that colours the file icons, so a card and its icon agree.
This commit is contained in:
parent
96d84dfab8
commit
a1fbda7363
5 changed files with 51 additions and 11 deletions
|
|
@ -20,7 +20,8 @@ import {
|
|||
SearchInput,
|
||||
TabLinks,
|
||||
textEllipsis,
|
||||
useTitle
|
||||
mimetypeColor,
|
||||
useTitle,
|
||||
} from "./Common";
|
||||
import {
|
||||
deleteDomain,
|
||||
|
|
@ -425,7 +426,8 @@ export function ArchiveCard({file}) {
|
|||
</div>
|
||||
</>;
|
||||
|
||||
return <Card media={media} title={titleElm} meta={meta}>
|
||||
return <Card media={media} title={titleElm} meta={meta}
|
||||
color={mimetypeColor(file.mimetype, file.primary_path)}>
|
||||
<div style={{display: 'flex', gap: '0.5em', marginTop: '0.5em'}}>
|
||||
<Link to={`/archives/${file.id}`}>
|
||||
<Button icon='file alternate'>Details</Button>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ import {
|
|||
TagIcon,
|
||||
Toggle,
|
||||
textEllipsis,
|
||||
useTitle
|
||||
mimetypeColor,
|
||||
useTitle,
|
||||
} from "./Common";
|
||||
import {
|
||||
usePages,
|
||||
|
|
@ -116,6 +117,7 @@ function EbookCard({file, sortField}) {
|
|||
return <Card media={<CardPoster file={file} to={detailUrl}/>}
|
||||
title={<Tooltip label={title}>{header}</Tooltip>}
|
||||
meta={meta}
|
||||
color={mimetypeColor(file.mimetype, file.primary_path)}
|
||||
/>
|
||||
}
|
||||
|
||||
|
|
@ -134,6 +136,7 @@ function ImageCard({file}) {
|
|||
return <Card media={<PreviewLink file={file}><CardPoster file={file}/></PreviewLink>}
|
||||
title={<Tooltip label={title}>{header}</Tooltip>}
|
||||
meta={meta}
|
||||
color={mimetypeColor(file.mimetype, file.primary_path)}
|
||||
/>
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +178,8 @@ function FileCard({file}) {
|
|||
</>
|
||||
}
|
||||
</>;
|
||||
return <Card media={<CardPoster file={file}/>} title={header} meta={meta}/>
|
||||
return <Card media={<CardPoster file={file}/>} title={header} meta={meta}
|
||||
color={mimetypeColor(file.mimetype, file.primary_path)}/>
|
||||
}
|
||||
|
||||
export function FileCards({files}) {
|
||||
|
|
|
|||
|
|
@ -382,20 +382,26 @@ export function ThemeSamplePage() {
|
|||
<Section label='Cards'>
|
||||
<CardGroup>
|
||||
{[
|
||||
['How To Sharpen An Axe The Right Way', 'Wranglerstar · 2024-11-03'],
|
||||
['Pressure Canning Basics', 'RoseRed Homestead · 2025-02-17'],
|
||||
['Solar Panel Wiring: Series vs Parallel', 'DIY Solar Power · 2025-08-21'],
|
||||
['Ham Radio General License, Part 1', 'Ham Radio Crash Course · 2024-05-09'],
|
||||
].map(([title, meta]) => <Card
|
||||
['How To Sharpen An Axe The Right Way', 'Wranglerstar · 2024-11-03', 'blue', 'film'],
|
||||
['Pressure Canning Basics', 'RoseRed Homestead · 2025-02-17', 'blue', 'film'],
|
||||
['Water Storage Guide.pdf', 'docs/ · 2025-08-21', 'red', 'file pdf'],
|
||||
['Ham Radio General License.epub', 'ebooks/ · 2024-05-09', 'yellow', 'book'],
|
||||
].map(([title, meta, color, icon]) => <Card
|
||||
key={title}
|
||||
title={title}
|
||||
meta={meta}
|
||||
color={color}
|
||||
media={<div style={{
|
||||
aspectRatio: '16/9', background: 'var(--head)', display: 'flex',
|
||||
alignItems: 'center', justifyContent: 'center', color: 'var(--muted)',
|
||||
}}><Icon name='film' size={34}/></div>}
|
||||
}}><Icon name={icon} size={34}/></div>}
|
||||
/>)}
|
||||
</CardGroup>
|
||||
<p style={{fontSize: 12, color: 'var(--muted)', marginTop: 10}}>
|
||||
The top edge carries the file type's colour, so a grid of results is
|
||||
scannable by kind before any title is read. It comes from a token, so night
|
||||
and amber render the accent in their own single hue rather than four.
|
||||
</p>
|
||||
</Section>
|
||||
|
||||
<Section label='Loading placeholders'>
|
||||
|
|
|
|||
|
|
@ -124,10 +124,17 @@ export interface CardProps {
|
|||
meta?: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
onClick?: React.MouseEventHandler<HTMLDivElement>;
|
||||
/**
|
||||
* A token colour name, drawn as an accent along the card's top edge. File cards use
|
||||
* it to carry the mimetype's colour, so a grid of results is scannable by kind before
|
||||
* any text is read. It remaps per theme, so night gets a red accent rather than a
|
||||
* dozen hues.
|
||||
*/
|
||||
color?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function Card({media, title, meta, children, onClick, className}: CardProps) {
|
||||
export function Card({media, title, meta, children, onClick, color, className}: CardProps) {
|
||||
return <MCard
|
||||
withBorder
|
||||
padding={0}
|
||||
|
|
@ -139,6 +146,9 @@ export function Card({media, title, meta, children, onClick, className}: CardPro
|
|||
cursor: onClick ? 'pointer' : undefined,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
// An accent edge rather than a tinted surface: the design rules keep surfaces
|
||||
// flat, and a 3px edge survives night mode without becoming a bright patch.
|
||||
borderTop: color ? `3px solid var(--${color})` : undefined,
|
||||
}}
|
||||
>
|
||||
{media && <div style={{borderBottom: '1px solid var(--border)'}}>{media}</div>}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import {themeChoices} from '../../themes/names';
|
|||
import {
|
||||
ActionInput,
|
||||
Button,
|
||||
Card,
|
||||
Confirm,
|
||||
Header,
|
||||
Icon,
|
||||
|
|
@ -432,6 +433,23 @@ describe('Table', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Card', () => {
|
||||
it('draws a mimetype accent from a token, not a hex', () => {
|
||||
// File cards carry the mimetype's colour on their top edge so a grid of results is
|
||||
// scannable by kind. Semantic did this with `<Card color='violet'>`; two migrated
|
||||
// files had dropped the accent because our Card had no equivalent.
|
||||
const {container} = renderUI(<Card title='Water Storage.pdf' color='red'/>);
|
||||
|
||||
expect(container.firstChild).toHaveStyle({borderTop: '3px solid var(--red)'});
|
||||
});
|
||||
|
||||
it('has no accent when no colour is given', () => {
|
||||
const {container} = renderUI(<Card title='Plain'/>);
|
||||
|
||||
expect(container.firstChild.style.borderTop).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Panel', () => {
|
||||
it('marks danger zones', () => {
|
||||
const {container} = renderUI(<Panel danger>Destructive actions</Panel>);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue