diff --git a/README.md b/README.md
index d1c68b5..fa18b34 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,4 @@
-# Todo
\ No newline at end of file
+# (O)FÄRDIG
+A minimalistic, modern todo app with a notebook feel
+
+Check it out: https://nevercomplete.netlify.app/
diff --git a/index.html b/index.html
index f7ac4e4..9542073 100644
--- a/index.html
+++ b/index.html
@@ -2,15 +2,24 @@
-
+
- Todo
+
+
+
+
+
+
+ (O)FÄRDIG
-
+
diff --git a/js-project-todo.code-workspace b/js-project-todo.code-workspace
new file mode 100644
index 0000000..40fe023
--- /dev/null
+++ b/js-project-todo.code-workspace
@@ -0,0 +1,10 @@
+{
+ "folders": [
+ {
+ "path": "."
+ },
+ {
+ "path": "."
+ }
+ ]
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index caf6289..c3e3a2f 100644
--- a/package.json
+++ b/package.json
@@ -10,8 +10,12 @@
"preview": "vite preview"
},
"dependencies": {
+ "date-fns": "^4.1.0",
"react": "^19.0.0",
- "react-dom": "^19.0.0"
+ "react-dom": "^19.0.0",
+ "react-select": "^5.10.1",
+ "styled-components": "^6.1.18",
+ "zustand": "^5.0.4"
},
"devDependencies": {
"@eslint/js": "^9.21.0",
@@ -22,6 +26,6 @@
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^15.15.0",
- "vite": "^6.2.0"
+ "vite": "^6.3.5"
}
}
diff --git a/public/listat.svg b/public/listat.svg
new file mode 100644
index 0000000..0edeff8
--- /dev/null
+++ b/public/listat.svg
@@ -0,0 +1,269 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/vite.svg b/public/vite.svg
deleted file mode 100644
index e7b8dfb..0000000
--- a/public/vite.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/App.jsx b/src/App.jsx
index 5427540..14b6e42 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,5 +1,61 @@
-export const App = () => {
+"use client";
+
+import { useEffect } from "react";
+import { ThemeProvider } from "styled-components";
+import { AppContainer, NotebookContainer, Header, Title } from "./LayoutStyles";
+import { useStore } from "./store";
+import GlobalStyle from "./GlobalStyle";
+import TodoList from "./components/TodoList";
+import TodoForm from "./components/TodoForm";
+import TodoStats from "./components/TodoStats";
+import EmptyState from "./components/EmptyState";
+import ThemeToggle from "./components/ThemeToggle";
+import { lightTheme, darkTheme } from "./theme";
+
+function App() {
+ const { tasks, darkMode, toggleDarkMode, loadTasks } = useStore();
+
+ useEffect(() => {
+ loadTasks();
+ }, [loadTasks]);
+
return (
- React Boilerplate
- )
+
+
+
+
+
+ You will never be complete, but your tasks can be.
+
+
+
(O)FÄRDIG
+
+
+
+
+
+
+
+ {tasks.length > 0 ? : }
+
+ {/* */}
+
+
+ );
}
+
+export default App;
diff --git a/src/GlobalStyle.jsx b/src/GlobalStyle.jsx
new file mode 100644
index 0000000..2daf691
--- /dev/null
+++ b/src/GlobalStyle.jsx
@@ -0,0 +1,38 @@
+import { createGlobalStyle } from "styled-components";
+
+const GlobalStyle = createGlobalStyle`
+ * {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ }
+
+
+ html, body {
+ margin: 0;
+ padding: 0;
+ overflow-x: hidden;
+ }
+
+ body {
+ font-family: 'Inter', sans-serif;
+ background-color: ${(props) => props.theme.background};
+ color: ${(props) => props.theme.text};
+ line-height: 1.6;
+ transition: all 0.3s ease;
+ }
+
+ h1, h2, h3 {
+ font-family: 'Zen Kaku Gothic New', sans-serif;
+}
+
+ button, input, select {
+ font-family: 'Inter', sans-serif;
+ }
+
+ small, em {
+ font-family: 'Libre Baskerville', serif;
+}
+`;
+
+export default GlobalStyle;
diff --git a/src/LayoutStyles.jsx b/src/LayoutStyles.jsx
new file mode 100644
index 0000000..ff3eb70
--- /dev/null
+++ b/src/LayoutStyles.jsx
@@ -0,0 +1,49 @@
+import styled from "styled-components";
+
+export const AppContainer = styled.div`
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 2rem 1rem;
+ box-sizing: border-box;
+
+ @media (max-width: 600px) {
+ padding: 1rem;
+ }
+`;
+
+export const NotebookContainer = styled.div`
+ background-color: ${(props) => props.theme.paper};
+ padding: 1rem 2rem;
+ position: relative;
+ box-sizing: border-box;
+`;
+
+export const Header = styled.header`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 4rem;
+ padding-bottom: 1rem;
+`;
+
+export const Title = styled.h1`
+ font-size: 8rem;
+ padding: 0 1.5rem;
+ font-weight: 700;
+ color: ${(props) => props.theme.title};
+ letter-spacing: -2px;
+ word-break: break-word;
+ max-width: 100%;
+
+ @media (max-width: 768px) {
+ font-size: 4rem;
+ }
+
+ @media (max-width: 480px) {
+ font-size: 3rem;
+ }
+
+ @media (max-width: 350px) {
+ font-size: 2rem;
+ }
+`;
diff --git a/src/components/EmptyState.jsx b/src/components/EmptyState.jsx
new file mode 100644
index 0000000..0e09167
--- /dev/null
+++ b/src/components/EmptyState.jsx
@@ -0,0 +1,42 @@
+import styled from "styled-components";
+
+const EmptyContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 5rem 1rem;
+ text-align: center;
+`;
+
+const EmptyIllustration = styled.div`
+ font-size: 3rem;
+ margin-bottom: 1rem;
+ color: ${(props) => props.theme.accent};
+ opacity: 0.7;
+`;
+
+const EmptyTitle = styled.h2`
+ font-size: 2rem;
+ font-weight: 500;
+ margin-bottom: 1rem;
+ color: ${(props) => props.theme.title};
+`;
+
+const EmptyText = styled.p`
+ color: ${(props) => props.theme.text};
+ max-width: 400px;
+ margin: 0 auto;
+ font-size: 1rem;
+`;
+
+const EmptyState = () => {
+ return (
+
+ No tasks yet
+ Add your first task using the form above.
+
+ );
+};
+
+export default EmptyState;
diff --git a/src/components/ThemeToggle.jsx b/src/components/ThemeToggle.jsx
new file mode 100644
index 0000000..8271ec8
--- /dev/null
+++ b/src/components/ThemeToggle.jsx
@@ -0,0 +1,38 @@
+"use client";
+
+import styled from "styled-components";
+
+const ToggleButton = styled.button`
+ background: none;
+ border: none;
+ cursor: pointer;
+ font-size: 1rem;
+ color: ${(props) => props.theme.text};
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: opacity 0.3s ease;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+
+ &:hover {
+ opacity: 0.7;
+ }
+
+ @media (max-width: 350px) {
+ font-size: 0.75rem;
+ }
+`;
+
+const ThemeToggle = ({ darkMode, toggleDarkMode }) => {
+ return (
+
+ {darkMode ? "Light" : "Dark"}
+
+ );
+};
+
+export default ThemeToggle;
diff --git a/src/components/TodoForm.jsx b/src/components/TodoForm.jsx
new file mode 100644
index 0000000..cfeefdd
--- /dev/null
+++ b/src/components/TodoForm.jsx
@@ -0,0 +1,189 @@
+"use client";
+
+import { useState } from "react";
+import styled, { useTheme } from "styled-components";
+import { useStore } from "../store";
+import Select from "react-select";
+
+const FormContainer = styled.form`
+ margin: 2rem 0 3rem;
+ display: flex;
+ gap: 1rem;
+
+ @media (max-width: 768px) {
+ flex-direction: column;
+ }
+`;
+
+const InputRow = styled.div`
+ display: flex;
+ gap: 1rem;
+ flex: 1;
+
+ @media (max-width: 768px) {
+ flex-direction: column;
+ }
+`;
+
+const Input = styled.input`
+ flex: 1;
+ padding: 0.75rem 0;
+ font-size: 1rem;
+ border: none;
+ border-bottom: 1px solid ${(props) => props.theme.border};
+ background-color: transparent;
+ color: ${(props) => props.theme.text};
+
+ &:focus {
+ outline: none;
+ border-color: ${(props) => props.theme.accent};
+ }
+
+ &::placeholder {
+ color: ${(props) => props.theme.completed};
+ }
+`;
+
+const Button = styled.button`
+ padding: 0.75rem 1.5rem;
+ font-size: 0.9rem;
+ background-color: transparent;
+ color: ${(props) => props.theme.text};
+ border: 1px solid ${(props) => props.theme.accent};
+ cursor: pointer;
+ transition: all 0.2s;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+
+ &:hover {
+ background-color: ${(props) => props.theme.accent};
+ color: ${(props) => props.theme.paper};
+ }
+
+ &:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+`;
+
+const CompleteAllButton = styled(Button)`
+ background-color: transparent;
+ border: 1px solid ${(props) => props.theme.accent};
+
+ &:hover {
+ background-color: ${(props) => props.theme.accent};
+ color: ${(props) => props.theme.paper};
+ }
+`;
+
+const TodoForm = () => {
+ const { addTask, completeAllTasks, categories } = useStore();
+ const [text, setText] = useState("");
+ const [category, setCategory] = useState("Personal");
+ const [dueDate, setDueDate] = useState("");
+ const theme = useTheme();
+
+ const categoryOptions = categories.map((cat) => ({
+ value: cat,
+ label: cat,
+ }));
+
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ if (text.trim()) {
+ addTask(text.trim(), category, dueDate || null);
+ setText("");
+ setDueDate("");
+ }
+ };
+
+ const customStyles = {
+ control: (base) => ({
+ ...base,
+ backgroundColor: "transparent",
+ border: "none",
+ borderBottom: `1px solid ${theme.border}`,
+ borderRadius: 0,
+ boxShadow: "none",
+ fontSize: "1rem",
+ color: theme.text,
+ fontFamily: "Zen Kaku Gothic New, sans-serif",
+ padding: "0.5rem 0",
+ cursor: "pointer",
+ }),
+ menu: (base) => ({
+ ...base,
+ backgroundColor: theme.paper,
+ border: `1px solid ${theme.border}`,
+ borderRadius: 0,
+ boxShadow: "none",
+ fontFamily: "Zen Kaku Gothic New, sans-serif",
+ }),
+ option: (base, { isFocused, isSelected }) => ({
+ ...base,
+ backgroundColor: isSelected
+ ? theme.text
+ : isFocused
+ ? theme.completed
+ : "transparent",
+ color: isSelected ? theme.paper : theme.text,
+ cursor: "pointer",
+ fontWeight: isSelected ? "600" : "400",
+ padding: "0.5rem 1rem",
+ }),
+ singleValue: (base) => ({
+ ...base,
+ color: theme.text,
+ }),
+ placeholder: (base) => ({
+ ...base,
+ color: theme.completed,
+ }),
+ indicatorSeparator: () => ({
+ display: "none",
+ }),
+ };
+
+ return (
+
+
+ setText(e.target.value)}
+ aria-label="Task description"
+ />
+
+
+ setCategory(selected.value)}
+ styles={customStyles}
+ aria-label="Task category"
+ />
+
+
+
+
+ setDueDate(e.target.value)}
+ aria-label="Due date"
+ />
+
+
+ Add Task
+
+
+
+ Complete All
+
+
+
+ );
+};
+
+export default TodoForm;
diff --git a/src/components/TodoItem.jsx b/src/components/TodoItem.jsx
new file mode 100644
index 0000000..1bdf28e
--- /dev/null
+++ b/src/components/TodoItem.jsx
@@ -0,0 +1,154 @@
+"use client";
+
+import { useState } from "react";
+import styled, { css, keyframes } from "styled-components";
+import { useStore } from "../store";
+import { format } from "date-fns";
+
+const fadeIn = keyframes`
+ from { opacity: 0; transform: translateY(10px); }
+ to { opacity: 1; transform: translateY(0); }
+`;
+
+const ItemContainer = styled.li`
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 1.5rem 0;
+ border-bottom: 1px solid ${(props) => props.theme.border};
+ animation: ${fadeIn} 0.3s ease;
+ position: relative;
+`;
+
+const Checkbox = styled.div`
+ width: 18px;
+ height: 18px;
+ border: 1px solid ${(props) => props.theme.accent};
+ margin-right: 12px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+
+ ${(props) =>
+ props.checked &&
+ css`
+ background-color: ${(props) => props.theme.accent};
+
+ &::after {
+ content: "✓";
+ color: ${(props) => props.theme.paper};
+ font-size: 12px;
+ }
+ `}
+`;
+
+const ContentContainer = styled.div`
+ flex: 1;
+`;
+
+const TaskText = styled.p`
+ font-size: 2rem;
+ font-weight: 600;
+ margin-bottom: 0.5rem;
+ position: relative;
+
+ ${(props) =>
+ props.$completed &&
+ css`
+ color: ${(props) => props.theme.completed};
+ text-decoration: line-through;
+ `}
+`;
+
+const TaskMeta = styled.div`
+ display: flex;
+ font-size: 0.85rem;
+ color: ${(props) => props.theme.completed};
+ flex-wrap: wrap;
+ gap: 12px;
+`;
+
+const TaskDate = styled.span`
+ display: inline-block;
+ color: ${(props) => props.theme.categoryText};
+`;
+
+const TaskDueDate = styled.span`
+ display: inline-block;
+ color: ${(props) =>
+ props.$overdue ? props.theme.categoryText : props.theme.completed};
+ font-weight: ${(props) => (props.$overdue ? "bold" : "normal")};
+`;
+
+const TaskCategory = styled.span`
+ display: inline-block;
+ color: ${(props) => props.theme.categoryText};
+ font-size: 0.8rem;
+ font-weight: 500;
+`;
+
+const DeleteButton = styled.button`
+ background: none;
+ border: none;
+ color: ${(props) => props.theme.completed};
+ cursor: pointer;
+ font-size: 1.2rem;
+ opacity: 0.6;
+ transition: opacity 0.2s;
+ margin-left: 8px;
+
+ &:hover {
+ opacity: 1;
+ }
+`;
+
+const TodoItem = ({ task }) => {
+ const { toggleTask, removeTask, getFormattedDate, isTaskOverdue } =
+ useStore();
+ const [showDelete, setShowDelete] = useState(false);
+
+ const handleToggle = () => {
+ toggleTask(task.id);
+ };
+
+ const overdue = task.dueDate && isTaskOverdue(task);
+
+ return (
+ setShowDelete(true)}
+ onMouseLeave={() => setShowDelete(false)}
+ >
+
+
+
+ {task.text}
+
+
+ Created: {getFormattedDate(task.createdAt)}
+
+ {task.dueDate && (
+
+ Due: {format(new Date(task.dueDate), "MMM d, yyyy")}
+ {overdue && " (overdue)"}
+
+ )}
+
+ {task.category}
+
+
+
+ {showDelete && (
+ removeTask(task.id)}
+ aria-label="Delete task"
+ >
+ ×
+
+ )}
+
+ );
+};
+
+export default TodoItem;
diff --git a/src/components/TodoList.jsx b/src/components/TodoList.jsx
new file mode 100644
index 0000000..b7df6ca
--- /dev/null
+++ b/src/components/TodoList.jsx
@@ -0,0 +1,53 @@
+import styled from "styled-components";
+import { useStore } from "../store";
+import TodoItem from "./TodoItem";
+
+const ListContainer = styled.ul`
+ list-style: none;
+ margin: 2rem 0;
+`;
+
+const CategorySection = styled.div`
+ margin-bottom: 3rem;
+`;
+
+const CategoryTitle = styled.h2`
+ font-size: 1.2rem;
+ font-weight: 500;
+ margin-bottom: 1rem;
+ color: ${(props) => props.theme.title};
+ text-transform: uppercase;
+ letter-spacing: 1px;
+`;
+
+const TodoList = () => {
+ const { tasks, categories } = useStore();
+
+ // Group tasks by category
+ const tasksByCategory = categories.reduce((acc, category) => {
+ const categoryTasks = tasks
+ .filter((task) => task.category === category)
+ .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); // nyast först
+ if (categoryTasks.length > 0) {
+ acc[category] = categoryTasks;
+ }
+ return acc;
+ }, {});
+
+ return (
+ <>
+ {Object.entries(tasksByCategory).map(([category, categoryTasks]) => (
+
+ {category}
+
+ {categoryTasks.map((task) => (
+
+ ))}
+
+
+ ))}
+ >
+ );
+};
+
+export default TodoList;
diff --git a/src/components/TodoStats.jsx b/src/components/TodoStats.jsx
new file mode 100644
index 0000000..fb2a246
--- /dev/null
+++ b/src/components/TodoStats.jsx
@@ -0,0 +1,54 @@
+import styled from "styled-components";
+import { useStore } from "../store";
+
+const StatsContainer = styled.div`
+ display: flex;
+ justify-content: space-between;
+ padding: 1rem 0;
+ font-size: 0.9rem;
+ color: ${(props) => props.theme.text};
+ border-top: 1px solid ${(props) => props.theme.border};
+ border-bottom: 1px solid ${(props) => props.theme.border};
+ margin: 2rem 0;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+
+ @media (max-width: 600px) {
+ flex-direction: column;
+ gap: 0.5rem;
+ }
+`;
+
+const StatItem = styled.div`
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+`;
+
+const StatValue = styled.span`
+ font-weight: 500;
+ color: ${(props) => props.theme.accent};
+`;
+
+const TodoStats = () => {
+ const { getUncompletedCount, getCompletedCount, getTotalCount } = useStore();
+
+ return (
+
+
+ Tasks:
+ {getTotalCount()}
+
+
+ Completed:
+ {getCompletedCount()}
+
+
+ Uncompleted:
+ {getUncompletedCount()}
+
+
+ );
+};
+
+export default TodoStats;
diff --git a/src/index.css b/src/index.css
deleted file mode 100644
index f7c0aef..0000000
--- a/src/index.css
+++ /dev/null
@@ -1,3 +0,0 @@
-:root {
- font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
-}
diff --git a/src/js-project-todo.code-workspace b/src/js-project-todo.code-workspace
new file mode 100644
index 0000000..1d122d3
--- /dev/null
+++ b/src/js-project-todo.code-workspace
@@ -0,0 +1,10 @@
+{
+ "folders": [
+ {
+ "path": ".."
+ },
+ {
+ "path": ".."
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/main.jsx b/src/main.jsx
index 1b8ffe9..0d1758a 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -1,12 +1,9 @@
-import React from 'react'
-import ReactDOM from 'react-dom/client'
+import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App";
-import { App } from './App.jsx'
-
-import './index.css'
-
-ReactDOM.createRoot(document.getElementById('root')).render(
+ReactDOM.createRoot(document.getElementById("root")).render(
-)
+);
diff --git a/src/store.js b/src/store.js
new file mode 100644
index 0000000..d57f5ed
--- /dev/null
+++ b/src/store.js
@@ -0,0 +1,98 @@
+import { create } from "zustand";
+import { persist } from "zustand/middleware";
+import { format } from "date-fns";
+
+const useStore = create(
+ persist(
+ (set, get) => ({
+ tasks: [],
+ darkMode: false,
+ categories: ["Personal", "Relationships", "Work", "Home"],
+
+ // Load tasks from localStorage
+ loadTasks: () => {
+ // This is handled by the persist middleware
+ },
+
+ // Add a new task
+ addTask: (text, category = "Personal", dueDate = null) => {
+ const newTask = {
+ id: Date.now().toString(),
+ text,
+ completed: false,
+ createdAt: new Date().toISOString(),
+ category,
+ dueDate: dueDate ? new Date(dueDate).toISOString() : null,
+ };
+
+ set((state) => ({
+ tasks: [...state.tasks, newTask],
+ }));
+ },
+
+ // Toggle task completion
+ toggleTask: (id) => {
+ set((state) => ({
+ tasks: state.tasks.map((task) =>
+ task.id === id ? { ...task, completed: !task.completed } : task
+ ),
+ }));
+ },
+
+ // Remove a task
+ removeTask: (id) => {
+ set((state) => ({
+ tasks: state.tasks.filter((task) => task.id !== id),
+ }));
+ },
+
+ // Complete all tasks
+ completeAllTasks: () => {
+ set((state) => ({
+ tasks: state.tasks.map((task) => ({ ...task, completed: true })),
+ }));
+ },
+
+ // Toggle dark mode
+ toggleDarkMode: () => {
+ set((state) => ({ darkMode: !state.darkMode }));
+ },
+
+ // Get formatted date
+ getFormattedDate: (dateString) => {
+ return format(new Date(dateString), "MMM d, yyyy h:mm a");
+ },
+
+ // Check if task is overdue
+ isTaskOverdue: (task) => {
+ if (!task.dueDate || task.completed) return false;
+ return new Date(task.dueDate) < new Date();
+ },
+
+ // Get tasks by category
+ getTasksByCategory: (category) => {
+ return get().tasks.filter((task) => task.category === category);
+ },
+
+ // Get uncompleted tasks count
+ getUncompletedCount: () => {
+ return get().tasks.filter((task) => !task.completed).length;
+ },
+
+ // Get completed tasks count
+ getCompletedCount: () => {
+ return get().tasks.filter((task) => task.completed).length;
+ },
+
+ // Get total tasks count
+ getTotalCount: () => {
+ return get().tasks.length;
+ },
+ }),
+ {
+ name: "notebook-todo-storage",
+ }
+ )
+);
+
+export { useStore };
diff --git a/src/theme.js b/src/theme.js
new file mode 100644
index 0000000..94eaf50
--- /dev/null
+++ b/src/theme.js
@@ -0,0 +1,55 @@
+export const lightTheme = {
+ background: "#f2f2f0",
+ paper: "#f8f8f6",
+ text: "#000000",
+ title: "#000000",
+ accent: "#000000",
+ border: "#d0d0d0",
+ completed: "#333333",
+ margin: "#e0e0e0",
+ buttonBg: "#f0f0f0",
+ buttonText: "#000000",
+ buttonHover: "#e0e0e0",
+ paperLines: "none",
+ overdue: "#000000",
+ categoryBg: "#f0f0f0",
+ categoryText: "#333333",
+ select: {
+ background: "#f8f8f6",
+ border: "#d0d0d0",
+ text: "#000000",
+ placeholder: "#888888",
+ optionBg: "#f5f5f3",
+ optionHover: "#e0e0e0",
+ optionSelected: "#000000",
+ optionSelectedText: "#ffffff",
+ },
+};
+
+export const darkTheme = {
+ background: "#1a1a1a",
+ paper: "#222222",
+ text: "#f0f0f0",
+ title: "#ffffff",
+ accent: "#ffffff",
+ border: "#444444",
+ completed: "#aaaaaa",
+ margin: "#444444",
+ buttonBg: "#333333",
+ buttonText: "#f0f0f0",
+ buttonHover: "#444444",
+ paperLines: "none",
+ overdue: "#dddddd",
+ categoryBg: "#333333",
+ categoryText: "#eeeeee",
+ select: {
+ background: "#222222",
+ border: "#555555",
+ text: "#f0f0f0",
+ placeholder: "#888888",
+ optionBg: "#1c1c1c",
+ optionHover: "#444444",
+ optionSelected: "#ffffff",
+ optionSelectedText: "#000000",
+ },
+};
diff --git a/vite.config.js b/vite.config.js
index ba24244..1ff0da0 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,7 +1,7 @@
-import react from '@vitejs/plugin-react'
-import { defineConfig } from 'vite'
+import react from "@vitejs/plugin-react";
+import { defineConfig } from "vite";
// https://vitejs.dev/config/
export default defineConfig({
- plugins: [react()]
-})
+ plugins: [react()],
+});