プロンプトマネージャー

https://prompt-manager.fukke.cafe/

Next.js

Firebase

ププロンプトを管理できるツール

ふっけ / ハックツ

推しアイデア

簡単コピペ! タグ付け検索!

作った背景

欲かったから!

推し技術

AppRouter & Firestore

プロジェクト詳細

image

概要

プロンプトを投稿して管理できるツールを作成しました。 タグ付けによる管理とコピペが簡単にできるところが特徴です。

開発について

このプロジェクトのベースは v0.dev というサイト生成ツールを使って作成しました。

最初にchat.gpt(4o)にv0.devに与えるプロンプトを生成してもらいます。

# 命令書 プロンプト管理ツールを作成します。 v0.devにデザインを作成してもらうための英語のプロンプトを生成してください。 # 機能 - プロンプトの登録 - プロンプトの検索 - プロンプトの修正 - サイドメニューから汎用キーワードをコピペできるように - プロンプトをクリップボードにコピー - プロンプトの公開、非公開設定 - プロンプトにタグ付け

以下の結果が来たのでこれを v0.dev に与えてデザインを生成してもらいます。

Design Brief for Prompt Management Tool Objective: Design a user-friendly prompt management tool with the following core functionalities. Core Features: 1. Register Prompts: • A form to input and save new prompts. • Fields: Title, Content, Tags, Public/Private setting. 2. Search Prompts: • A search bar to quickly find prompts by title, content, or tags. 3. Edit Prompts: • Functionality to update existing prompts. • Editable fields: Title, Content, Tags, Public/Private setting. 4. Copy Keywords from Sidebar: • A sidebar with common keywords that users can copy and paste into their prompts. 5. Copy Prompts to Clipboard: • A button to copy the entire prompt content to the clipboard. 6. Public/Private Settings for Prompts: • An option to set prompts as public or private. • Visual indicators for the public or private status of each prompt. 7. Tagging Prompts: • Allow users to add, edit, and search tags associated with each prompt. Design Requirements: • Intuitive User Interface: • Clean and simple layout. • Easy-to-navigate interface with clear labels and instructions. • Responsive Design: • Ensure the tool is accessible and usable on both desktop and mobile devices. • Aesthetic Elements: • Use a professional and modern color scheme. • Consistent use of typography and spacing for readability. Specific Elements: • Prompt Registration Form: • Input fields for Title, Content, Tags (with autocomplete), and a toggle switch for Public/Private setting. • Submit button to save the prompt. • Prompt List: • Display a list of prompts with their title, a snippet of content, tags, and public/private status. • Each prompt should have an edit button, copy to clipboard button, and delete button. • Search Bar: • Positioned at the top of the prompt list. • Includes filters for tags and public/private status. • Sidebar: • A collapsible sidebar on the left with a list of common keywords. • Copy button next to each keyword for easy copying to the clipboard. User Flows: 1. Adding a Prompt: • User clicks on “Add Prompt” button. • A form appears where the user inputs the details. • User submits the form, and the prompt is saved and appears in the prompt list. 2. Editing a Prompt: • User clicks on the edit button next to a prompt. • The form with the current details is shown. • User updates the information and saves the changes. 3. Searching for Prompts: • User types in the search bar. • The list dynamically updates to show matching prompts. 4. Copying a Prompt: • User clicks on the copy button next to a prompt. • The prompt content is copied to the clipboard. 5. Using the Sidebar: • User opens the sidebar and clicks the copy button next to a keyword. • The keyword is copied to the clipboard for use in a prompt.

生成されたものはこちらです。 https://v0.dev/r/EPYU9NfBZTB

image

これを元にNextJSの環境を作成します。

npx create-next-app@latest --typescript --tailwind --eslint npx v0@latest init # shadcn/uiの設定などをしてくれる npx v0 add cwRpvk1Tlx1 # 生成されたコンポーネントを取り込んでくれる

大枠のアプリはこれで完成しました。 これを拡張して、フォームやバックエンドの準備をしていけばアプリケーションの完成です。

AppRouter & Firestore

Server Actionsを使ってデータ取得を実装しました。 DBは画像のようになっています。

image

例としてプロンプト一覧を取得するActionsは以下のようになります。

export async function getPromptsAction() { return unstable_cache( () => refs.pipe( query(refs.promptsRef, orderBy("createdAt", "desc")), getDocsWithQuery, ), ["get-prompts"], { tags: ["get-prompts"], }, )(); }

unstable_cacheを使ってデータキャッシュを作成し、Firestoreへのアクセス数を減らしています。 Firestoreへのクエリの作成はRemeda(https://remedajs.com/) のpipeを活用しています。(Remedaはまたどこかで解説します)

タグ検索はarray-containsというクエリを使って実装しました。 以下に例を示します。

export async function getPromptsByTagAction(tagTitle: string) { return unstable_cache( () => refs.pipe( query( refs.promptsRef, where("tags", "array-contains", tagTitle), orderBy("createdAt", "desc"), ), getDocsWithQuery, ), ["get-prompts", tagTitle], { tags: ["get-prompts", tagTitle], }, )(); }

array-containsを使うにはインデックスを貼る必要があるので注意です。

image

ふっけ / ハックツ

@fukke0906