My-Weekly-ToDo-List/src/lib/quotes.ts
mARTin 163e9c1a07 feat: major update — mobile fix, auth decoupling, CalDAV perf, projects, fonts, quotes
Mobile fixes:
- Add viewport meta tag (was missing, causing broken mobile rendering)
- Make header nav controls visible on mobile (opacity-0 group-hover was invisible on touch)
- Add touch swipe gestures for day navigation on mobile
- Fix viewDays responsive override after profile load

Bug fixes:
- Fix goal save (WeeklyView used POST but route only had GET/PUT; fix to use PUT, add POST alias)
- Fix body key mismatch (goal → text) in goal save request

Auth & identity (Task 1):
- Add accountNumber (auto-increment) to User model for stable identity
- Fix OAuth flows: pass user CUID in state instead of email
- Google/Outlook callbacks now look up users by ID, not email
- Non-Gmail users can now connect Google Calendar/Tasks

CalDAV performance (Task 5):
- Embed CalDAV object URL in Apple event IDs (caldav::<url>::<uid> format)
- Delete/update now use O(1) direct URL access instead of O(n) full calendar scan
- Optimistic UI removal on delete (no blocking force-refresh)
- Legacy fallback for old-format IDs during transition

Apple Calendar data (Task 2):
- Pass URL, location, recurringEventId, isRecurring through full pipeline
- Add url, recurringEventId, isRecurring to CachedCalendarEvent schema
- Calendar cache now reads/writes all new fields

Projects (Task 6):
- New Project model (name, icon, color, description, order)
- CRUD API at /api/tasks/projects
- Tasks now support optional projectId with cascading nullify

Quotes (Task 4):
- Curated local quote database (50 quotes, DE+EN) with tag filtering
- Preset quote source APIs (ZenQuotes, Quotable, Forismatic, Type.fit)

Fonts (Task 7):
- FontPicker component with searchable dropdown and live preview
- /api/fonts endpoint (Google Fonts API proxy with 24h cache, fallback to 40 popular fonts)

Quick Settings (Task 8):
- QuickSettingsSidebar component (font size, spacing, show completed, start day, show lines)
- New user preferences: showCompletedTasks, showLines, startDayOffset, quoteSourceUrls

v1.9.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 17:55:49 +01:00

384 lines
11 KiB
TypeScript

