Skip to content

Commit 869a0d2

Browse files
Cleaned up dashboard empty state and fixed broken nav dropdown
1 parent 88c60ec commit 869a0d2

18 files changed

Lines changed: 169 additions & 176 deletions

File tree

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,34 @@ labels: bug
66
assignees: ''
77
---
88

9-
## 🐛 What's Wrong?
9+
## What's wrong?
1010
Tell me what's not working. Be as detailed as you can!
1111

12-
## 🔄 How to Make It Happen Again
12+
## How to reproduce
1313
Help me recreate the bug:
1414
1. I went to '...'
1515
2. Then I clicked '...'
1616
3. And then '...'
1717
4. That's when I saw the error
1818

19-
## What You Expected
19+
## What you expected
2020
What did you think would happen?
2121

22-
## What Actually Happened
22+
## What actually happened
2323
What happened instead?
2424

25-
## 📸 Screenshots or Videos
26-
If you can grab a screenshot or screen recording, that helps a LOT. Phone camera pic works too!
25+
## Screenshots or videos
26+
If you can grab a screenshot or screen recording, that helps a lot. Phone camera pic works too!
2727

28-
## 💻 Your Setup
28+
## Your setup
2929
Help me understand your environment:
3030
- **Device**: [e.g. My laptop, iPhone 14, Samsung Galaxy]
3131
- **Browser**: [e.g. Chrome, Safari, Firefox]
3232
- **OS**: [e.g. Windows 11, macOS, Android]
3333
- **Version**: [e.g. v0.1, or just say "latest"]
3434

35-
## 📝 Anything Else?
35+
## Anything else?
3636
Any console errors? Does it only happen sometimes? Any other weird behavior?
3737

38-
## 🔗 Related?
38+
## Related issues?
3939
Is this similar to another issue you've seen? Link it here if you know.

.github/ISSUE_TEMPLATE/feature_request.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,28 @@ labels: enhancement
66
assignees: ''
77
---
88

9-
## 💡 What Do You Want?
9+
## What do you want?
1010
Describe the feature you'd love to see in closedNote.
1111

12-
## 🎯 What Problem Does This Solve?
13-
Why do you need this? What's frustrating you right now?
12+
## What problem does this solve?
13+
Why do you need this? What's frustrating you right now?
1414
Ex: "I'm always frustrated when I can't find my old prompts from last month..."
1515

16-
## 🚀 How Should It Work?
16+
## How should it work?
1717
Walk me through it. What would the perfect version of this look like?
1818

19-
## 🔄 Any Other Ways to Do It?
19+
## Any other approaches?
2020
Have you thought of alternative solutions? Other ways this could work?
2121

22-
## 📸 Show Me What You Mean
22+
## Show me what you mean
2323
Got a sketch? A screenshot from another app? A napkin drawing? Share it!
2424

25-
## Who Benefits?
25+
## Who benefits?
2626
- Who would use this feature the most?
2727
- How would it make closedNote better?
2828

29-
## 🧠 Anything Else?
29+
## Anything else?
3030
Links, references, examples, whatever helps me understand your vision.
3131

32-
## 🏷️ Does This Build on Anything?
32+
## Does this build on anything?
3333
Is there an existing feature this connects to or expands?

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,35 @@
1-
## 📝 What does this do?
1+
## What does this do?
22
<!-- Explain your changes in simple terms, like you're telling a friend -->
33

