Spaces:
Build error
Build error
Add 17 files
Browse files- .huskyrc.json +5 -0
- .lintstagedrc.json +3 -0
- Dockerfile +57 -0
- README.md +11 -8
- package.json +25 -0
- src/components/Footer.tsx +11 -0
- src/components/Header.tsx +11 -0
- src/components/Layout.tsx +17 -0
- src/components/Task.tsx +12 -0
- src/components/TodoList.tsx +40 -0
- src/pages/api/addTask.ts +23 -0
- src/pages/api/tasks.ts +19 -0
- src/pages/index.tsx +13 -0
- src/public/index.html +13 -0
- src/public/styles.css +5 -0
- tsconfig.json +28 -0
.huskyrc.json
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"hooks": {
|
3 |
+
"pre-commit": "lint-staged"
|
4 |
+
}
|
5 |
+
}
|
.lintstagedrc.json
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"*.{js,jsx,ts,tsx}": "eslint --fix"
|
3 |
+
}
|
Dockerfile
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
FROM node:18-alpine AS base
|
3 |
+
|
4 |
+
# Install dependencies only when needed
|
5 |
+
FROM base AS deps
|
6 |
+
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
7 |
+
RUN apk add --no-cache libc6-compat
|
8 |
+
WORKDIR /app
|
9 |
+
|
10 |
+
# Install dependencies based on the preferred package manager
|
11 |
+
COPY package.json package-lock.json* ./
|
12 |
+
RUN npm install
|
13 |
+
|
14 |
+
# Uncomment the following lines if you want to use a secret at buildtime,
|
15 |
+
# for example to access your private npm packages
|
16 |
+
# RUN --mount=type=secret,id=HF_EXAMPLE_SECRET,mode=0444,required=true # $(cat /run/secrets/HF_EXAMPLE_SECRET)
|
17 |
+
|
18 |
+
# Rebuild the source code only when needed
|
19 |
+
FROM base AS builder
|
20 |
+
WORKDIR /app
|
21 |
+
COPY --from=deps /app/node_modules ./node_modules
|
22 |
+
COPY . .
|
23 |
+
|
24 |
+
# Next.js collects completely anonymous telemetry data about general usage.
|
25 |
+
# Learn more here: https://nextjs.org/telemetry
|
26 |
+
# Uncomment the following line in case you want to disable telemetry during the build.
|
27 |
+
# ENV NEXT_TELEMETRY_DISABLED 1
|
28 |
+
|
29 |
+
RUN npm run build
|
30 |
+
|
31 |
+
# Production image, copy all the files and run next
|
32 |
+
FROM base AS runner
|
33 |
+
WORKDIR /app
|
34 |
+
|
35 |
+
ENV NODE_ENV production
|
36 |
+
# Uncomment the following line in case you want to disable telemetry during runtime.
|
37 |
+
# ENV NEXT_TELEMETRY_DISABLED 1
|
38 |
+
|
39 |
+
RUN addgroup --system --gid 1001 nodejs
|
40 |
+
RUN adduser --system --uid 1001 nextjs
|
41 |
+
|
42 |
+
COPY --from=builder /app/public ./public
|
43 |
+
|
44 |
+
# Automatically leverage output traces to reduce image size
|
45 |
+
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
46 |
+
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
47 |
+
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
48 |
+
COPY --from=builder --chown=nextjs:nodejs /app/.next/cache ./.next/cache
|
49 |
+
# COPY --from=builder --chown=nextjs:nodejs /app/.next/cache/fetch-cache ./.next/cache/fetch-cache
|
50 |
+
|
51 |
+
USER nextjs
|
52 |
+
|
53 |
+
EXPOSE 3000
|
54 |
+
|
55 |
+
ENV PORT 3000
|
56 |
+
|
57 |
+
CMD ["node", "server.js"]
|
README.md
CHANGED
@@ -1,11 +1,14 @@
|
|
1 |
---
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
license: mit
|
9 |
---
|
10 |
|
11 |
-
|
|
|
|
|
|
|
|
|
|
1 |
---
|
2 |
+
license: apache-2.0
|
3 |
+
title: <APPNAME>
|
4 |
+
sdk: docker
|
5 |
+
emoji: π¨βπ»
|
6 |
+
colorFrom: yellow
|
7 |
+
colorTo: green
|
|
|
8 |
---
|
9 |
|
10 |
+
This is a simple todo list app using NextJS and Tailwind CSS.
|
11 |
+
|
12 |
+
## Getting Started
|
13 |
+
|
14 |
+
To get started, clone this repository and run
|
package.json
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "<APPNAME>",
|
3 |
+
"version": "1.0.0",
|
4 |
+
"description": "A simple todo list app using Next.js and Tailwind CSS",
|
5 |
+
"scripts": {
|
6 |
+
"dev": "next dev",
|
7 |
+
"build": "next build",
|
8 |
+
"start": "next start"
|
9 |
+
},
|
10 |
+
"dependencies": {
|
11 |
+
"@tailwindcss/typography": "2.2.1",
|
12 |
+
"@types/node": "17.0.22",
|
13 |
+
"@types/react": "18.2.15",
|
14 |
+
"@types/react-dom": "18.9.11",
|
15 |
+
"next": "12.0.1",
|
16 |
+
"react": "18.0.1",
|
17 |
+
"react-dom": "18.0.1",
|
18 |
+
"tailwindcss": "3.0.23",
|
19 |
+
"typescript": "5.1.6"
|
20 |
+
},
|
21 |
+
"devDependencies": {
|
22 |
+
"husky": "7.0.4",
|
23 |
+
"lint-staged": "12.1.5"
|
24 |
+
}
|
25 |
+
}
|
src/components/Footer.tsx
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React from 'react';
|
2 |
+
|
3 |
+
const Footer = () => {
|
4 |
+
return (
|
5 |
+
<footer className="bg-gray-200 py-4 text-center">
|
6 |
+
<p>© 2023 My Company</p>
|
7 |
+
</footer>
|
8 |
+
);
|
9 |
+
};
|
10 |
+
|
11 |
+
export default Footer;
|
src/components/Header.tsx
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React from 'react';
|
2 |
+
|
3 |
+
const Header = ({pageTitle}) => {
|
4 |
+
return (
|
5 |
+
<header className="bg-gray-200 py-4 text-center">
|
6 |
+
<h1 className="text-2xl">{pageTitle}</h1>
|
7 |
+
</header>
|
8 |
+
);
|
9 |
+
};
|
10 |
+
|
11 |
+
export default Header;
|
src/components/Layout.tsx
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React from 'react';
|
2 |
+
import Header from './Header';
|
3 |
+
import Footer from './Footer';
|
4 |
+
|
5 |
+
const Layout = ({pageTitle, children}) => {
|
6 |
+
return (
|
7 |
+
<section className="flex flex-col min-h-screen">
|
8 |
+
<Header pageTitle={pageTitle} />
|
9 |
+
<main className="flex-1">
|
10 |
+
{children}
|
11 |
+
</main>
|
12 |
+
<Footer />
|
13 |
+
</section>
|
14 |
+
);
|
15 |
+
};
|
16 |
+
|
17 |
+
export default Layout;
|
src/components/Task.tsx
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React from 'react';
|
2 |
+
|
3 |
+
const Task = ({task}) => {
|
4 |
+
return (
|
5 |
+
<li className="flex">
|
6 |
+
<input type="checkbox" />
|
7 |
+
{task}
|
8 |
+
</li>
|
9 |
+
);
|
10 |
+
};
|
11 |
+
|
12 |
+
export default Task;
|
src/components/TodoList.tsx
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React, {useState} from 'react';
|
2 |
+
import Task from '../components/Task';
|
3 |
+
|
4 |
+
const TodoList = () => {
|
5 |
+
const [tasks, setTasks] = useState([]);
|
6 |
+
|
7 |
+
const addTask = (task) => {
|
8 |
+
setTasks([...tasks, task]);
|
9 |
+
};
|
10 |
+
|
11 |
+
const handleKeyDown = (e) => {
|
12 |
+
if (e.key === 'Enter') {
|
13 |
+
addTask(e.target.value);
|
14 |
+
e.target.value = '';
|
15 |
+
}
|
16 |
+
};
|
17 |
+
|
18 |
+
return (
|
19 |
+
<section className="">
|
20 |
+
<h2 className="text-xl">Todo List</h2>
|
21 |
+
<div className="mt-4">
|
22 |
+
<input
|
23 |
+
type="text"
|
24 |
+
className="w-full h-full p-2"
|
25 |
+
placeholder="Add a task..."
|
26 |
+
onKeyDown={handleKeyDown}
|
27 |
+
/>
|
28 |
+
</div>
|
29 |
+
<ul className="mt-4">
|
30 |
+
{tasks.map((task, index) => (
|
31 |
+
<li key={index}>
|
32 |
+
<Task task={task} />
|
33 |
+
</li>
|
34 |
+
))}
|
35 |
+
</ul>
|
36 |
+
</section>
|
37 |
+
);
|
38 |
+
};
|
39 |
+
|
40 |
+
export default TodoList;
|
src/pages/api/addTask.ts
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { NextApiRequest, NextApiResponse } from 'next';
|
2 |
+
|
3 |
+
const handler = (req: NextApiRequest, res: NextApiResponse) => {
|
4 |
+
const task = {
|
5 |
+
title: req.body.tasks,
|
6 |
+
};
|
7 |
+
|
8 |
+
// Add task to API
|
9 |
+
fetch('https://api.example.com/tasks', {
|
10 |
+
method: 'POST',
|
11 |
+
body: JSON.stringify(task),
|
12 |
+
})
|
13 |
+
.then((response) => response.json())
|
14 |
+
.then((data) => {
|
15 |
+
res.json(data);
|
16 |
+
})
|
17 |
+
.catch((error) => {
|
18 |
+
console.error(error);
|
19 |
+
res.status(500).json({ message: 'Error adding task' });
|
20 |
+
});
|
21 |
+
};
|
22 |
+
|
23 |
+
export default handler;
|
src/pages/api/tasks.ts
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { NextApiRequest, NextApiResponse } from 'next';
|
2 |
+
|
3 |
+
const handler = (req: NextApiRequest, res: NextApiResponse) => {
|
4 |
+
const tasks = [];
|
5 |
+
|
6 |
+
// Fetch tasks from API
|
7 |
+
fetch('https://api.example.com/tasks')
|
8 |
+
.then((response) => response.json())
|
9 |
+
.then((data) => {
|
10 |
+
tasks = data;
|
11 |
+
res.json(tasks);
|
12 |
+
})
|
13 |
+
.catch((error) => {
|
14 |
+
console.error(error);
|
15 |
+
res.status(500).json({ message: 'Error fetching tasks' });
|
16 |
+
});
|
17 |
+
};
|
18 |
+
|
19 |
+
export default handler;
|
src/pages/index.tsx
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import React from 'react';
|
2 |
+
import Layout from '../components/Layout';
|
3 |
+
import TodoList from '../components/TodoList';
|
4 |
+
|
5 |
+
const HomePage = () => {
|
6 |
+
return (
|
7 |
+
<Layout pageTitle="Todo List">
|
8 |
+
<TodoList />
|
9 |
+
</Layout>
|
10 |
+
);
|
11 |
+
};
|
12 |
+
|
13 |
+
export default HomePage;
|
src/public/index.html
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Todo List</title>
|
7 |
+
<link rel="stylesheet" href="styles.css" />
|
8 |
+
</head>
|
9 |
+
<body>
|
10 |
+
<div id="root"></div>
|
11 |
+
<script defer src="bundle.js"></script>
|
12 |
+
</body>
|
13 |
+
</html>
|
src/public/styles.css
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@tailwind base;
|
2 |
+
@tailwind components;
|
3 |
+
@tailwind utilities;
|
4 |
+
|
5 |
+
/* Your custom CSS goes here */
|
tsconfig.json
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"compilerOptions": {
|
3 |
+
"target": "ES2022",
|
4 |
+
"lib": ["dom", "dom.iterable", "esnext"],
|
5 |
+
"allowJs": true,
|
6 |
+
"skipLibCheck": true,
|
7 |
+
"strict": true,
|
8 |
+
"forceConsistentCasingInFileNames": true,
|
9 |
+
"noEmit": true,
|
10 |
+
"esModuleInterop": true,
|
11 |
+
"module": "esnext",
|
12 |
+
"moduleResolution": "node",
|
13 |
+
"resolveJsonModule": true,
|
14 |
+
"isolatedModules": true,
|
15 |
+
"jsx": "preserve",
|
16 |
+
"incremental": true,
|
17 |
+
"plugins": [
|
18 |
+
{
|
19 |
+
"name": "next"
|
20 |
+
}
|
21 |
+
],
|
22 |
+
"paths": {
|
23 |
+
"@/*": ["./src/*"]
|
24 |
+
}
|
25 |
+
},
|
26 |
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
27 |
+
"exclude": ["node_modules"]
|
28 |
+
}
|