basicly complete pattern detail presentation.

This commit is contained in:
Vixalie 2025-03-11 22:37:57 +08:00
parent abee609e43
commit 13d32fb0e0
2 changed files with 129 additions and 6 deletions

View File

@ -3,15 +3,58 @@
flex: 2; flex: 2;
border-radius: calc(var(--border-radius) * 2); border-radius: calc(var(--border-radius) * 2);
background-color: var(--color-surface-container); background-color: var(--color-surface-container);
padding: calc(var(--spacing) * 2) calc(var(--spacing) * 2);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;
gap: calc(var(--spacing) * 2); gap: calc(var(--spacing) * 2);
.control_panel {
display: flex;
flex-direction: column;
gap: calc(var(--spacing) * 2);
.button_row {
display: flex;
flex-direction: row;
align-items: center;
gap: calc(var(--spacing) * 2);
}
}
.detail_panel {
flex: 1;
display: flex;
flex-direction: column;
gap: calc(var(--spacing) * 2);
.detail_row {
display: flex;
flex-direction: row;
align-items: center;
gap: calc(var(--spacing) * 2);
.detail_unit {
display: flex;
flex-direction: row;
align-items: center;
gap: calc(var(--spacing));
label {
min-width: 8em;
flex: 0 0 8em;
text-align: right;
}
.content {
flex: 1 1;
}
}
}
}
.preview_panel {
min-height: 140px;
flex: 0 0;
}
} }
.empty_promption { .empty_promption {
flex: 2; flex: 2;
border-radius: calc(var(--border-radius) * 2); border-radius: calc(var(--border-radius) * 2);
background-color: var(--color-surface-container); background-color: var(--color-surface-container);
padding: calc(var(--spacing) * 2) calc(var(--spacing) * 2);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;

View File

@ -1,6 +1,17 @@
import { useAtomValue } from 'jotai'; import { invoke } from '@tauri-apps/api/core';
import { FC } from 'react'; import { ask } from '@tauri-apps/plugin-dialog';
import { CurrentPatternAtom, Pattern } from '../../context/Patterns'; import dayjs from 'dayjs';
import { useAtomValue, useSetAtom } from 'jotai';
import { FC, useCallback, useMemo } from 'react';
import { NotificationType, useNotification } from '../../components/Notifications';
import PatternPreview from '../../components/PatternPreview';
import {
CurrentPatternAtom,
Pattern,
PatternsAtom,
SelectedPatternIdAtom,
totalDuration,
} from '../../context/Patterns';
import styles from './PatternDetail.module.css'; import styles from './PatternDetail.module.css';
const EmptyPromption: FC = () => { const EmptyPromption: FC = () => {
@ -15,11 +26,80 @@ const EmptyPromption: FC = () => {
}; };
const Detail: FC<{ pattern: Pattern }> = ({ pattern }) => { const Detail: FC<{ pattern: Pattern }> = ({ pattern }) => {
const { showToast } = useNotification();
const refreshPatterns = useSetAtom(PatternsAtom);
const resetSelected = useSetAtom(SelectedPatternIdAtom);
const patternDuration = useMemo(() => totalDuration(pattern), [pattern]);
const createTime = useMemo(
() => dayjs(pattern.createdAt).format('YYYY-MM-DD HH:mm:ss'),
[pattern],
);
const handleDeleteAction = useCallback(async () => {
try {
const answer = await ask(
`The pattern ${pattern.name} will be deleted, and cannot be revoked. Are you sure?`,
{
title: 'Confirm action',
kind: 'warning',
},
);
if (answer) {
await invoke('remove_pattern', { patternId: pattern.id });
showToast(NotificationType.SUCCESS, 'Pattern deleted.');
refreshPatterns();
resetSelected(null);
}
} catch (e) {
console.error('[delete pattern]', e);
showToast(NotificationType.ERROR, 'Failed to delete pattern. Please try again.');
}
}, [pattern]);
return ( return (
<div className={styles.pattern_detail}> <div className={styles.pattern_detail}>
<div></div> <div className={styles.control_panel}>
<div></div> <div className={styles.button_row}>
<div></div> <button className="tonal">Edit Pattern</button>
<button className="tonal danger" onClick={handleDeleteAction}>
Delete Pattern
</button>
</div>
<div className={styles.button_row}>
<button className="tonal warn">Test Run</button>
</div>
<div className={styles.button_row}>
<button className="tonal secondary">Add to Channel A Playlist</button>
<button className="tonal secondary">Add to Channel B Playlist</button>
</div>
</div>
<hr className="dotted" />
<div className={styles.detail_panel}>
<div className={styles.detail_row}>
<div className={styles.detail_unit}>
<label>Created At</label>
<div className={styles.content}>{createTime}</div>
</div>
</div>
<div className={styles.detail_row}>
<div className={styles.detail_unit}>
<label>Duration</label>
<div className={styles.content}>{(patternDuration / 1000).toFixed(2)} s</div>
</div>
</div>
<div className={styles.detail_row}>
<div className={styles.detail_unit}>
<label>&nbsp;</label>
<div className={styles.content}>
{pattern.pulses.length} key frame{pattern.pulses.length > 1 && 's'}
</div>
</div>
</div>
</div>
<hr className="dotted" />
<div className={styles.preview_panel}>
<PatternPreview />
</div>
</div> </div>
); );
}; };