Add share target, prompt templates, command palette and session organisation
- PWA share target: shared text/links start a new chat or go into a
recent session (chooser dialog)
- Prompt templates (personal + global for admins) with {{placeholders}}
that are asked for on insert; managed under Settings → Templates
- Ctrl/Cmd+K command palette; Alt+N new session, Alt+Up/Down switch
sessions, Ctrl+, settings
- Sessions can be pinned, archived and filed into folders; the list can
be grouped by date or by project, groups are collapsible
- Fix: the "What's new" dialog was never shown to signed-in users
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b5de531d2e
commit
428e2df40a
25 files changed
+1106
-33
No files matched your search
@@ -1,3 +1,4 @@
|
||||
import { TemplatePicker } from "./TemplatePicker";
|
||||
import { Icon } from "./Icon";
|
||||
import { formatSize } from "./FileFigure";
|
||||
import { uploadFile } from "../api";
|
||||
@@ -65,6 +66,7 @@ export function Composer({
|
||||
// Reasoning effort for the next message only ("" = model default).
|
||||
const [effort, setEffort] = useState("");
|
||||
const [interim, setInterim] = useState("");
|
||||
const [picker, setPicker] = useState(false);
|
||||
const models = useModels();
|
||||
const [prov, ...mid] = session.model.split("/");
|
||||
const reasoning = !!models.find((p) => p.provider === prov)?.models.find((m) => m.id === mid.join("/"))?.reasoning;
|
||||
@@ -322,6 +324,19 @@ export function Composer({
|
||||
</select>
|
||||
<ModelSelect value={session.model} onChange={(m) => onUpdate({ model: m })} title={t("composer.model")} />
|
||||
{reasoning && <EffortSelect value={effort} onChange={setEffort} compact />}
|
||||
<button className="ghost" style={{ padding: "3px 6px" }} onClick={() => setPicker(true)} title={t("templates.title")}>
|
||||
<Icon name="template" />
|
||||
</button>
|
||||
{picker && (
|
||||
<TemplatePicker
|
||||
onClose={() => setPicker(false)}
|
||||
onPick={(x) => {
|
||||
setPicker(false);
|
||||
setText(text.trim() ? `${text.replace(/\s+$/, "")}\n\n${x}` : x);
|
||||
setTimeout(() => ref.current?.focus(), 0);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<VoiceButton onText={(d) => setText(text ? `${text.replace(/\s+$/, "")} ${d}` : d)} onInterim={setInterim} />
|
||||
<label className="ghost" style={{ cursor: "pointer", padding: "3px 6px" }} title={t("composer.attach")}>
|
||||
<Icon name="clip" />
|
||||
|
||||
Reference in new issue
Block a user