basicly complete pattern detail presentation.
This commit is contained in:
		| @@ -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; | ||||||
|   | |||||||
| @@ -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> </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> | ||||||
|   ); |   ); | ||||||
| }; | }; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user