feat: private feeds, all input fields supersede keyboard nav
This commit is contained in:
@@ -1,38 +1,55 @@
|
||||
const createSignal = <T,>(value: T): [() => T, (next: T) => void] => {
|
||||
let current = value
|
||||
return [() => current, (next) => {
|
||||
current = next
|
||||
}]
|
||||
}
|
||||
let current = value;
|
||||
return [
|
||||
() => current,
|
||||
(next) => {
|
||||
current = next;
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
import { SyncStatus } from "./SyncStatus"
|
||||
import { useTheme } from "@/context/ThemeContext"
|
||||
import { SyncStatus } from "./SyncStatus";
|
||||
import { useTheme } from "@/context/ThemeContext";
|
||||
import { useInputFocusNav } from "@/hooks/useInputFocusNav";
|
||||
|
||||
export function ExportDialog() {
|
||||
const { theme } = useTheme();
|
||||
const filename = createSignal("podcast-sync.json")
|
||||
const format = createSignal<"json" | "xml">("json")
|
||||
const { theme } = useTheme();
|
||||
const filename = createSignal("podcast-sync.json");
|
||||
const format = createSignal<"json" | "xml">("json");
|
||||
// Yield navigation keybinds to the Shell router while the input is focused.
|
||||
const filenameRef = useInputFocusNav();
|
||||
|
||||
return (
|
||||
<box border title="Export" style={{ padding: 1, flexDirection: "column", gap: 1 }}>
|
||||
<box style={{ flexDirection: "row", gap: 1 }}>
|
||||
<text fg={theme.text}>File:</text>
|
||||
<input value={filename[0]()} onInput={filename[1]} style={{ width: 30 }} />
|
||||
</box>
|
||||
<box style={{ flexDirection: "row", gap: 1 }}>
|
||||
<text fg={theme.text}>Format:</text>
|
||||
<tab_select
|
||||
options={[
|
||||
{ name: "JSON", description: "Portable" },
|
||||
{ name: "XML", description: "Structured" },
|
||||
]}
|
||||
onSelect={(index) => format[1](index === 0 ? "json" : "xml")}
|
||||
/>
|
||||
</box>
|
||||
<box border borderColor={theme.border}>
|
||||
<text fg={theme.text}>Export {format[0]()} to {filename[0]()}</text>
|
||||
</box>
|
||||
<SyncStatus />
|
||||
</box>
|
||||
)
|
||||
return (
|
||||
<box
|
||||
border
|
||||
title="Export"
|
||||
style={{ padding: 1, flexDirection: "column", gap: 1 }}
|
||||
>
|
||||
<box style={{ flexDirection: "row", gap: 1 }}>
|
||||
<text fg={theme.text}>File:</text>
|
||||
<input
|
||||
ref={filenameRef}
|
||||
value={filename[0]()}
|
||||
onInput={filename[1]}
|
||||
style={{ width: 30 }}
|
||||
/>
|
||||
</box>
|
||||
<box style={{ flexDirection: "row", gap: 1 }}>
|
||||
<text fg={theme.text}>Format:</text>
|
||||
<tab_select
|
||||
options={[
|
||||
{ name: "JSON", description: "Portable" },
|
||||
{ name: "XML", description: "Structured" },
|
||||
]}
|
||||
onSelect={(index) => format[1](index === 0 ? "json" : "xml")}
|
||||
/>
|
||||
</box>
|
||||
<box border borderColor={theme.border}>
|
||||
<text fg={theme.text}>
|
||||
Export {format[0]()} to {filename[0]()}
|
||||
</text>
|
||||
</box>
|
||||
<SyncStatus />
|
||||
</box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
import { detectFormat } from "@/utils/file-detector";
|
||||
import { useTheme } from "@/context/ThemeContext";
|
||||
import { useInputFocusNav } from "@/hooks/useInputFocusNav";
|
||||
|
||||
type FilePickerProps = {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
export function FilePicker(props: FilePickerProps) {
|
||||
const { theme } = useTheme();
|
||||
const format = detectFormat(props.value);
|
||||
const { theme } = useTheme();
|
||||
// Yield navigation keybinds to the Shell router while the input is focused.
|
||||
const inputRef = useInputFocusNav();
|
||||
const format = detectFormat(props.value);
|
||||
|
||||
return (
|
||||
<box style={{ flexDirection: "column", gap: 1 }}>
|
||||
<input
|
||||
value={props.value}
|
||||
onInput={props.onChange}
|
||||
placeholder="/path/to/sync-file.json"
|
||||
style={{ width: 40 }}
|
||||
/>
|
||||
<text fg={theme.text}>Format: {format}</text>
|
||||
</box>
|
||||
);
|
||||
return (
|
||||
<box style={{ flexDirection: "column", gap: 1 }}>
|
||||
<input
|
||||
ref={inputRef}
|
||||
value={props.value}
|
||||
onInput={props.onChange}
|
||||
placeholder="/path/to/sync-file.json"
|
||||
style={{ width: 40 }}
|
||||
/>
|
||||
<text fg={theme.text}>Format: {format}</text>
|
||||
</box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import { createSignal, For, Show } from "solid-js";
|
||||
import { useFeedStore } from "@/stores/feed";
|
||||
import { useTheme } from "@/context/ThemeContext";
|
||||
import { useInputFocusNav } from "@/hooks/useInputFocusNav";
|
||||
import { SourceType } from "@/types/source";
|
||||
import type { PodcastSource } from "@/types/source";
|
||||
import type { SettingItem } from "./types";
|
||||
@@ -61,6 +62,9 @@ function AddSourceForm() {
|
||||
const [name, setName] = createSignal("");
|
||||
const [url, setUrl] = createSignal("");
|
||||
const [error, setError] = createSignal<string | null>(null);
|
||||
// Yield navigation keybinds to the Shell router while either input is focused.
|
||||
const nameRef = useInputFocusNav();
|
||||
const urlRef = useInputFocusNav();
|
||||
|
||||
const submit = () => {
|
||||
const u = url().trim();
|
||||
@@ -94,6 +98,7 @@ function AddSourceForm() {
|
||||
<box flexDirection="row" gap={1}>
|
||||
<text fg={theme.textMuted}>Name:</text>
|
||||
<input
|
||||
ref={nameRef}
|
||||
value={name()}
|
||||
onInput={setName}
|
||||
placeholder="My Custom Feed"
|
||||
@@ -103,6 +108,7 @@ function AddSourceForm() {
|
||||
<box flexDirection="row" gap={1}>
|
||||
<text fg={theme.textMuted}>URL:</text>
|
||||
<input
|
||||
ref={urlRef}
|
||||
value={url()}
|
||||
onInput={(v) => {
|
||||
setUrl(v);
|
||||
|
||||
Reference in New Issue
Block a user