Compare commits
No commits in common. "13d32fb0e00bbe97d957985bfe8e294c4c587686" and "3c7b3c76b961e0b4d2873c031bdeaa0fc5e83204" have entirely different histories.
13d32fb0e0
...
3c7b3c76b9
@ -80,29 +80,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border-width: 0;
|
|
||||||
border-top-width: 1px;
|
|
||||||
border-color: var(--color-outline-variant);
|
|
||||||
border-style: solid;
|
|
||||||
width: 100%;
|
|
||||||
align-self: stretch;
|
|
||||||
&.dashed {
|
|
||||||
border-style: dashed;
|
|
||||||
}
|
|
||||||
&.dotted {
|
|
||||||
border-style: dotted;
|
|
||||||
}
|
|
||||||
&.vertical {
|
|
||||||
border-top-width: 0;
|
|
||||||
border-left-width: 1px;
|
|
||||||
width: auto;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:where(button, .button) {
|
:where(button, .button) {
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: calc(var(--border-radius) * 2);
|
border-radius: calc(var(--border-radius) * 2);
|
||||||
|
@ -117,7 +117,7 @@ export function totalDuration(pattern: Pattern): number {
|
|||||||
return reduce(
|
return reduce(
|
||||||
pattern.pulses,
|
pattern.pulses,
|
||||||
(former, pulse) => former + pulse.offset,
|
(former, pulse) => former + pulse.offset,
|
||||||
pattern.smoothRepeat && pattern.pulses.length > 1 ? 100 : 0,
|
pattern.smoothRepeat ? 100 : 0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,58 +3,15 @@
|
|||||||
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;
|
||||||
|
@ -1,17 +1,6 @@
|
|||||||
import { invoke } from '@tauri-apps/api/core';
|
import { useAtomValue } from 'jotai';
|
||||||
import { ask } from '@tauri-apps/plugin-dialog';
|
import { FC } from 'react';
|
||||||
import dayjs from 'dayjs';
|
import { CurrentPatternAtom, Pattern } from '../../context/Patterns';
|
||||||
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 = () => {
|
||||||
@ -26,80 +15,11 @@ 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 className={styles.control_panel}>
|
<div></div>
|
||||||
<div className={styles.button_row}>
|
<div></div>
|
||||||
<button className="tonal">Edit Pattern</button>
|
<div></div>
|
||||||
<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> </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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user