Compare commits

...

4 Commits

Author SHA1 Message Date
Vixalie
d0c1ee2adb add basic layout for Pattern Library. 2025-03-10 21:36:47 +08:00
Vixalie
add11be2b7 refactor empty promption. 2025-03-10 21:24:42 +08:00
Vixalie
a3b0d9071a rearange utilities styles. 2025-03-10 21:23:20 +08:00
Vixalie
d4e1884d8e add common styles. 2025-03-10 21:18:29 +08:00
8 changed files with 88 additions and 13 deletions

View File

@ -467,6 +467,9 @@
flex-direction: row;
align-items: center;
gap: calc(var(--spacing) * 2);
border-bottom: 1px solid var(--color-on-surface-variant);
border-top-left-radius: calc(var(--border-radius) * 2);
border-top-right-radius: calc(var(--border-radius) * 2);
background-color: var(--color-surface-container-highest);
}
}

View File

@ -1,7 +1,7 @@
import { invoke } from '@tauri-apps/api/core';
import dayjs from 'dayjs';
import { atom } from 'jotai';
import { atomFamily } from 'jotai/utils';
import { atomFamily, atomWithRefresh } from 'jotai/utils';
import { get, reduce } from 'lodash-es';
import { v4 } from 'uuid';
@ -121,7 +121,7 @@ export function totalDuration(pattern: Pattern): number {
}
export const PatternsAtom = atomFamily((keyword: string) =>
atom(async () => {
atomWithRefresh(async () => {
try {
const patterns = await invoke<Pattern[]>('list_patterns', { keyword });
return patterns;

View File

@ -3,3 +3,4 @@
@import 'sanitize.css/forms.css' layer(base);
@import './theme.css';
@import './components.css';
@import './utilities.css';

View File

@ -41,11 +41,5 @@
background-color: color-mix(in oklch, var(--color-on-surface) 8%, transparent);
}
}
.empty_prompt {
padding-block: calc(var(--spacing) * 1);
text-align: center;
font-size: calc(var(--font-size) * 0.8);
color: var(--color-on-surface-variant);
}
}
}

View File

@ -10,7 +10,7 @@ const AvailableDevices: FC = () => {
return (
<div className={styles.devices_list}>
{devices.length === 0 && <div className={styles.empty_prompt}>No available devices.</div>}
{devices.length === 0 && <div className="empty_prompt">No available devices.</div>}
{devices.map((device, index) => (
<div key={index} className={styles.device_card}>
<div className={styles.device_name}>{device.represent}</div>

View File

@ -1,10 +1,27 @@
@layer pages {
.pattern_list {
.patterns {
min-width: 0;
min-height: 0;
overflow: hidden;
flex: 1;
border-radius: calc(var(--border-radius) * 2);
background-color: var(--color-surface-container);
padding: calc(var(--spacing) * 2);
display: flex;
flex-direction: column;
align-items: stretch;
gap: calc(var(--spacing) * 2);
.search_row {
display: flex;
flex-direction: row;
align-items: center;
gap: calc(var(--spacing));
}
}
.pattern_list {
display: flex;
flex-direction: column;
align-items: stretch;
gap: calc(var(--spacing) * 2);
}
}

View File

@ -1,11 +1,51 @@
import { FC } from 'react';
import { Icon } from '@iconify/react/dist/iconify.js';
import cx from 'clsx';
import { useAtomValue } from 'jotai';
import { FC, useState } from 'react';
import { useDebounce } from 'react-use';
import { ScrollArea } from '../../components/ScrollArea';
import { PatternsAtom } from '../../context/Patterns';
import styles from './Patterns.module.css';
const Patterns: FC = () => {
const [rawKeyword, setRawKeyword] = useState<string>('');
const [keyword, setKeyword] = useState<string | null>(null);
const patterns = useAtomValue(PatternsAtom(keyword));
useDebounce(
() => {
if (rawKeyword.trim().length > 0) {
setKeyword(rawKeyword.trim());
} else {
setKeyword(null);
}
},
1500,
[rawKeyword],
);
return (
<div className={styles.pattern_list}>
<ScrollArea enableY></ScrollArea>
<div className={styles.patterns}>
<div className={styles.search_row}>
<div className={cx('input_wrapper', 'extendable')}>
<Icon icon="material-symbols-light:search" />
<input
type="text"
placeholder="Search patterns..."
value={rawKeyword}
onChange={(evt) => setRawKeyword(evt.currentTarget.value)}
/>
</div>
<button className="tonal secondary">
<Icon icon="material-symbols-light:add" />
New Pattern
</button>
</div>
<ScrollArea enableY>
<div className={styles.pattern_list}>
{patterns.length === 0 && <div className="empty_prompt">No pattern found.</div>}
</div>
</ScrollArea>
</div>
);
};

20
src/utilities.css Normal file
View File

@ -0,0 +1,20 @@
@layer utilities {
.extendable {
flex: 1 1;
}
.grow {
flex-grow: 1;
}
.shrink {
flex-shrink: 1;
}
.empty_prompt {
padding-block: calc(var(--spacing) * 1);
text-align: center;
font-size: calc(var(--font-size) * 0.8);
color: var(--color-on-surface-variant);
}
}