From 94b9535d28292dbc209e251e3b0cb18d480d6a3b Mon Sep 17 00:00:00 2001 From: Innei Date: Fri, 20 Sep 2024 23:39:11 +0800 Subject: [PATCH] feat(audio-view): seek circle indicator Signed-off-by: Innei --- .../ui/markdown/components/TimeStamp.tsx | 70 ++++++++++++++++++- apps/renderer/src/styles/colors.css | 4 ++ tailwind.config.ts | 7 +- 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/apps/renderer/src/components/ui/markdown/components/TimeStamp.tsx b/apps/renderer/src/components/ui/markdown/components/TimeStamp.tsx index 802951e1d5..4c568ee7a4 100644 --- a/apps/renderer/src/components/ui/markdown/components/TimeStamp.tsx +++ b/apps/renderer/src/components/ui/markdown/components/TimeStamp.tsx @@ -1,16 +1,24 @@ import { AudioPlayer } from "~/atoms/player" import { nextFrame } from "~/lib/dom" import { useEntryContentContext } from "~/modules/entry-content/hooks" +import { useEntry } from "~/store/entry" import { timeStringToSeconds } from "../utils" export const TimeStamp = (props: { time: string }) => { const { entryId, audioSrc: src } = useEntryContentContext() + const entry = useEntry(entryId) + const mediaDuration = entry?.entries.attachments?.[0]?.duration_in_seconds + if (!src) return {props.time} + + const seekTo = timeStringToSeconds(props.time) + if (typeof seekTo !== "number") return {props.time} + return ( { AudioPlayer.mount({ type: "audio", @@ -18,11 +26,67 @@ export const TimeStamp = (props: { time: string }) => { src, currentTime: 0, }) - nextFrame(() => AudioPlayer.seek(timeStringToSeconds(props.time) || 0)) + nextFrame(() => AudioPlayer.seek(seekTo)) }} > - + {/* */} + {!!mediaDuration && ( + + )} {props.time} ) } + +interface CircleProgressProps { + percent: number + size?: number + strokeWidth?: number + strokeColor?: string + backgroundColor?: string + className?: string +} + +const CircleProgress: React.FC = ({ + percent, + size = 100, + strokeWidth = 8, + strokeColor = "hsl(var(--fo-a))", + backgroundColor = "hsl(var(--fo-inactive))", + className, +}) => { + const normalizedPercent = Math.min(100, Math.max(0, percent)) + const radius = (size - strokeWidth) / 2 + const circumference = radius * 2 * Math.PI + const offset = circumference - (normalizedPercent / 100) * circumference + + return ( + + + + + ) +} diff --git a/apps/renderer/src/styles/colors.css b/apps/renderer/src/styles/colors.css index 150f835604..f2fb876a79 100644 --- a/apps/renderer/src/styles/colors.css +++ b/apps/renderer/src/styles/colors.css @@ -1,4 +1,6 @@ [data-theme="light"] { + --fo-a: 21.6, 100%, 50%; + --fo-vibrancy-background: theme(colors.native.active); --fo-vibrancy-foreground: 0, 0%, 45%; @@ -21,6 +23,8 @@ } [data-theme="dark"] { + --fo-a: 21.6, 100%, 50%; + --fo-vibrancy-foreground: 0, 0%, 83%; --fo-vibrancy-background: theme(colors.native.active); diff --git a/tailwind.config.ts b/tailwind.config.ts index ef575ab0da..c0121d72a9 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -40,10 +40,7 @@ export default resolveConfig({ DEFAULT: "hsl(var(--muted) / )", foreground: "hsl(var(--muted-foreground) / )", }, - accent: { - DEFAULT: "#ff5c00", - foreground: "hsl(var(--fo-text-primary), )", - }, + accent: "hsl(var(--fo-a) / )", popover: { DEFAULT: "hsl(var(--popover) / )", @@ -61,7 +58,7 @@ export default resolveConfig({ theme: { // https://uicolors.app/create accent: { - DEFAULT: "#ff5c00", + DEFAULT: "hsl(var(--fo-a) / )", 50: "#fff7ec", 100: "#ffeed3", 200: "#ffd9a5",