mirror of
https://github.com/AnoyRC/priospace.git
synced 2026-09-17 17:51:30 +08:00
Added 4 new themes and responsive Desktop support
This commit is contained in:
+313
@@ -432,4 +432,317 @@
|
||||
--shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25);
|
||||
--tracking-normal: 0em;
|
||||
--spacing: 0.25rem;
|
||||
}
|
||||
|
||||
/* === PASTEL DREAM THEME === */
|
||||
.theme-pastel-dream {
|
||||
--background: 280 20% 98%;
|
||||
--foreground: 240 10% 20%;
|
||||
--card: 270 30% 96%;
|
||||
--card-foreground: 240 10% 20%;
|
||||
--popover: 270 30% 96%;
|
||||
--popover-foreground: 240 10% 20%;
|
||||
--primary: 280 80% 60%;
|
||||
--primary-foreground: 280 20% 95%;
|
||||
--secondary: 200 40% 70%;
|
||||
--secondary-foreground: 240 10% 20%;
|
||||
--muted: 270 20% 90%;
|
||||
--muted-foreground: 240 10% 40%;
|
||||
--accent: 320 70% 65%;
|
||||
--accent-foreground: 280 20% 95%;
|
||||
--destructive: 0 80% 60%;
|
||||
--destructive-foreground: 280 20% 95%;
|
||||
--border: 270 15% 80%;
|
||||
--input: 270 15% 80%;
|
||||
--ring: 280 80% 60%;
|
||||
--radius: 0.75rem;
|
||||
--shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1);
|
||||
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
|
||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
|
||||
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
|
||||
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
||||
--tracking-normal: 0em;
|
||||
--spacing: 0.25rem;
|
||||
}
|
||||
|
||||
.theme-pastel-dream.dark {
|
||||
--background: 280 10% 8%;
|
||||
--foreground: 280 15% 85%;
|
||||
--card: 280 12% 12%;
|
||||
--card-foreground: 280 15% 85%;
|
||||
--popover: 280 12% 12%;
|
||||
--popover-foreground: 280 15% 85%;
|
||||
--primary: 280 70% 55%;
|
||||
--primary-foreground: 280 10% 95%;
|
||||
--secondary: 200 50% 65%;
|
||||
--secondary-foreground: 280 10% 95%;
|
||||
--muted: 280 10% 15%;
|
||||
--muted-foreground: 280 10% 60%;
|
||||
--accent: 320 60% 60%;
|
||||
--accent-foreground: 280 10% 95%;
|
||||
--destructive: 0 70% 55%;
|
||||
--destructive-foreground: 280 10% 95%;
|
||||
--border: 280 10% 20%;
|
||||
--input: 280 10% 20%;
|
||||
--ring: 280 70% 55%;
|
||||
}
|
||||
|
||||
/* === QUANTUM ROSE THEME === */
|
||||
.theme-quantum-rose {
|
||||
--background: 330 90% 97%;
|
||||
--foreground: 320 20% 20%;
|
||||
--card: 330 85% 95%;
|
||||
--card-foreground: 320 20% 20%;
|
||||
--popover: 330 85% 95%;
|
||||
--popover-foreground: 320 20% 20%;
|
||||
--primary: 320 85% 60%;
|
||||
--primary-foreground: 330 20% 95%;
|
||||
--secondary: 240 70% 70%;
|
||||
--secondary-foreground: 320 20% 20%;
|
||||
--muted: 330 50% 90%;
|
||||
--muted-foreground: 320 20% 45%;
|
||||
--accent: 180 70% 60%;
|
||||
--accent-foreground: 330 20% 95%;
|
||||
--destructive: 0 80% 60%;
|
||||
--destructive-foreground: 330 20% 95%;
|
||||
--border: 330 60% 85%;
|
||||
--input: 330 60% 85%;
|
||||
--ring: 320 85% 60%;
|
||||
--radius: 1rem;
|
||||
--shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1);
|
||||
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
|
||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
|
||||
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
|
||||
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
||||
--tracking-normal: 0em;
|
||||
--spacing: 0.25rem;
|
||||
}
|
||||
|
||||
.theme-quantum-rose.dark {
|
||||
--background: 320 20% 8%;
|
||||
--foreground: 320 80% 85%;
|
||||
--card: 320 25% 12%;
|
||||
--card-foreground: 320 80% 85%;
|
||||
--popover: 320 25% 12%;
|
||||
--popover-foreground: 320 80% 85%;
|
||||
--primary: 320 75% 60%;
|
||||
--primary-foreground: 320 15% 95%;
|
||||
--secondary: 240 80% 65%;
|
||||
--secondary-foreground: 320 15% 95%;
|
||||
--muted: 320 20% 15%;
|
||||
--muted-foreground: 320 20% 60%;
|
||||
--accent: 180 70% 55%;
|
||||
--accent-foreground: 320 15% 95%;
|
||||
--destructive: 0 75% 60%;
|
||||
--destructive-foreground: 320 15% 95%;
|
||||
--border: 320 20% 25%;
|
||||
--input: 320 20% 25%;
|
||||
--ring: 320 75% 60%;
|
||||
}
|
||||
|
||||
/* === MODERN THEME (already defined, just fixing syntax) === */
|
||||
.theme-modern {
|
||||
--background: 223.8136 0% 100%;
|
||||
--foreground: 223.8136 0% 3.9388%;
|
||||
--card: 223.8136 0% 100%;
|
||||
--card-foreground: 223.8136 0% 3.9388%;
|
||||
--popover: 223.8136 0% 100%;
|
||||
--popover-foreground: 223.8136 0% 3.9388%;
|
||||
--primary: 223.8136 0% 9.0527%;
|
||||
--primary-foreground: 223.8136 0% 98.0256%;
|
||||
--secondary: 223.8136 0% 96.0587%;
|
||||
--secondary-foreground: 223.8136 0% 9.0527%;
|
||||
--muted: 223.8136 0% 96.0587%;
|
||||
--muted-foreground: 223.8136 0% 45.1519%;
|
||||
--accent: 223.8136 0% 96.0587%;
|
||||
--accent-foreground: 223.8136 0% 9.0527%;
|
||||
--destructive: 0 80% 60%;
|
||||
--destructive-foreground: 223.8136 0% 98.0256%;
|
||||
--border: 223.8136 0% 90%;
|
||||
--input: 223.8136 0% 90%;
|
||||
--ring: 223.8136 0% 9.0527%;
|
||||
--radius: 0.5rem;
|
||||
--shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1);
|
||||
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
|
||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
|
||||
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
|
||||
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
||||
--tracking-normal: 0em;
|
||||
--spacing: 0.25rem;
|
||||
}
|
||||
|
||||
.theme-modern.dark {
|
||||
--background: 223.8136 0% 3.9388%;
|
||||
--foreground: 223.8136 0% 98.0256%;
|
||||
--card: 223.8136 0% 7%;
|
||||
--card-foreground: 223.8136 0% 98.0256%;
|
||||
--popover: 223.8136 0% 7%;
|
||||
--popover-foreground: 223.8136 0% 98.0256%;
|
||||
--primary: 223.8136 0% 60%;
|
||||
--primary-foreground: 223.8136 0% 10%;
|
||||
--secondary: 223.8136 0% 12%;
|
||||
--secondary-foreground: 223.8136 0% 98.0256%;
|
||||
--muted: 223.8136 0% 10%;
|
||||
--muted-foreground: 223.8136 0% 60%;
|
||||
--accent: 223.8136 0% 12%;
|
||||
--accent-foreground: 223.8136 0% 98.0256%;
|
||||
--destructive: 0 80% 60%;
|
||||
--destructive-foreground: 223.8136 0% 98.0256%;
|
||||
--border: 223.8136 0% 15%;
|
||||
--input: 223.8136 0% 15%;
|
||||
--ring: 223.8136 0% 60%;
|
||||
}
|
||||
|
||||
/* === TWITTER THEME === */
|
||||
.theme-twitter {
|
||||
--background: 205 100% 98%;
|
||||
--foreground: 205 20% 20%;
|
||||
--card: 205 100% 96%;
|
||||
--card-foreground: 205 20% 20%;
|
||||
--popover: 205 100% 96%;
|
||||
--popover-foreground: 205 20% 20%;
|
||||
--primary: 205 100% 50%;
|
||||
--primary-foreground: 205 20% 95%;
|
||||
--secondary: 0 0% 90%;
|
||||
--secondary-foreground: 205 20% 20%;
|
||||
--muted: 205 50% 90%;
|
||||
--muted-foreground: 205 20% 50%;
|
||||
--accent: 15 100% 60%;
|
||||
--accent-foreground: 205 20% 95%;
|
||||
--destructive: 0 80% 60%;
|
||||
--destructive-foreground: 205 20% 95%;
|
||||
--border: 205 80% 85%;
|
||||
--input: 205 80% 85%;
|
||||
--ring: 205 100% 50%;
|
||||
--radius: 0.375rem;
|
||||
--shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1);
|
||||
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
|
||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
|
||||
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
|
||||
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
||||
--tracking-normal: 0em;
|
||||
--spacing: 0.25rem;
|
||||
}
|
||||
|
||||
.theme-twitter.dark {
|
||||
--background: 205 20% 6%;
|
||||
--foreground: 205 20% 90%;
|
||||
--card: 205 25% 10%;
|
||||
--card-foreground: 205 20% 90%;
|
||||
--popover: 205 25% 10%;
|
||||
--popover-foreground: 205 20% 90%;
|
||||
--primary: 205 100% 55%;
|
||||
--primary-foreground: 205 20% 95%;
|
||||
--secondary: 0 0% 20%;
|
||||
--secondary-foreground: 205 20% 90%;
|
||||
--muted: 205 20% 15%;
|
||||
--muted-foreground: 205 20% 60%;
|
||||
--accent: 15 100% 65%;
|
||||
--accent-foreground: 205 20% 95%;
|
||||
--destructive: 0 80% 60%;
|
||||
--destructive-foreground: 205 20% 95%;
|
||||
--border: 205 20% 25%;
|
||||
--input: 205 20% 25%;
|
||||
--ring: 205 100% 55%;
|
||||
}
|
||||
|
||||
/* === AMBER MINIMAL THEME === */
|
||||
.theme-amber-minimal {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 0 0% 14.9020%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 0 0% 14.9020%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 0 0% 14.9020%;
|
||||
--primary: 37.6923 92.1260% 50.1961%;
|
||||
--primary-foreground: 0 0% 0%;
|
||||
--secondary: 220.0000 14.2857% 95.8824%;
|
||||
--secondary-foreground: 215 13.7931% 34.1176%;
|
||||
--muted: 210 20.0000% 98.0392%;
|
||||
--muted-foreground: 220 8.9362% 46.0784%;
|
||||
--accent: 48.0000 100.0000% 96.0784%;
|
||||
--accent-foreground: 22.7273 82.5000% 31.3725%;
|
||||
--destructive: 0 84.2365% 60.1961%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
--border: 220 13.0435% 90.9804%;
|
||||
--input: 220 13.0435% 90.9804%;
|
||||
--ring: 37.6923 92.1260% 50.1961%;
|
||||
--chart-1: 37.6923 92.1260% 50.1961%;
|
||||
--chart-2: 32.1327 94.6188% 43.7255%;
|
||||
--chart-3: 25.9649 90.4762% 37.0588%;
|
||||
--chart-4: 22.7273 82.5000% 31.3725%;
|
||||
--chart-5: 21.7143 77.7778% 26.4706%;
|
||||
--sidebar: 210 20.0000% 98.0392%;
|
||||
--sidebar-foreground: 0 0% 14.9020%;
|
||||
--sidebar-primary: 37.6923 92.1260% 50.1961%;
|
||||
--sidebar-primary-foreground: 0 0% 100%;
|
||||
--sidebar-accent: 48.0000 100.0000% 96.0784%;
|
||||
--sidebar-accent-foreground: 22.7273 82.5000% 31.3725%;
|
||||
--sidebar-border: 220 13.0435% 90.9804%;
|
||||
--sidebar-ring: 37.6923 92.1260% 50.1961%;
|
||||
--font-sans: Inter, sans-serif;
|
||||
--font-serif: Source Serif 4, serif;
|
||||
--font-mono: JetBrains Mono, monospace;
|
||||
--radius: 0.375rem;
|
||||
--shadow-2xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
|
||||
--shadow-xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
|
||||
--shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 2px 4px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 4px 6px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 8px 10px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-2xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.25);
|
||||
--tracking-normal: 0em;
|
||||
--spacing: 0.25rem;
|
||||
}
|
||||
|
||||
.theme-amber-minimal.dark {
|
||||
--background: 0 0% 9.0196%;
|
||||
--foreground: 0 0% 89.8039%;
|
||||
--card: 0 0% 14.9020%;
|
||||
--card-foreground: 0 0% 89.8039%;
|
||||
--popover: 0 0% 14.9020%;
|
||||
--popover-foreground: 0 0% 89.8039%;
|
||||
--primary: 37.6923 92.1260% 50.1961%;
|
||||
--primary-foreground: 0 0% 0%;
|
||||
--secondary: 0 0% 14.9020%;
|
||||
--secondary-foreground: 0 0% 89.8039%;
|
||||
--muted: 0 0% 14.9020%;
|
||||
--muted-foreground: 0 0% 63.9216%;
|
||||
--accent: 22.7273 82.5000% 31.3725%;
|
||||
--accent-foreground: 48 96.6387% 76.6667%;
|
||||
--destructive: 0 84.2365% 60.1961%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
--border: 0 0% 25.0980%;
|
||||
--input: 0 0% 25.0980%;
|
||||
--ring: 37.6923 92.1260% 50.1961%;
|
||||
--chart-1: 43.2558 96.4126% 56.2745%;
|
||||
--chart-2: 32.1327 94.6188% 43.7255%;
|
||||
--chart-3: 22.7273 82.5000% 31.3725%;
|
||||
--chart-4: 25.9649 90.4762% 37.0588%;
|
||||
--chart-5: 22.7273 82.5000% 31.3725%;
|
||||
--sidebar: 0 0% 5.8824%;
|
||||
--sidebar-foreground: 0 0% 89.8039%;
|
||||
--sidebar-primary: 37.6923 92.1260% 50.1961%;
|
||||
--sidebar-primary-foreground: 0 0% 100%;
|
||||
--sidebar-accent: 22.7273 82.5000% 31.3725%;
|
||||
--sidebar-accent-foreground: 48 96.6387% 76.6667%;
|
||||
--sidebar-border: 0 0% 25.0980%;
|
||||
--sidebar-ring: 37.6923 92.1260% 50.1961%;
|
||||
--font-sans: Inter, sans-serif;
|
||||
--font-serif: Source Serif 4, serif;
|
||||
--font-mono: JetBrains Mono, monospace;
|
||||
--radius: 0.375rem;
|
||||
--shadow-2xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
|
||||
--shadow-xs: 0px 4px 8px -1px hsl(0 0% 0% / 0.05);
|
||||
--shadow-sm: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 1px 2px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-md: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 2px 4px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-lg: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 4px 6px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.10), 0px 8px 10px -2px hsl(0 0% 0% / 0.10);
|
||||
--shadow-2xl: 0px 4px 8px -1px hsl(0 0% 0% / 0.25);
|
||||
}
|
||||
+234
-96
@@ -6,7 +6,7 @@ import { DayNightCycle, AnimatedNumber } from "@/components/day-night-cycle";
|
||||
import { AnimatedYear } from "@/components/animated-year";
|
||||
import { WeeklyCalendar } from "@/components/weekly-calender";
|
||||
import { TaskList } from "@/components/task-list";
|
||||
import { Timer, Plus, BarChart3, Settings } from "lucide-react";
|
||||
import { Timer, Plus, BarChart3, Settings, CheckCircle } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { AddTaskModal } from "@/components/add-task-modal";
|
||||
import { TaskOptionsModal } from "@/components/task-options-modal";
|
||||
@@ -95,7 +95,15 @@ export default function Home() {
|
||||
const root = document.documentElement;
|
||||
|
||||
// Remove all theme classes
|
||||
root.classList.remove("theme-nature", "theme-neo-brutal", "theme-modern");
|
||||
root.classList.remove(
|
||||
"theme-nature",
|
||||
"theme-neo-brutal",
|
||||
"theme-modern",
|
||||
"theme-pastel-dream",
|
||||
"theme-quantum-rose",
|
||||
"theme-twitter",
|
||||
"theme-amber-minimal"
|
||||
);
|
||||
|
||||
// Add current theme class (except for default)
|
||||
if (theme !== "default") {
|
||||
@@ -927,7 +935,8 @@ export default function Home() {
|
||||
|
||||
{!showIntroScreen && (
|
||||
<div className="min-h-screen transition-colors duration-300 bg-background">
|
||||
<div className="max-w-lg mx-auto min-h-screen px-4 relative overflow-hidden">
|
||||
{/* Mobile/Tablet Layout (up to lg) */}
|
||||
<div className="lg:hidden max-w-lg mx-auto min-h-screen px-4 relative overflow-hidden">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
@@ -985,7 +994,7 @@ export default function Home() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="p-4 border-t border-dashed dark:border-gray-700 absolute bottom-0 left-1/2 -translate-x-1/2 bg-background/70 backdrop-blur-sm w-full z-50">
|
||||
<div className="p-4 border-t border-dashed absolute bottom-0 left-1/2 -translate-x-1/2 bg-background/70 backdrop-blur-sm w-full z-50">
|
||||
<div className="flex items-center justify-between">
|
||||
<Button
|
||||
onClick={() => setShowTimer(true)}
|
||||
@@ -1021,99 +1030,228 @@ export default function Home() {
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<AnimatePresence>
|
||||
{showSettings && (
|
||||
<SettingsModal
|
||||
onClose={() => setShowSettings(false)}
|
||||
darkMode={darkMode}
|
||||
onToggleDarkMode={() => setDarkMode(!darkMode)}
|
||||
theme={theme}
|
||||
onThemeChange={setTheme}
|
||||
onExportData={exportData}
|
||||
onImportData={importData}
|
||||
onOpenWebRTCShare={() => setShowWebRTCShare(true)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showWebRTCShare && (
|
||||
<WebRTCShareModal
|
||||
onClose={() => setShowWebRTCShare(false)}
|
||||
dailyTasks={dailyTasks}
|
||||
customTags={customTags}
|
||||
habits={habits}
|
||||
darkMode={darkMode}
|
||||
theme={theme}
|
||||
onImportData={importDataFromWebRTC}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showAddTask && (
|
||||
<AddTaskModal
|
||||
onClose={() => setShowAddTask(false)}
|
||||
onAddTask={addTask}
|
||||
customTags={customTags}
|
||||
onAddCustomTag={addCustomTag}
|
||||
selectedDate={selectedDate}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showAddSubtask && parentTaskForSubtask && (
|
||||
<AddSubtaskModal
|
||||
onClose={() => {
|
||||
setShowAddSubtask(false);
|
||||
setParentTaskForSubtask(null);
|
||||
}}
|
||||
onAddSubtask={(title, tagId) => {
|
||||
addSubtask(parentTaskForSubtask.id, title, tagId);
|
||||
}}
|
||||
customTags={customTags}
|
||||
onAddCustomTag={addCustomTag}
|
||||
parentTask={parentTaskForSubtask}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showTaskOptions && selectedTask && (
|
||||
<TaskOptionsModal
|
||||
task={selectedTask}
|
||||
customTags={customTags}
|
||||
onClose={() => {
|
||||
setShowTaskOptions(false);
|
||||
setSelectedTask(null);
|
||||
}}
|
||||
onUpdateTask={updateTask}
|
||||
onDeleteTask={deleteTask}
|
||||
onAddCustomTag={addCustomTag}
|
||||
onToggleTask={toggleTask}
|
||||
selectedDate={selectedDate}
|
||||
onTransferTask={transferTaskToCurrentDay}
|
||||
currentActualDate={new Date()}
|
||||
onAddSubtask={handleAddSubtask}
|
||||
allTasks={allTasks}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showHabits && (
|
||||
<HabitTracker
|
||||
habits={habits}
|
||||
customTags={customTags}
|
||||
onClose={() => setShowHabits(false)}
|
||||
onUpdateHabits={setHabits}
|
||||
onAddCustomTag={addCustomTag}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showTimer && (
|
||||
<TimerModal
|
||||
tasks={flatTaskList} // Use flattened list for timer
|
||||
onClose={() => setShowTimer(false)}
|
||||
onUpdateTaskTime={updateTaskTime}
|
||||
onUpdateTaskFocusTime={updateTaskFocusTime}
|
||||
onToggleTask={toggleTask}
|
||||
/>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
{/* Desktop Layout (lg and up) */}
|
||||
<div className="hidden lg:flex max-h-screen h-screen overflow-hidden">
|
||||
{/* Left Sidebar - Calendar & Navigation */}
|
||||
<div className="w-lg border-r border-dashed flex flex-col bg-background/50 backdrop-blur-sm">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
className="flex flex-col h-full"
|
||||
>
|
||||
{/* Settings Button */}
|
||||
<div className="p-6 border-b border-dashed flex items-center justify-between">
|
||||
<div className="flex items-center gap-2 text-2xl font-extrabold">
|
||||
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-primary/10">
|
||||
<CheckCircle className="h-4 w-4 text-primary" />
|
||||
</div>
|
||||
Prio Space
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setShowSettings(true)}
|
||||
className="bg-primary text-background rounded-lg py-3 px-4 hover:bg-primary/90 transition-colors"
|
||||
>
|
||||
<Settings className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Date Header */}
|
||||
<div className="p-4 border-b border-dashed px-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<DayNightCycle selectedDate={selectedDate} />
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="text-right flex flex-col">
|
||||
<div className="text-xl font-extrabold flex items-center gap-2">
|
||||
<AnimatedNumber
|
||||
value={selectedDate.getDate()}
|
||||
fontSize={20}
|
||||
/>
|
||||
{selectedDate.toLocaleDateString("en-US", {
|
||||
month: "long",
|
||||
})}
|
||||
</div>
|
||||
<div className="text-xl opacity-90 -mt-1 flex justify-end">
|
||||
<AnimatedYear
|
||||
year={selectedDate.getFullYear()}
|
||||
fontSize={30}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Calendar */}
|
||||
<div className="p-6 border-b border-dashed">
|
||||
<WeeklyCalendar
|
||||
selectedDate={selectedDate}
|
||||
onDateSelect={setSelectedDate}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Desktop Action Buttons */}
|
||||
<div className="p-6 space-y-4 flex-1">
|
||||
<Button
|
||||
onClick={() => setShowAddTask(true)}
|
||||
size="lg"
|
||||
className="w-full h-12 bg-primary hover:bg-primary/90 group hover:scale-[1.02] transition-all duration-200 [&_svg]:size-5 rounded-2xl"
|
||||
>
|
||||
<Plus className="h-5 w-5 mr-2 group-hover:scale-110 transition-transform" />
|
||||
<span className="font-extrabold">Add Task</span>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={() => setShowTimer(true)}
|
||||
variant="outline"
|
||||
size="lg"
|
||||
className="w-full h-12 font-bold hover:bg-accent/50 group hover:scale-[1.02] transition-all duration-200 rounded-2xl"
|
||||
>
|
||||
<Timer className="h-5 w-5 mr-2 group-hover:scale-110 transition-transform" />
|
||||
<span className="font-extrabold">Timer</span>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={() => setShowHabits(true)}
|
||||
variant="outline"
|
||||
size="lg"
|
||||
className="w-full h-12 font-bold hover:bg-accent/50 group hover:scale-[1.02] transition-all duration-200 rounded-2xl"
|
||||
>
|
||||
<BarChart3 className="h-5 w-5 mr-2 group-hover:scale-110 transition-transform" />
|
||||
<span className="font-extrabold">Habits</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Keyboard shortcuts hint */}
|
||||
<div className="p-6 pt-0 text-[10px] text-muted-foreground font-extrabold space-y-1 opacity-70">
|
||||
<div>⌘/Ctrl + A → Add Task</div>
|
||||
<div>⌘/Ctrl + C → Timer</div>
|
||||
<div>⌘/Ctrl + H → Habits</div>
|
||||
<div>⌘/Ctrl + X → Settings</div>
|
||||
<div>Esc → Close Modal</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
{/* Main Content Area */}
|
||||
<div className="flex-1 flex flex-col">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5, delay: 0.1 }}
|
||||
className="flex-1 overflow-hidden relative"
|
||||
>
|
||||
{/* Task List */}
|
||||
<div className="absolute top-0 left-0 h-full w-full overflow-auto hide-scroll">
|
||||
<div className="p-6 mt-[4px]">
|
||||
<TaskList
|
||||
tasks={allTasks}
|
||||
customTags={customTags}
|
||||
onToggleTask={toggleTask}
|
||||
onDeleteTask={deleteTask}
|
||||
onTaskClick={handleTaskClick}
|
||||
onAddSubtask={handleAddSubtask}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Modals - Same for both layouts */}
|
||||
<AnimatePresence>
|
||||
{showSettings && (
|
||||
<SettingsModal
|
||||
onClose={() => setShowSettings(false)}
|
||||
darkMode={darkMode}
|
||||
onToggleDarkMode={() => setDarkMode(!darkMode)}
|
||||
theme={theme}
|
||||
onThemeChange={setTheme}
|
||||
onExportData={exportData}
|
||||
onImportData={importData}
|
||||
onOpenWebRTCShare={() => setShowWebRTCShare(true)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showWebRTCShare && (
|
||||
<WebRTCShareModal
|
||||
onClose={() => setShowWebRTCShare(false)}
|
||||
dailyTasks={dailyTasks}
|
||||
customTags={customTags}
|
||||
habits={habits}
|
||||
darkMode={darkMode}
|
||||
theme={theme}
|
||||
onImportData={importDataFromWebRTC}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showAddTask && (
|
||||
<AddTaskModal
|
||||
onClose={() => setShowAddTask(false)}
|
||||
onAddTask={addTask}
|
||||
customTags={customTags}
|
||||
onAddCustomTag={addCustomTag}
|
||||
selectedDate={selectedDate}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showAddSubtask && parentTaskForSubtask && (
|
||||
<AddSubtaskModal
|
||||
onClose={() => {
|
||||
setShowAddSubtask(false);
|
||||
setParentTaskForSubtask(null);
|
||||
}}
|
||||
onAddSubtask={(title, tagId) => {
|
||||
addSubtask(parentTaskForSubtask.id, title, tagId);
|
||||
}}
|
||||
customTags={customTags}
|
||||
onAddCustomTag={addCustomTag}
|
||||
parentTask={parentTaskForSubtask}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showTaskOptions && selectedTask && (
|
||||
<TaskOptionsModal
|
||||
task={selectedTask}
|
||||
customTags={customTags}
|
||||
onClose={() => {
|
||||
setShowTaskOptions(false);
|
||||
setSelectedTask(null);
|
||||
}}
|
||||
onUpdateTask={updateTask}
|
||||
onDeleteTask={deleteTask}
|
||||
onAddCustomTag={addCustomTag}
|
||||
onToggleTask={toggleTask}
|
||||
selectedDate={selectedDate}
|
||||
onTransferTask={transferTaskToCurrentDay}
|
||||
currentActualDate={new Date()}
|
||||
onAddSubtask={handleAddSubtask}
|
||||
allTasks={allTasks}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showHabits && (
|
||||
<HabitTracker
|
||||
habits={habits}
|
||||
customTags={customTags}
|
||||
onClose={() => setShowHabits(false)}
|
||||
onUpdateHabits={setHabits}
|
||||
onAddCustomTag={addCustomTag}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showTimer && (
|
||||
<TimerModal
|
||||
tasks={flatTaskList} // Use flattened list for timer
|
||||
onClose={() => setShowTimer(false)}
|
||||
onUpdateTaskTime={updateTaskTime}
|
||||
onUpdateTaskFocusTime={updateTaskFocusTime}
|
||||
onToggleTask={toggleTask}
|
||||
/>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -4,6 +4,49 @@ import { useState, useEffect } from "react";
|
||||
import { motion, useSpring } from "framer-motion";
|
||||
import { Sun, Moon } from "lucide-react";
|
||||
|
||||
function AnimatedWeekday({ dayIndex, fontSize, textColor }) {
|
||||
const weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||
const height = fontSize * 1.2;
|
||||
|
||||
const animatedIndex = useSpring(dayIndex, { stiffness: 300, damping: 30 });
|
||||
|
||||
useEffect(() => {
|
||||
animatedIndex.set(dayIndex);
|
||||
}, [animatedIndex, dayIndex]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative overflow-hidden inline-block"
|
||||
style={{
|
||||
height: height,
|
||||
width: fontSize * 2.2,
|
||||
fontSize: fontSize,
|
||||
color: textColor,
|
||||
fontWeight: "800",
|
||||
}}
|
||||
>
|
||||
{weekdays.map((day, index) => (
|
||||
<motion.div
|
||||
key={day}
|
||||
className="absolute flex items-center justify-start font-extrabold"
|
||||
style={{
|
||||
y: useSpring((index - dayIndex) * height, {
|
||||
stiffness: 300,
|
||||
damping: 30,
|
||||
}),
|
||||
}}
|
||||
animate={{
|
||||
y: (index - dayIndex) * height,
|
||||
}}
|
||||
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
||||
>
|
||||
{day}
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function AnimatedDigit({ value, fontSize, textColor }) {
|
||||
const animatedValue = useSpring(value, { stiffness: 300, damping: 30 });
|
||||
|
||||
@@ -69,20 +112,21 @@ export function DayNightCycle({ selectedDate }) {
|
||||
return date.toDateString() === today.toDateString();
|
||||
};
|
||||
|
||||
// Get the day index (0 for Sunday, 1 for Monday, etc.) from the date
|
||||
const dayIndex = selectedDate.getDay();
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-3">
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="text-4xl font-extrabold">
|
||||
{selectedDate.toLocaleDateString("en-US", { weekday: "short" })}
|
||||
</div>
|
||||
{isToday(selectedDate) &&
|
||||
(isDay ? (
|
||||
<Sun className="h-7 w-7 text-yellow-500" />
|
||||
) : (
|
||||
<Moon className="h-7 w-7 text-blue-500" />
|
||||
))}
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="text-4xl font-extrabold flex items-center">
|
||||
<AnimatedWeekday dayIndex={dayIndex} fontSize={32} />
|
||||
</div>
|
||||
{isToday(selectedDate) &&
|
||||
(isDay ? (
|
||||
<Sun className="h-7 w-7 text-yellow-500" />
|
||||
) : (
|
||||
<Moon className="h-7 w-7 text-blue-500" />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -68,6 +68,46 @@ export function SettingsModal({
|
||||
background: "#FFFFFF",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "pastel-dream",
|
||||
name: "Pastel Dream",
|
||||
description: "Soft lavender & pink tones",
|
||||
preview: {
|
||||
primary: "#D67AD2",
|
||||
secondary: "#A2DCEF",
|
||||
background: "#F8F4FF",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "quantum-rose",
|
||||
name: "Quantum Rose",
|
||||
description: "Vibrant pink & teal fusion",
|
||||
preview: {
|
||||
primary: "#D93A7D",
|
||||
secondary: "#2DD8C6",
|
||||
background: "#FFF5FA",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "twitter",
|
||||
name: "Twitter",
|
||||
description: "Blues & clean contrast",
|
||||
preview: {
|
||||
primary: "#1DA1F2",
|
||||
secondary: "#F7F9F9",
|
||||
background: "#F5F8FA",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "amber-minimal",
|
||||
name: "Amber Minimal",
|
||||
description: "Clean amber & white minimalism",
|
||||
preview: {
|
||||
primary: "#F59E0B",
|
||||
secondary: "#E0E7FF",
|
||||
background: "#FFFFFF",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// Animation variants
|
||||
@@ -276,7 +316,7 @@ export function SettingsModal({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<div className="grid grid-cols-4 gap-2">
|
||||
{themes.map((themeData) => (
|
||||
<motion.button
|
||||
key={themeData.id}
|
||||
@@ -481,10 +521,10 @@ export function SettingsModal({
|
||||
>
|
||||
<div className="text-center space-y-3">
|
||||
<div className="text-lg font-extrabold text-primary">
|
||||
Prio Space V1.2.0
|
||||
Prio Space V1.3.0
|
||||
</div>
|
||||
<div className="text-sm font-bold text-gray-600 dark:text-gray-300 uppercase tracking-wider">
|
||||
Focus • Track • Share • Achieve
|
||||
Focus • Track • Achieve
|
||||
</div>
|
||||
|
||||
{/* vibecoded section */}
|
||||
|
||||
@@ -425,12 +425,14 @@ function TaskItem({
|
||||
}
|
||||
${isLastTask && (!hasSubtasks || !isExpanded) ? "border-b" : ""}`}
|
||||
style={{ paddingLeft: `${paddingLeft}px` }}
|
||||
onClick={(e) => onTaskClick(task, e)}
|
||||
whileHover={{ scale: 1.01 }}
|
||||
whileHover={{ scale: 1.0 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
<div className="flex items-center justify-between relative z-10 p-4">
|
||||
<div className="flex items-center gap-3 flex-1">
|
||||
<div className="flex items-center justify-between relative z-10">
|
||||
<div
|
||||
className="flex items-center gap-3 flex-1 p-4"
|
||||
onClick={(e) => onTaskClick(task, e)}
|
||||
>
|
||||
{/* Expand/Collapse button for main tasks with subtasks */}
|
||||
{hasSubtasks && !isSubtask && (
|
||||
<motion.button
|
||||
@@ -528,10 +530,10 @@ function TaskItem({
|
||||
{/* Completion Circle */}
|
||||
<motion.button
|
||||
onClick={(e) => onToggleTask(task.id, e)}
|
||||
className={`flex-shrink-0 w-6 h-6 rounded-full border-2 flex items-center justify-center transition-all duration-200 ${
|
||||
className={`flex-shrink-0 w-6 h-6 rounded-full border-2 flex items-center justify-center transition-all duration-200 mr-4 ${
|
||||
task.completed
|
||||
? "bg-primary border-primary"
|
||||
: "border-primary/30 hover:border-primary hover:bg-primary/10 border-dotted"
|
||||
: "border-primary/50 hover:border-primary hover:bg-primary/10 border-dotted"
|
||||
}`}
|
||||
whileHover={{ scale: 1.1 }}
|
||||
whileTap={{ scale: 0.9 }}
|
||||
|
||||
Reference in New Issue
Block a user