Create src/renderer/components/ui/icons.ts as the single re-export point
for every Phosphor icon the renderer touches, then rewrite the 95 files
that previously imported directly from "@phosphor-icons/react" to pull
from the relative-path-to-barrel instead. The TitleBar commit earlier
in this series already used ui/icons; this commit extends the pattern
to the rest of the renderer.
Benefits now wired in:
- one location where bundle tree-shaking can be reasoned about,
- typos like Briefcase vs BriefCase show up against a finite list,
- re-theming or swapping icon sets is a one-file edit,
- a lint rule that flags raw @phosphor-icons/react imports can be
added later without mass-rewriting call sites.
The barrel also re-exports the `Icon` type so call sites that type
icon props against the Phosphor component type work unchanged.
Test count stays at 363 passing; typecheck stays at 156 errors.
78 lines
2.6 KiB
TypeScript
78 lines
2.6 KiB
TypeScript
import { useMemo } from "react"
|
|
import { Clock } from "../../ui/icons"
|
|
import { InlineNotice } from "../../ui"
|
|
|
|
export type ScheduleMode = "immediate" | "scheduled"
|
|
|
|
function computeMinDatetime(): string {
|
|
const d = new Date(Date.now() + 5 * 60 * 1000)
|
|
const pad = (n: number) => String(n).padStart(2, "0")
|
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`
|
|
}
|
|
|
|
export function SchedulePicker({
|
|
mode,
|
|
scheduledAt,
|
|
error,
|
|
onModeChange,
|
|
onScheduledAtChange,
|
|
onClearError,
|
|
}: {
|
|
mode: ScheduleMode
|
|
scheduledAt: string
|
|
error: string | null
|
|
onModeChange: (mode: ScheduleMode) => void
|
|
onScheduledAtChange: (value: string) => void
|
|
onClearError: () => void
|
|
}) {
|
|
const minDatetime = useMemo(computeMinDatetime, [])
|
|
|
|
return (
|
|
<div className="space-y-3">
|
|
<div role="radiogroup" aria-label="Post timing" className="space-y-2">
|
|
<label className="flex cursor-pointer items-center gap-2">
|
|
<input
|
|
type="radio"
|
|
name="schedule-mode"
|
|
value="immediate"
|
|
checked={mode === "immediate"}
|
|
onChange={() => {
|
|
onModeChange("immediate")
|
|
onClearError()
|
|
}}
|
|
className="h-4 w-4 shrink-0 cursor-pointer accent-[color:var(--primary)]"
|
|
/>
|
|
<span className="text-[13px] font-medium text-foreground">Post immediately</span>
|
|
</label>
|
|
<label className="flex cursor-pointer items-center gap-2">
|
|
<input
|
|
type="radio"
|
|
name="schedule-mode"
|
|
value="scheduled"
|
|
checked={mode === "scheduled"}
|
|
onChange={() => onModeChange("scheduled")}
|
|
className="h-4 w-4 shrink-0 cursor-pointer accent-[color:var(--primary)]"
|
|
/>
|
|
<span className="text-[13px] font-medium text-foreground">Schedule for later</span>
|
|
</label>
|
|
</div>
|
|
{mode === "scheduled" ? (
|
|
<div className="flex items-center gap-2">
|
|
<Clock size={16} className="text-muted-foreground" />
|
|
<input
|
|
type="datetime-local"
|
|
value={scheduledAt}
|
|
min={minDatetime}
|
|
onChange={(e) => {
|
|
onScheduledAtChange(e.target.value)
|
|
onClearError()
|
|
}}
|
|
className="rounded-lg border border-border bg-card px-3.5 py-2.5 text-[13px] text-foreground focus:border-[color:var(--primary)] focus:outline-none"
|
|
/>
|
|
</div>
|
|
) : null}
|
|
{error ? <InlineNotice message={error} /> : null}
|
|
</div>
|
|
)
|
|
}
|