+
+
提示词中心
+
当前共 {totalPrompts} 条提示词
-
-
- } value={titleKeyword} placeholder="搜索标题、内容或标签" onChange={(event) => setTitleKeyword(event.target.value)} />
-
- {activeTab === "library" ? (
-
+
+
-
-
标签
-
+
+
标签
+
{promptTags.map((tag) => {
const active = tag === ALL_PROMPTS_OPTION ? selectedTags.length === 0 : selectedTags.includes(tag);
return toggleTag(tag)}>{tag} ;
})}
-
- ) : null}
+
+
+
-
- {activeTab === "library" && query.isLoading ?
: null}
- {activeTab === "library" && !query.isLoading ? (
-
<> } onClick={() => saveToMyPrompts(item)}>保存 } onClick={() => savePromptAsset(item)} /> >} onCopy={(item) => copyText(item.prompt, "提示词已复制")} emptyText="没有找到匹配的提示词" />
- ) : null}
- {activeTab === "personal" ? (
- copyText(item.prompt, "提示词已复制")}
- renderActions={(item) => {
- const personal = personalPrompts.find((prompt) => prompt.id === item.id)!;
- return } onClick={() => openEditPrompt(personal)} /> removePrompt(item.id)}> } /> ;
- }}
- emptyText="还没有保存提示词"
- />
- ) : null}
- {activeTab === "library" ? {query.isFetchingNextPage ? "加载中..." : query.hasNextPage ? "继续向下滚动加载更多" : promptItems.length > 0 ? "已经到底了" : null}
: null}
- setSelectedPrompt(null)} onCopy={(prompt) => copyText(prompt, "提示词已复制")} onSaveAsset={selectedPrompt?.sourceId === "personal" ? undefined : savePromptAsset} onSavePrompt={selectedPrompt?.sourceId === "personal" ? undefined : saveToMyPrompts} />
- setEditorOpen(false)} />
+ setSelectedPrompt(null)} onCopy={(prompt) => copyText(prompt, "提示词已复制")} onSaveAsset={savePromptAsset} />
);
}
function PromptFilter({ label, options, selected, onChange }: { label: string; options: string[]; selected: string; onChange: (value: string) => void }) {
- return
{label}
{options.map((option) => onChange(option)}>{option} )}
;
+ return
{label}
{options.map((option) => onChange(option)}>{option} )}
;
}
function PromptGrid({ items, onOpen, onCopy, renderActions, emptyText }: { items: Prompt[]; onOpen: (item: Prompt) => void; onCopy: (item: Prompt) => void; renderActions: (item: Prompt) => ReactNode; emptyText: string }) {
- return
{items.map((item) =>
onOpen(item)} onCopy={() => onCopy(item)} extraAction={renderActions(item)} />)} {items.length === 0 ?
: null}
;
+ return
{items.map((item) =>
onOpen(item)} onCopy={() => onCopy(item)} extraAction={renderActions(item)} />)} {items.length === 0 ?
: null}
;
}
-function toPersonalInput(item: Prompt): PersonalPromptInput {
- return { title: item.title, prompt: item.prompt, description: item.description, coverUrl: item.coverUrl, referenceImageUrls: item.referenceImageUrls, tags: item.tags, imageMode: item.imageMode, imageModel: item.imageModel, imageSize: item.imageSize, imageCount: item.imageCount };
-}
diff --git a/web/src/services/api/prompts.ts b/web/src/services/api/prompts.ts
index eedf6c6..9b96d05 100644
--- a/web/src/services/api/prompts.ts
+++ b/web/src/services/api/prompts.ts
@@ -2,7 +2,6 @@ import localforage from "localforage";
import { runPromptSource, type RawPrompt } from "./prompt-source-runtime";
import { usePromptSourceStore } from "@/stores/use-prompt-source-store";
-import { usePromptStore, type PersonalPrompt } from "@/stores/use-prompt-store";
import type { PromptSource } from "./prompt-source-presets";
export type Prompt = RawPrompt & {
@@ -12,7 +11,6 @@ export type Prompt = RawPrompt & {
};
export const ALL_PROMPTS_OPTION = "全部";
-export const PERSONAL_PROMPTS_CATEGORY = "我的提示词";
export type PromptListResponse = {
items: Prompt[];
@@ -76,17 +74,6 @@ function withSourceMeta(source: PromptSource, items: RawPrompt[]): Prompt[] {
}));
}
-export function personalPromptToPrompt(item: PersonalPrompt): Prompt {
- return {
- ...item,
- coverUrl: item.coverUrl || item.referenceImageUrls[0] || "",
- sourceId: "personal",
- category: PERSONAL_PROMPTS_CATEGORY,
- githubUrl: "",
- preview: "",
- };
-}
-
async function readSourceCache(sourceId: string) {
return promptCacheStore.getItem
(cacheKey(sourceId));
}
@@ -135,7 +122,7 @@ async function getSourcePrompts(source: PromptSource): Promise {
return (await readSourceCache(source.id))?.items || [];
}
-async function getAllPrompts(includePersonal: boolean): Promise {
+async function getAllPrompts(): Promise {
const settled = await Promise.all(
enabledSources().map(async (source) => {
try {
@@ -145,19 +132,17 @@ async function getAllPrompts(includePersonal: boolean): Promise {
}
}),
);
- const personal = includePersonal ? usePromptStore.getState().prompts.map(personalPromptToPrompt) : [];
- return [...personal, ...settled.flat()];
+ return settled.flat();
}
-export async function fetchPrompts({ keyword = "", tag = [], category = ALL_PROMPTS_OPTION, page = 1, pageSize = 20, includePersonal = true }: { keyword?: string; tag?: string[]; category?: string; page?: number; pageSize?: number; includePersonal?: boolean } = {}) {
- const items = await getAllPrompts(includePersonal);
+export async function fetchPrompts({ keyword = "", tag = [], category = ALL_PROMPTS_OPTION, page = 1, pageSize = 20 }: { keyword?: string; tag?: string[]; category?: string; page?: number; pageSize?: number } = {}) {
+ const items = await getAllPrompts();
const normalizedKeyword = keyword.trim().toLowerCase();
const normalizedPage = Math.max(1, page);
const normalizedPageSize = Math.max(1, Math.min(100, pageSize));
const withoutTagFilter = filterPrompts(items, { keyword: normalizedKeyword, category, tags: [] });
const filtered = filterPrompts(items, { keyword: normalizedKeyword, category, tags: tag });
const categories = enabledSources().map((source) => source.name);
- if (includePersonal && usePromptStore.getState().prompts.length) categories.unshift(PERSONAL_PROMPTS_CATEGORY);
return {
items: filtered.slice((normalizedPage - 1) * normalizedPageSize, normalizedPage * normalizedPageSize),
diff --git a/web/src/stores/use-prompt-store.ts b/web/src/stores/use-prompt-store.ts
deleted file mode 100644
index 079be89..0000000
--- a/web/src/stores/use-prompt-store.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { nanoid } from "nanoid";
-import { create } from "zustand";
-import { createJSONStorage, persist } from "zustand/middleware";
-
-import { localForageStorage } from "@/lib/localforage-storage";
-
-export type PersonalPrompt = {
- id: string;
- title: string;
- prompt: string;
- description: string;
- coverUrl: string;
- referenceImageUrls: string[];
- tags: string[];
- createdAt: string;
- updatedAt: string;
- imageMode?: string;
- imageModel?: string;
- imageSize?: string;
- imageCount?: number;
-};
-
-export type PersonalPromptInput = Omit;
-
-type PromptStore = {
- hydrated: boolean;
- prompts: PersonalPrompt[];
- addPrompt: (prompt: PersonalPromptInput) => string;
- updatePrompt: (id: string, prompt: PersonalPromptInput) => void;
- removePrompt: (id: string) => void;
-};
-
-export const usePromptStore = create()(
- persist(
- (set) => ({
- hydrated: false,
- prompts: [],
- addPrompt: (prompt) => {
- const id = nanoid();
- const now = new Date().toISOString();
- set((state) => ({ prompts: [{ ...prompt, id, createdAt: now, updatedAt: now }, ...state.prompts] }));
- return id;
- },
- updatePrompt: (id, prompt) => set((state) => ({ prompts: state.prompts.map((item) => (item.id === id ? { ...item, ...prompt, updatedAt: new Date().toISOString() } : item)) })),
- removePrompt: (id) => set((state) => ({ prompts: state.prompts.filter((item) => item.id !== id) })),
- }),
- {
- name: "infinite-canvas:prompt_store",
- storage: createJSONStorage(() => localForageStorage),
- onRehydrateStorage: () => () => usePromptStore.setState({ hydrated: true }),
- },
- ),
-);