first commit
This commit is contained in:
12
src/app/Component/preview.jsx
Normal file
12
src/app/Component/preview.jsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import { useEffect } from "react"
|
||||
|
||||
export default function Preview({daySelected}){
|
||||
useEffect(()=>{
|
||||
fetch(`/api/days`)
|
||||
},[])
|
||||
return(
|
||||
<div className="preview">
|
||||
preview
|
||||
</div>
|
||||
)
|
||||
}
|
||||
31
src/app/Component/tracker.jsx
Normal file
31
src/app/Component/tracker.jsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { useEffect } from "react"
|
||||
|
||||
export default function Tracker({calendar,setDaySelected}){
|
||||
|
||||
useEffect(()=>{
|
||||
fetch(`/api/days`)
|
||||
},[])
|
||||
|
||||
const monthLine = Object.keys(calendar).map((month, monthIndex) =>
|
||||
<div key={month} className="month">
|
||||
<p>
|
||||
{month.charAt(0).toUpperCase() + month.slice(1)}
|
||||
</p>
|
||||
<div className="monthBlock">
|
||||
{[...Array(calendar[month])].map(
|
||||
(dayValue, dayIndex) => (
|
||||
<span onClick={()=>{setDaySelected(`${monthIndex+1}/${dayIndex+1}`)}} id={dayIndex} key={dayIndex} title={`${dayIndex+1} ${month}`} className="day"/>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
|
||||
return(
|
||||
<div className="Tracker">
|
||||
{monthLine}
|
||||
</div>
|
||||
)
|
||||
};
|
||||
66
src/app/Component/upload.jsx
Normal file
66
src/app/Component/upload.jsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { FileUploader } from "react-drag-drop-files";
|
||||
|
||||
const fileTypes = ["JPG", "PNG", "GIF"];
|
||||
|
||||
function DragDrop({setPreview ,file, setFile}) {
|
||||
|
||||
const handleChange = (file) => {
|
||||
setFile(file);
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
if(!file) return;
|
||||
|
||||
const objectUrl = URL.createObjectURL(file)
|
||||
setPreview(objectUrl)
|
||||
|
||||
// free memory when ever this component is unmounted
|
||||
return () => URL.revokeObjectURL(objectUrl)
|
||||
},[file])
|
||||
return (
|
||||
<FileUploader handleChange={handleChange} name="file" types={fileTypes} multiple={false}/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default function Upload({daySelected={daySelected}}){
|
||||
const [file, setFile] = useState(null);
|
||||
const [preview, setPreview] = useState(null);
|
||||
|
||||
function uploadFile(){
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
formData.append("date", daySelected)
|
||||
|
||||
fetch("/api/days", {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
}).then(() => {
|
||||
setFile(null);
|
||||
setPreview(null);
|
||||
});
|
||||
}
|
||||
|
||||
return(
|
||||
<div className="Upload">
|
||||
|
||||
<div className="preview">
|
||||
{preview ? <img src={preview} alt="preview" /> : null}
|
||||
</div>
|
||||
|
||||
<DragDrop setPreview={setPreview} file={file} setFile={setFile}/>
|
||||
|
||||
|
||||
<select type="select">
|
||||
<option value="gesture">Gesture</option>
|
||||
<option value="blender">Blender</option>
|
||||
</select>
|
||||
|
||||
<p onClick={()=>{
|
||||
uploadFile()
|
||||
}}>Upload</p>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
5
src/app/api/days/[id]/route.js
Normal file
5
src/app/api/days/[id]/route.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export async function GET(req){
|
||||
console.log(req)
|
||||
return Response.json({"message":"hello"})
|
||||
|
||||
}
|
||||
42
src/app/api/days/route.js
Normal file
42
src/app/api/days/route.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import {readdir, access, mkdir, writeFile } from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
export async function GET(req) {
|
||||
const dir = "./public/uploads";
|
||||
const entries = await readdir(dir, { withFileTypes: true });
|
||||
console.log(entries)
|
||||
|
||||
|
||||
return Response.json({"hello":"wesh"})
|
||||
}
|
||||
|
||||
export async function POST(req) {
|
||||
const formData = await req.formData();
|
||||
const date = formData.get('date');
|
||||
const file = formData.get('file');
|
||||
console.log(file)
|
||||
if (!file) {
|
||||
return new Response("No file uploaded", { status: 400 });
|
||||
}
|
||||
|
||||
const bytes = await file.arrayBuffer();
|
||||
const buffer = Buffer.from(bytes);
|
||||
|
||||
// if folder not created make one
|
||||
try{
|
||||
await access(`./public/uploads/${date}/`)
|
||||
}catch{
|
||||
await mkdir(`./public/uploads/${date}/`, {recursive:true})
|
||||
}
|
||||
|
||||
//get the number of files before uploading
|
||||
const files = await readdir(`./public/uploads/${date}/`);
|
||||
const nbFiles = (files.length);
|
||||
const fileName = `${nbFiles}.${path.extname(file.name).slice(1).toLowerCase()}`
|
||||
console.log(fileName);
|
||||
// Save file locally
|
||||
const pathName = `./public/uploads/${date}/${fileName}`;
|
||||
|
||||
await writeFile(pathName, buffer);
|
||||
return new Response("File uploaded successfully");
|
||||
}
|
||||
5
src/app/api/hello/route.js
Normal file
5
src/app/api/hello/route.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export async function GET () {
|
||||
const res = {"message":"hello"}
|
||||
return Response.json(res)
|
||||
|
||||
}
|
||||
@@ -1,66 +1,46 @@
|
||||
import Image from "next/image";
|
||||
import styles from "./page.module.css";
|
||||
'use client'
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import "./style.sass"
|
||||
import Preview from "./Component/preview";
|
||||
import Upload from "./Component/upload";
|
||||
import Tracker from "./Component/tracker";
|
||||
export default function Home() {
|
||||
|
||||
const calendar = {
|
||||
"january":31,
|
||||
"febuary":28,
|
||||
"march":29,
|
||||
"april":30,
|
||||
"may":31,
|
||||
"june":30,
|
||||
"july":31,
|
||||
"august":31,
|
||||
"september":30,
|
||||
"october":31,
|
||||
"november":30,
|
||||
"december":31,
|
||||
}
|
||||
|
||||
|
||||
const date = new Date();
|
||||
const [daySelected, setDaySelected] = useState(`${date.getMonth()}/${date.getDate()}`)
|
||||
|
||||
return (
|
||||
<div className={styles.page}>
|
||||
<main className={styles.main}>
|
||||
<Image
|
||||
className={styles.logo}
|
||||
src="/next.svg"
|
||||
alt="Next.js logo"
|
||||
width={100}
|
||||
height={20}
|
||||
priority
|
||||
/>
|
||||
<div className={styles.intro}>
|
||||
<h1>To get started, edit the page.js file.</h1>
|
||||
<p>
|
||||
Looking for a starting point or more instructions? Head over to{" "}
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Templates
|
||||
</a>{" "}
|
||||
or the{" "}
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Learning
|
||||
</a>{" "}
|
||||
center.
|
||||
</p>
|
||||
</div>
|
||||
<div className={styles.ctas}>
|
||||
<a
|
||||
className={styles.primary}
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
className={styles.logo}
|
||||
src="/vercel.svg"
|
||||
alt="Vercel logomark"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Deploy Now
|
||||
</a>
|
||||
<a
|
||||
className={styles.secondary}
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
<div className="Home">
|
||||
|
||||
<aside>
|
||||
<p>Link</p>
|
||||
</aside>
|
||||
|
||||
<main>
|
||||
|
||||
<h2>{daySelected}</h2>
|
||||
<Preview daySelected={daySelected}/>
|
||||
<Upload daySelected={daySelected}/>
|
||||
<Tracker calendar={calendar} setDaySelected={setDaySelected}/>
|
||||
</main>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
.page {
|
||||
--background: #fafafa;
|
||||
--foreground: #fff;
|
||||
|
||||
--text-primary: #000;
|
||||
--text-secondary: #666;
|
||||
|
||||
--button-primary-hover: #383838;
|
||||
--button-secondary-hover: #f2f2f2;
|
||||
--button-secondary-border: #ebebeb;
|
||||
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: var(--font-geist-sans);
|
||||
background-color: var(--background);
|
||||
}
|
||||
|
||||
.main {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
background-color: var(--foreground);
|
||||
padding: 120px 60px;
|
||||
}
|
||||
|
||||
.intro {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
text-align: left;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.intro h1 {
|
||||
max-width: 320px;
|
||||
font-size: 40px;
|
||||
font-weight: 600;
|
||||
line-height: 48px;
|
||||
letter-spacing: -2.4px;
|
||||
text-wrap: balance;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.intro p {
|
||||
max-width: 440px;
|
||||
font-size: 18px;
|
||||
line-height: 32px;
|
||||
text-wrap: balance;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.intro a {
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.ctas {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
max-width: 440px;
|
||||
gap: 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.ctas a {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
padding: 0 16px;
|
||||
border-radius: 128px;
|
||||
border: 1px solid transparent;
|
||||
transition: 0.2s;
|
||||
cursor: pointer;
|
||||
width: fit-content;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
a.primary {
|
||||
background: var(--text-primary);
|
||||
color: var(--background);
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
a.secondary {
|
||||
border-color: var(--button-secondary-border);
|
||||
}
|
||||
|
||||
/* Enable hover only on non-touch devices */
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
a.primary:hover {
|
||||
background: var(--button-primary-hover);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
a.secondary:hover {
|
||||
background: var(--button-secondary-hover);
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.main {
|
||||
padding: 48px 24px;
|
||||
}
|
||||
|
||||
.intro {
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.intro h1 {
|
||||
font-size: 32px;
|
||||
line-height: 40px;
|
||||
letter-spacing: -1.92px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.logo {
|
||||
filter: invert();
|
||||
}
|
||||
|
||||
.page {
|
||||
--background: #000;
|
||||
--foreground: #000;
|
||||
|
||||
--text-primary: #ededed;
|
||||
--text-secondary: #999;
|
||||
|
||||
--button-primary-hover: #ccc;
|
||||
--button-secondary-hover: #1a1a1a;
|
||||
--button-secondary-border: #1a1a1a;
|
||||
}
|
||||
}
|
||||
43
src/app/style.sass
Normal file
43
src/app/style.sass
Normal file
@@ -0,0 +1,43 @@
|
||||
.Home
|
||||
display: flex
|
||||
width: 100%
|
||||
padding:2%
|
||||
justify-content: space-between
|
||||
height: 100vh
|
||||
aside
|
||||
background: rebeccapurple
|
||||
width: 20%
|
||||
height: 100%
|
||||
main
|
||||
width: 79%
|
||||
height: 100%
|
||||
padding: 1%
|
||||
.Tracker
|
||||
.month
|
||||
display: flex
|
||||
flex-direction: row
|
||||
align-items: center
|
||||
gap: 5px
|
||||
p
|
||||
width: 8%
|
||||
.monthBlock
|
||||
display: flex
|
||||
gap: 5px
|
||||
width: 90%
|
||||
.day
|
||||
display: block
|
||||
width: 20px
|
||||
height: 10px
|
||||
background: green
|
||||
border-radius: 5px
|
||||
cursor: pointer
|
||||
.Upload
|
||||
display: flex
|
||||
gap: 5%
|
||||
align-items: center
|
||||
.preview
|
||||
height: 400px
|
||||
img
|
||||
height: 100%
|
||||
select
|
||||
height: 40px
|
||||
Reference in New Issue
Block a user