4-
## 🔗 Related Issue
4+
## Related issue
55
<!-- Link to the issue this fixes (e.g., Closes #123) -->
66
Closes #
77

8-
## 🎯 What kind of change is this?
8+
## What kind of change is this?
99
<!-- Mark the relevant option with an 'x' -->
10-
- [ ] 🐛 Bug fix (something wasn't working, now it does)
11-
- [ ] New feature (adds something cool and useful)
12-
- [ ] 📚 Documentation (README, guides, comments)
13-
- [ ] 🎨 UI improvement (makes things look better or easier to use)
14-
- [ ] 🧹 Code cleanup (organizing things, no new features)
15-
- [ ] 💡 Idea/Suggestion (not code, just sharing thoughts)
10+
- [ ] Bug fix (something wasn't working, now it does)
11+
- [ ] New feature (adds something cool and useful)
12+
- [ ] Documentation (README, guides, comments)
13+
- [ ] UI improvement (makes things look better or easier to use)
14+
- [ ] Code cleanup (organizing things, no new features)
15+
- [ ] Idea/Suggestion (not code, just sharing thoughts)
1616

17-
## 🧪 Did you test this?
17+
## Did you test this?
1818
<!-- How did you make sure it works? -->
1919
- [ ] Tested on my computer (desktop/laptop)
2020
- [ ] Tested on my phone
2121
- [ ] Asked someone else to try it
2222
- [ ] Works in light mode and dark mode
2323

24-
## 📸 Show us!
24+
## Show us
2525
<!-- Screenshots or a quick video help a lot, especially for UI changes -->
2626

27-
## Quick checks
27+
## Quick checks
2828
<!-- Only mark what applies to your change -->
2929
- [ ] I tested this myself and it works
3030
- [ ] I added comments to explain tricky parts (if needed)
3131
- [ ] I updated the docs if I changed how something works
3232
- [ ] No weird errors in the console
3333

34-
## 💬 Anything else we should know?
34+
## Anything else we should know?
3535
<!-- Extra context, questions, or things you're not sure about -->

README.md

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,39 @@
1515

1616
PromptBase stores prompts. Notion organizes them. FlowGPT shares them. None of them remember how they got there.
1717

18-
In real life, prompts evolve. You tweak your "code review prompt" three times, and by the fourth iteration you've forgotten what made version 2 actually work. There is no tool aimed at everyday users that tracks how your prompts change over time until now.
18+
In real life, prompts evolve. You tweak your "code review prompt" three times, and by the fourth iteration you've forgotten what made version 2 actually work. There is no tool aimed at everyday users that tracks how your prompts change over time, until now.
1919

2020
closedNote is built on one thesis: **a prompt is not a sticky note. It's a document with a history.**
2121

22-
Beyond versioning, closedNote adds structure: organize into collections, chain into multi-step workflows, refine with AI, and import from any image via OCR all private by default.
22+
Beyond versioning, closedNote adds structure: organize into collections, chain into multi-step workflows, refine with AI, and import from any image via OCR, all private by default.
2323

2424
---
2525

26-
## Version History — Git for Your Prompts
26+
## Version History, git for your prompts
2727

28-
Every time you save an edit, closedNote snapshots the version. Jump back to any point in time, see exactly what changed line by line, and restore with one click without overwriting your history.
28+
Every time you save an edit, closedNote snapshots the version. Jump back to any point in time, see exactly what changed line by line, and restore with one click, without overwriting your history.
2929

3030
![Version History](./screenshots/versioning01.png)
3131

3232
- Full version timeline on every prompt
33-
- Visual diff additions in green, removals in red
33+
- Visual diff, additions in green, removals in red
3434
- Restore any version without losing the history chain
35-
- Versions only created when content actually changes no noise
35+
- Versions only created when content actually changes, no noise
3636

3737
---
3838

3939
## All Features
4040

41-
- **Version History** track every draft with a visual diff and one-click restore *(new)*
42-
- **Instant Search** command palette (`⌘K`) across your entire library
43-
- **Collections** group prompts by topic, project, or use case
44-
- **AI Refinement** clean up rough ideas into polished, reusable prompts using your own API key
45-
- **OCR Import** upload a screenshot or photo, extract the text, save it as a prompt
46-
- **Prompt Chains** link prompts into multi-step workflows where each output feeds the next
47-
- **One-Click Copy** paste straight into ChatGPT, Claude, Cursor, or wherever you work
48-
- **Private by Default** row-level security ensures your data is never accessible to others
49-
- **Dark Mode** full theme support, system-aware
50-
- **Fully Responsive** works on mobile without crying
41+
- **Version History**, track every draft with a visual diff and one-click restore *(new)*
42+
- **Instant Search**, command palette (`⌘K`) across your entire library
43+
- **Collections**, group prompts by topic, project, or use case
44+
- **AI Refinement**, clean up rough ideas into polished, reusable prompts using your own API key
45+
- **OCR Import**, upload a screenshot or photo, extract the text, save it as a prompt
46+
- **Prompt Chains**, link prompts into multi-step workflows where each output feeds the next
47+
- **One-Click Copy**, paste straight into ChatGPT, Claude, Cursor, or wherever you work
48+
- **Private by Default**, row-level security ensures your data is never accessible to others
49+
- **Dark Mode**, full theme support, system-aware
50+
- **Fully Responsive**, works on mobile without crying
5151

5252
---
5353

@@ -107,7 +107,7 @@ I got tired of re-engineering my "perfect ChatGPT prompts" every time I needed a
107107

108108
Meanwhile, prompt engineers were dropping tips on X and Stack Overflow, but nobody had a good place to store, iterate on, and *remember* them.
109109

110-
So I built one and added version control, because the best prompt you'll ever write is usually the fourth draft of something you thought was broken.
110+
So I built one, and added version control, because the best prompt you'll ever write is usually the fourth draft of something you thought was broken.
111111

112112
---
113113

@@ -155,7 +155,7 @@ See [open issues](https://github.com/aboderinsamuel/closedNote/issues) for what'
155155

156156
## Built by
157157

158-
**Samuel Aboderin** Computer Engineering, UNILAG 🇳🇬
158+
**Samuel Aboderin**, Computer Engineering, UNILAG 🇳🇬
159159

160160
[![GitHub](https://img.shields.io/badge/GitHub-aboderinsamuel-black?style=flat-square&logo=github)](https://github.com/aboderinsamuel)
161161
[![LinkedIn](https://img.shields.io/badge/LinkedIn-samuelaboderin-0A66C2?style=flat-square&logo=linkedin&logoColor=white)](https://www.linkedin.com/in/samuelaboderin)
@@ -164,8 +164,8 @@ See [open issues](https://github.com/aboderinsamuel/closedNote/issues) for what'
164164

165165
## License
166166

167-
MIT use it, remix it, improve it.
167+
MIT, use it, remix it, improve it.
168168

169169
---
170170

171-
*closedNote because your prompts deserve better than browser history.*
171+
*closedNote, because your prompts deserve better than browser history.*

__tests__/components/PromptForm.test.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ import { render, screen, waitFor } from "@testing-library/react";
1313
import userEvent from "@testing-library/user-event";
1414
import { PromptForm } from "@/components/PromptForm";
1515

16-
// ── Mocks ────────────────────────────────────────────────────────────────────
16+
// Mocks
1717

1818
// jest.mock() is hoisted before variable declarations, so factories must only
19-
// use jest.fn() inline no outer variables. We then import the mocked hooks
19+
// use jest.fn() inline, no outer variables. We then import the mocked hooks
2020
// and call mockReturnValue() to inject our named jest.fn() references.
2121
jest.mock("next/navigation", () => ({ useRouter: jest.fn() }));
2222
jest.mock("@/lib/hooks/usePrompts", () => ({ usePrompts: jest.fn() }));
@@ -33,7 +33,7 @@ const mockAddOptimistic = jest.fn();
3333
const mockRefresh = jest.fn(() => Promise.resolve());
3434
const mockSavePrompt = savePrompt as jest.Mock;
3535

36-
// ── Helpers ──────────────────────────────────────────────────────────────────
36+
// Helpers
3737

3838
function renderWithAuth(user: object | null = { id: "user-1", email: "test@example.com" }) {
3939
(useRouter as jest.Mock).mockReturnValue({ push: mockPush });
@@ -50,9 +50,9 @@ function renderWithAuth(user: object | null = { id: "user-1", email: "test@examp
5050
return render(<PromptForm />);
5151
}
5252

53-
// ── Tests ─────────────────────────────────────────────────────────────────────
53+
// Tests
5454

55-
describe("PromptForm rendering", () => {
55+
describe("PromptForm - rendering", () => {
5656
it("renders all form fields", () => {
5757
renderWithAuth();
5858
expect(screen.getByPlaceholderText("Give your prompt a name")).toBeInTheDocument();
@@ -68,7 +68,7 @@ describe("PromptForm – rendering", () => {
6868
});
6969
});
7070

71-
describe("PromptForm unauthenticated behavior", () => {
71+
describe("PromptForm - unauthenticated behavior", () => {
7272
it("redirects to /login on submit when user is not authenticated", async () => {
7373
renderWithAuth(null);
7474
await userEvent.type(screen.getByPlaceholderText("Give your prompt a name"), "Test Prompt");
@@ -80,7 +80,7 @@ describe("PromptForm – unauthenticated behavior", () => {
8080
});
8181
});
8282

83-
describe("PromptForm authenticated submission", () => {
83+
describe("PromptForm - authenticated submission", () => {
8484
beforeEach(() => {
8585
jest.clearAllMocks();
8686
mockSavePrompt.mockResolvedValue(undefined);
@@ -146,7 +146,7 @@ describe("PromptForm – authenticated submission", () => {
146146

147147
it("still calls refresh when savePrompt rejects, to roll back the optimistic entry", async () => {
148148
mockSavePrompt.mockRejectedValueOnce(new Error("network error"));
149-
// PromptForm logs the error silence it so Jest output stays clean
149+
// PromptForm logs the error, silence it so Jest output stays clean
150150
jest.spyOn(console, "error").mockImplementation(() => {});
151151
renderWithAuth();
152152
await userEvent.type(screen.getByPlaceholderText("Give your prompt a name"), "Prompt");

__tests__/lib/auth.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ import { supabase } from "@/lib/supabase";
2929

3030
const mockAuth = supabase.auth as jest.Mocked<typeof supabase.auth>;
3131

32-
// ─── registerUser ────────────────────────────────────────────────────────────
32+
// registerUser
3333

34-
describe("registerUser input validation", () => {
34+
describe("registerUser - input validation", () => {
3535
it("rejects empty email and password", async () => {
3636
const result = await registerUser("", "");
3737
expect(result).toEqual({ ok: false, error: "Email and password are required" });
@@ -62,7 +62,7 @@ describe("registerUser – input validation", () => {
6262
});
6363
});
6464

65-
describe("registerUser Supabase error handling", () => {
65+
describe("registerUser - Supabase error handling", () => {
6666
it("returns error message from Supabase on failure", async () => {
6767
(mockAuth.signUp as jest.Mock).mockResolvedValueOnce({
6868
data: { user: null, session: null },
@@ -92,9 +92,9 @@ describe("registerUser – Supabase error handling", () => {
9292
});
9393
});
9494

95-
// ─── authenticateUser ────────────────────────────────────────────────────────
95+
// authenticateUser
9696

97-
describe("authenticateUser input validation", () => {
97+
describe("authenticateUser - input validation", () => {
9898
it("rejects empty email and password", async () => {
9999
const result = await authenticateUser("", "");
100100
expect(result).toEqual({ ok: false, error: "Email and password are required" });
@@ -111,7 +111,7 @@ describe("authenticateUser – input validation", () => {
111111
});
112112
});
113113

114-
describe("authenticateUser Supabase error handling", () => {
114+
describe("authenticateUser - Supabase error handling", () => {
115115
it("maps invalid credentials to a friendly message", async () => {
116116
(mockAuth.signInWithPassword as jest.Mock).mockResolvedValueOnce({
117117
data: { user: null, session: null },

app/chains/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export default function ChainsPage() {
5959
Prompt Threads
6060
</h1>
6161
<p className="mt-1 text-sm text-neutral-500 dark:text-neutral-400">
62-
Build multi-step prompt workflows and run them sequentially.
62+
String prompts together and run them in sequence.
6363
</p>
6464
</div>
6565
<Link
@@ -108,7 +108,7 @@ export default function ChainsPage() {
108108
No threads yet
109109
</h2>
110110
<p className="text-sm text-neutral-500 dark:text-neutral-400 mb-6 max-w-sm">
111-
Create your first prompt thread to build multi-step AI workflows. Thread prompts together and run them in sequence.
111+
Create a thread to chain prompts and run them one by one.
112112
</p>
113113
<Link
114114
href="/chains/new"

app/dashboard/page.tsx

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@
22

33
import { Suspense } from "react";
44
import { useState, useMemo, useEffect } from "react";
5+
import Link from "next/link";
56
import { groupPromptsByCollection, filterPrompts } from "@/lib/promptData";
67
import { PromptModel } from "@/lib/types";
78
import { Header } from "@/components/Header";
89
import { Sidebar } from "@/components/Sidebar";
910
import { Layout } from "@/components/Layout";
1011
import { PromptCollection } from "@/components/PromptCollection";
11-
import { UseCasesShowcase } from "@/components/UseCasesShowcase";
12-
import { PoweredByCarousel } from "@/components/PoweredByCarousel";
1312
import { usePrompts } from "@/lib/hooks/usePrompts";
1413
import { useAuth } from "@/components/AuthProvider";
1514

@@ -81,23 +80,17 @@ function DashboardContent() {
8180
))}
8281
</div>
8382
) : allPrompts.length === 0 ? (
84-
<div className="max-w-2xl mx-auto">
85-
<div className="text-center mb-8">
86-
<h1 className="font-serif-title text-4xl sm:text-5xl font-normal text-neutral-900 dark:text-neutral-100 mb-4">
87-
closedNote
88-
</h1>
89-
<p className="text-lg text-neutral-600 dark:text-neutral-400 max-w-xl mx-auto">
90-
Your personal prompt notebook. Create, organize, and refine AI
91-
prompts with speed and clarity.
92-
</p>
93-
</div>
94-
<div className="mb-8">
95-
<div className="text-center mb-2 text-xs uppercase tracking-wide text-neutral-500 dark:text-neutral-400">
96-
Powered by
97-
</div>
98-
<PoweredByCarousel />
99-
</div>
100-
<UseCasesShowcase />
83+
<div className="max-w-sm mx-auto text-center py-20">
84+
<p className="text-neutral-900 dark:text-neutral-100 font-medium mb-2">No prompts yet</p>
85+
<p className="text-sm text-neutral-500 dark:text-neutral-400 mb-6">
86+
Create your first one and it'll show up here.
87+
</p>
88+
<Link
89+
href="/prompts/new"
90+
className="inline-flex items-center px-5 py-2.5 bg-neutral-900 hover:bg-neutral-800 dark:bg-neutral-100 dark:hover:bg-neutral-200 dark:text-neutral-900 text-white font-medium rounded-full transition-colors text-sm"
91+
>
92+
+ New prompt
93+
</Link>
10194
</div>
10295
) : (
10396
<div className="max-w-5xl mx-auto w-full">

0 commit comments

Comments
 (0)