Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
898cacc
Update package.json
tildetilde May 20, 2025
ce2f67b
Merge pull request #1 from tildetilde/zustand-store
tildetilde May 20, 2025
2a870bc
Create js-project-todo.code-workspace
tildetilde May 20, 2025
990d36d
Initial sprint
tildetilde May 20, 2025
662b366
Merge pull request #2 from tildetilde/zustand-store
tildetilde May 20, 2025
ca474df
Improving fonts and use of styled components
tildetilde May 20, 2025
ed115cb
Update README.md
tildetilde May 20, 2025
acf47f0
Merge pull request #3 from tildetilde/improving-design
tildetilde May 20, 2025
62e65fa
Styled form using react select
tildetilde May 20, 2025
e4aa4bd
Merge pull request #4 from tildetilde/margins
tildetilde May 20, 2025
08942fa
Update package.json
tildetilde May 20, 2025
075b965
Update package.json
tildetilde May 20, 2025
0af44f2
hiding about
tildetilde May 20, 2025
df6db7b
Improved margins
tildetilde May 21, 2025
1abffdb
Removed tally
tildetilde May 21, 2025
9d457e8
Merge pull request #5 from tildetilde/todoitem-improvement
tildetilde May 21, 2025
148d5b2
Small tweeks
tildetilde May 21, 2025
cc75aa7
Merge pull request #6 from tildetilde/tilde-sprint-21
tildetilde May 21, 2025
c4bcdca
Installed react swipeable list
tildetilde May 22, 2025
f431aac
Merge pull request #7 from tildetilde/tilde-sprint-21
tildetilde May 22, 2025
0bffe43
Structure
tildetilde May 22, 2025
764e4f9
New name
tildetilde May 22, 2025
4f54676
Update README.md
tildetilde May 22, 2025
8a1c9dc
Merge branch 'main' into tilde-sprint-21
tildetilde May 22, 2025
5ab06c2
Merge pull request #8 from tildetilde/tilde-sprint-21
tildetilde May 22, 2025
51cb3dc
Update TodoList.jsx
tildetilde May 23, 2025
9d43397
Fixes
tildetilde May 26, 2025
445950a
Update README.md
tildetilde May 26, 2025
3c7859a
Update README.md
tildetilde May 26, 2025
d89f714
Update README.md
tildetilde May 26, 2025
057431a
Accessibility fixes
tildetilde May 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
# Todo
# (O)FÄRDIG
A minimalistic, modern todo app with a notebook feel

Check it out: https://nevercomplete.netlify.app/
21 changes: 15 additions & 6 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,24 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="./vite.svg" />
<link rel="icon" type="image/svg+xml" href="./listat.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Todo</title>
<meta
name="description"
content="A minimalistic, modern todo app with a notebook feel"
/>

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Libre+Baskerville:ital@0;1&family=Zen+Kaku+Gothic+New:wght@300;400;500;700;900&display=swap"
rel="stylesheet"
/>

<title>(O)FÄRDIG</title>
</head>
<body>
<div id="root"></div>
<script
type="module"
src="./src/main.jsx">
</script>
<script type="module" src="./src/main.jsx"></script>
</body>
</html>
10 changes: 10 additions & 0 deletions js-project-todo.code-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"folders": [
{
"path": "."
},
{
"path": "."
}
]
}
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"
}
}
269 changes: 269 additions & 0 deletions public/listat.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion public/vite.svg

This file was deleted.

62 changes: 59 additions & 3 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<h1>React Boilerplate</h1>
)
<ThemeProvider theme={darkMode ? darkTheme : lightTheme}>
<GlobalStyle />
<AppContainer>
<div>
<p
style={{
fontSize: "0.9rem",
marginBottom: "1rem",
padding: "0 2rem",
fontStyle: "italic",
fontFamily: '"Zen Kaku Gothic New", sans-serif',
}}
>
You will never be complete, but your tasks can be.
</p>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Title>(O)FÄRDIG</Title>
<ThemeToggle darkMode={darkMode} toggleDarkMode={toggleDarkMode} />
</div>
</div>

<NotebookContainer>
<TodoForm />
<TodoStats />
{tasks.length > 0 ? <TodoList /> : <EmptyState />}
</NotebookContainer>
{/* <AboutPage /> */}
</AppContainer>
</ThemeProvider>
);
}

export default App;
38 changes: 38 additions & 0 deletions src/GlobalStyle.jsx
Original file line number Diff line number Diff line change
@@ -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;
49 changes: 49 additions & 0 deletions src/LayoutStyles.jsx
Original file line number Diff line number Diff line change
@@ -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;
}
`;
42 changes: 42 additions & 0 deletions src/components/EmptyState.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<EmptyContainer>
<EmptyTitle>No tasks yet</EmptyTitle>
<EmptyText>Add your first task using the form above.</EmptyText>
</EmptyContainer>
);
};

export default EmptyState;
38 changes: 38 additions & 0 deletions src/components/ThemeToggle.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<ToggleButton
onClick={toggleDarkMode}
aria-label={darkMode ? "Switch to light mode" : "Switch to dark mode"}
>
{darkMode ? "Light" : "Dark"}
</ToggleButton>
);
};

export default ThemeToggle;
Loading