// quotes.ts - Curated quotes collection and utility functions
export interface LocalQuote {
text: string;
author: string;
language: "de" | "en";
tags: string[];
}
export const PRESET_QUOTE_SOURCES = [
{
name: "ZenQuotes",
url: "https://zenquotes.io/api/random",
language: "en",
tags: ["motivation", "wisdom", "life"],
},
{
name: "Quotable",
url: "https://api.quotable.io/random",
language: "en",
tags: ["motivation", "wisdom", "success", "life"],
},
{
name: "Forismatic",
url: "https://api.forismatic.com/api/1.0/?method=getQuote&format=json&lang=de",
language: "de",
tags: ["motivation", "wisdom", "life"],
},
{
name: "Type.fit",
url: "https://type.fit/api/quotes",
language: "en",
tags: ["motivation", "wisdom"],
},
] as const;
export const LOCAL_QUOTES: LocalQuote[] = [
// --- German Quotes ---
{
text: "Es ist nicht genug zu wissen, man muss auch anwenden; es ist nicht genug zu wollen, man muss auch tun.",
author: "Johann Wolfgang von Goethe",
language: "de",
tags: ["motivation", "work", "perseverance"],
},
{
text: "Wer immer tut, was er schon kann, bleibt immer das, was er schon ist.",
author: "Henry Ford",
language: "de",
tags: ["motivation", "success", "perseverance"],
},
{
text: "Der Zweck des Lebens ist das Leben selbst.",
author: "Johann Wolfgang von Goethe",
language: "de",
tags: ["life", "wisdom"],
},
{
text: "Man muss das Unmogliche versuchen, um das Mogliche zu erreichen.",
author: "Hermann Hesse",
language: "de",
tags: ["motivation", "perseverance"],
},
{
text: "Wer nicht kann, was er will, muss wollen, was er kann.",
author: "Friedrich Schiller",
language: "de",
tags: ["wisdom", "perseverance", "life"],
},
{
text: "Es hort doch jeder nur, was er versteht.",
author: "Johann Wolfgang von Goethe",
language: "de",
tags: ["wisdom", "life"],
},
{
text: "Ohne Musik ware das Leben ein Irrtum.",
author: "Friedrich Nietzsche",
language: "de",
tags: ["life", "creativity"],
},
{
text: "Wege entstehen dadurch, dass man sie geht.",
author: "Franz Kafka",
language: "de",
tags: ["motivation", "perseverance", "life"],
},
{
text: "Der Mensch ist nichts anderes als wozu er sich macht.",
author: "Jean-Paul Sartre",
language: "de",
tags: ["wisdom", "life", "motivation"],
},
{
text: "Wer kampft, kann verlieren. Wer nicht kampft, hat schon verloren.",
author: "Bertolt Brecht",
language: "de",
tags: ["motivation", "perseverance", "success"],
},
{
text: "Die Grenzen meiner Sprache bedeuten die Grenzen meiner Welt.",
author: "Ludwig Wittgenstein",
language: "de",
tags: ["wisdom", "creativity"],
},
{
text: "Was mich nicht umbringt, macht mich starker.",
author: "Friedrich Nietzsche",
language: "de",
tags: ["perseverance", "motivation"],
},
{
text: "Phantasie ist wichtiger als Wissen, denn Wissen ist begrenzt.",
author: "Albert Einstein",
language: "de",
tags: ["creativity", "wisdom"],
},
{
text: "Nur wer sein Ziel kennt, findet den Weg.",
author: "Laozi",
language: "de",
tags: ["wisdom", "motivation", "success"],
},
{
text: "Die beste Zeit einen Baum zu pflanzen war vor zwanzig Jahren. Die zweitbeste Zeit ist jetzt.",
author: "Konfuzius",
language: "de",
tags: ["wisdom", "motivation", "work"],
},
{
text: "Auch aus Steinen, die einem in den Weg gelegt werden, kann man Schones bauen.",
author: "Johann Wolfgang von Goethe",
language: "de",
tags: ["perseverance", "creativity", "life"],
},
{
text: "Handle, ehe du gehandelt wirst.",
author: "Friedrich Schiller",
language: "de",
tags: ["motivation", "work"],
},
{
text: "Geduld ist das Vertrauen, dass alles kommt, wenn die Zeit reif ist.",
author: "Konfuzius",
language: "de",
tags: ["wisdom", "perseverance", "life"],
},
{
text: "Im Wesen der Musik liegt es, Freude zu machen.",
author: "Aristoteles",
language: "de",
tags: ["creativity", "life", "humor"],
},
{
text: "Lache nie uber die Dummheit der anderen. Sie ist deine Chance.",
author: "Winston Churchill",
language: "de",
tags: ["humor", "success", "wisdom"],
},
{
text: "Leben ist das, was passiert, wahrend du eifrig dabei bist, andere Plane zu machen.",
author: "John Lennon",
language: "de",
tags: ["life", "humor", "wisdom"],
},
{
text: "Der Langsamste, der sein Ziel nicht aus den Augen verliert, geht noch immer geschwinder als jener, der ohne Ziel umherirrt.",
author: "Gotthold Ephraim Lessing",
language: "de",
tags: ["perseverance", "motivation", "work"],
},
{
text: "Ein Tropfen Humor auf einen Zentner Verstand.",
author: "Friedrich Nietzsche",
language: "de",
tags: ["humor", "wisdom"],
},
// --- English Quotes ---
{
text: "The only way to do great work is to love what you do.",
author: "Steve Jobs",
language: "en",
tags: ["work", "motivation", "success"],
},
{
text: "Stay hungry, stay foolish.",
author: "Steve Jobs",
language: "en",
tags: ["motivation", "creativity"],
},
{
text: "Life is what happens when you are busy making other plans.",
author: "John Lennon",
language: "en",
tags: ["life", "wisdom"],
},
{
text: "In the middle of difficulty lies opportunity.",
author: "Albert Einstein",
language: "en",
tags: ["perseverance", "motivation", "success"],
},
{
text: "The unexamined life is not worth living.",
author: "Socrates",
language: "en",
tags: ["wisdom", "life"],
},
{
text: "Be yourself; everyone else is already taken.",
author: "Oscar Wilde",
language: "en",
tags: ["life", "wisdom", "humor"],
},
{
text: "To live is the rarest thing in the world. Most people exist, that is all.",
author: "Oscar Wilde",
language: "en",
tags: ["life", "wisdom"],
},
{
text: "The man who moves a mountain begins by carrying away small stones.",
author: "Konfuzius",
language: "en",
tags: ["perseverance", "motivation", "work"],
},
{
text: "It is not because things are difficult that we do not dare; it is because we do not dare that they are difficult.",
author: "Seneca",
language: "en",
tags: ["motivation", "perseverance", "wisdom"],
},
{
text: "The happiness of your life depends upon the quality of your thoughts.",
author: "Marcus Aurelius",
language: "en",
tags: ["wisdom", "life"],
},
{
text: "Waste no more time arguing about what a good man should be. Be one.",
author: "Marcus Aurelius",
language: "en",
tags: ["wisdom", "motivation", "work"],
},
{
text: "If you want to lift yourself up, lift up someone else.",
author: "Booker T. Washington",
language: "en",
tags: ["motivation", "wisdom", "life"],
},
{
text: "Darkness cannot drive out darkness; only light can do that.",
author: "Martin Luther King Jr.",
language: "en",
tags: ["wisdom", "life", "motivation"],
},
{
text: "The time is always right to do what is right.",
author: "Martin Luther King Jr.",
language: "en",
tags: ["motivation", "wisdom", "work"],
},
{
text: "There is no greater agony than bearing an untold story inside you.",
author: "Maya Angelou",
language: "en",
tags: ["creativity", "life"],
},
{
text: "We delight in the beauty of the butterfly, but rarely admit the changes it has gone through to achieve that beauty.",
author: "Maya Angelou",
language: "en",
tags: ["perseverance", "life", "wisdom"],
},
{
text: "The secret of getting ahead is getting started.",
author: "Mark Twain",
language: "en",
tags: ["motivation", "work", "success"],
},
{
text: "Whenever you find yourself on the side of the majority, it is time to pause and reflect.",
author: "Mark Twain",
language: "en",
tags: ["wisdom", "creativity"],
},
{
text: "Twenty years from now you will be more disappointed by the things you did not do than by the ones you did.",
author: "Mark Twain",
language: "en",
tags: ["motivation", "life", "perseverance"],
},
{
text: "It does not matter how slowly you go as long as you do not stop.",
author: "Konfuzius",
language: "en",
tags: ["perseverance", "motivation"],
},
{
text: "Success is not final, failure is not fatal: it is the courage to continue that counts.",
author: "Winston Churchill",
language: "en",
tags: ["perseverance", "success", "motivation"],
},
{
text: "The best time to plant a tree was 20 years ago. The second best time is now.",
author: "Chinese Proverb",
language: "en",
tags: ["motivation", "wisdom", "work"],
},
{
text: "Do what you can, with what you have, where you are.",
author: "Theodore Roosevelt",
language: "en",
tags: ["motivation", "work", "perseverance"],
},
{
text: "Creativity is intelligence having fun.",
author: "Albert Einstein",
language: "en",
tags: ["creativity", "humor", "wisdom"],
},
{
text: "Everything you can imagine is real.",
author: "Pablo Picasso",
language: "en",
tags: ["creativity", "motivation"],
},
{
text: "I have not failed. I have just found 10,000 ways that will not work.",
author: "Thomas Edison",
language: "en",
tags: ["perseverance", "humor", "success"],
},
{
text: "Well done is better than well said.",
author: "Benjamin Franklin",
language: "en",
tags: ["work", "motivation", "success"],
},
{
text: "You miss 100% of the shots you do not take.",
author: "Wayne Gretzky",
language: "en",
tags: ["motivation", "success"],
},
];
/**
* All unique tags available across the local quotes collection.
*/
export const AVAILABLE_QUOTE_TAGS: string[] = Array.from(
new Set(LOCAL_QUOTES.flatMap((q) => q.tags))
).sort();
/**
* Returns a random quote from the local collection, optionally filtered
* by language and/or tag.
*
* @param language - Filter by "de" or "en". If omitted, picks from all.
* @param tag - Filter by a specific tag (e.g. "motivation"). If omitted, no tag filter.
* @returns A random LocalQuote matching the filters, or a fallback if no match found.
*/
export function getRandomLocalQuote(
language?: string,
tag?: string
): LocalQuote {
let pool = LOCAL_QUOTES;
if (language) {
pool = pool.filter((q) => q.language === language);
}
if (tag) {
pool = pool.filter((q) => q.tags.includes(tag));
}
if (pool.length === 0) {
// Fallback: return a random quote from the full collection
return LOCAL_QUOTES[Math.floor(Math.random() * LOCAL_QUOTES.length)];
}
return pool[Math.floor(Math.random() * pool.length)];
}