feat: middle save

This commit is contained in:
Project_IO 2025-03-15 14:06:23 +09:00
parent d9280bdead
commit a2f00ac83e
10 changed files with 303 additions and 84 deletions

View file

@ -5,6 +5,7 @@
"name": "kuma-archive", "name": "kuma-archive",
"dependencies": { "dependencies": {
"bootstrap": "^5.3.3", "bootstrap": "^5.3.3",
"lucide-react": "^0.482.0",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-router": "^7.3.0", "react-router": "^7.3.0",
@ -359,6 +360,8 @@
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
"lucide-react": ["lucide-react@0.482.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-XM8PzHzSrg8ATmmO+fzf+JyYlVVdQnJjuyLDj2p4V2zEtcKeBNAqAoJIGFv1x2HSBa7kT8gpYUxwdQ0g7nypfw=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],

View file

@ -4,17 +4,18 @@
"version": "0.0.0", "version": "0.0.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "build:view": "tsc -b && vite build",
"dev:server": "go run ./app.go daemon -d --api-only",
"dev:all": "bun run build && go run ./app.go daemon -d",
"build": "tsc -b && vite build",
"build:server": "go build -o kuma-archive", "build:server": "go build -o kuma-archive",
"build:all": "bun run build && bun run build-server", "build": "bun run build:view && bun run build:server",
"dev:view": "vite",
"dev:server": "go run ./app.go daemon -d --api-only",
"dev": "bun run build:view && go run ./app.go daemon -d",
"lint": "eslint .", "lint": "eslint .",
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"bootstrap": "^5.3.3", "bootstrap": "^5.3.3",
"lucide-react": "^0.482.0",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-router": "^7.3.0", "react-router": "^7.3.0",

View file

@ -0,0 +1 @@
:root{font-family:system-ui,Avenir,Helvetica,Arial,sans-serif;line-height:1.5;font-weight:400;color-scheme:light dark;color:#ffffffde;background-color:#242424;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{font-weight:500;color:#646cff;text-decoration:inherit}a:hover{color:#535bf2}body{margin:0;display:flex;place-items:center;min-width:320px;min-height:100vh}h1{font-size:3.2em;line-height:1.1}button{border-radius:8px;border:1px solid transparent;padding:.6em 1.2em;font-size:1em;font-weight:500;font-family:inherit;background-color:#1a1a1a;cursor:pointer;transition:border-color .25s}button:hover{border-color:#646cff}button:focus,button:focus-visible{outline:4px auto -webkit-focus-ring-color}@media (prefers-color-scheme: light){:root{color:#213547;background-color:#fff}a:hover{color:#747bff}button{background-color:#f9f9f9}}#root{max-width:1280px;margin:0 auto;padding:2rem;text-align:center}.logo{height:6em;padding:1.5em;will-change:filter;transition:filter .3s}.logo:hover{filter:drop-shadow(0 0 2em rgba(100,108,255,.6666666667))}.logo.react:hover{filter:drop-shadow(0 0 2em rgba(97,218,251,.6666666667))}@keyframes logo-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@media (prefers-reduced-motion: no-preference){a:nth-of-type(2) .logo{animation:logo-spin infinite 20s linear}}.card{padding:2em}.read-the-docs{color:#888}

File diff suppressed because one or more lines are too long

13
public/index.html Normal file
View file

@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Kuma Archive</title>
<script type="module" crossorigin src="/assets/index-T1mLj9f8.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-EHS3EQtg.css">
</head>
<body>
<div id="root"></div>
</body>
</html>

View file

@ -0,0 +1,28 @@
.ka-view {
width: 100%;
height: 100%;
}
.ka-nav {
width: 100%;
height: 50px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
.title {
display: flex;
align-items: center;
flex-direction: row;
img {
width: 30px;
height: 30px;
}
.title-content {
margin: 0 0.5rem;
}
}
}

View file

@ -1,7 +1,10 @@
import { BrowserRouter, Route, Routes } from "react-router"; import { BrowserRouter, Route, Routes, useLocation } from "react-router";
import Dashboard from "./components/dashboard"; import { usePath } from "./store/path";
import { useEffect, useState } from "react";
import "./App.scss"; import "./App.scss";
import kuma from "./assets/kuma.png";
import { Menu } from "lucide-react";
function App() { function App() {
return ( return (
@ -13,4 +16,44 @@ function App() {
); );
} }
function Dashboard() {
const path = usePath();
const location = useLocation();
const [load, setLoad] = useState(false);
useEffect(() => {
if (!load) {
path.update(location.pathname.substring(1, location.pathname.length));
setLoad(true);
}
const id = setInterval(() => {
path.update(location.pathname.substring(1, location.pathname.length));
}, 5000);
return () => clearInterval(id);
}, [load, path, location]);
return (
<main className="container-md ka-view">
<Header />
</main>
);
}
function Header() {
return (
<nav className="ka-nav">
<div className="title">
<img src={kuma} alt="" />
<h4 className="title-content">Kuma Archive</h4>
</div>
<button>
<Menu />
</button>
</nav>
);
}
export default App; export default App;

View file

@ -1,31 +0,0 @@
import { useEffect, useState } from "react";
import Directory from "../directory";
import { usePath } from "../../store/path";
import { useLocation } from "react-router";
import "./dashboard.scss";
function Dashboard() {
const path = usePath();
const location = useLocation();
const [load, setLoad] = useState(false);
useEffect(() => {
if (!load) {
path.update(location.pathname.substring(1, location.pathname.length));
setLoad(true);
}
const id = setInterval(() => {
path.update(location.pathname.substring(1, location.pathname.length));
}, 5000);
return () => clearInterval(id);
}, [load, path, location]);
return (
<Directory />
);
}
export default Dashboard;

View file

@ -1,11 +1,50 @@
@import url("https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css");
:root { :root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; --background: #242424;
--foreground: rgba(255, 255, 255, 0.87);
--sidebar-color: #2a2a2a;
--stroke: #3c3c3c;
--nav-color: #191919;
--nav-hover: #101010;
--profile-color: #3a3a3a;
--hover: rgba(255, 255, 255, 0.7);
--focus: rgba(255, 255, 255, 0.55);
--form-color: #151515;
--btn-primary: #0069d9;
--btn-secondary: #859099;
--btn-success: #28a745;
--btn-danger: #dc3545;
--btn-primary-hover: #0254ac;
--btn-secondary-hover: #596066;
--btn-success-hover: #208a39;
--btn-danger-hover: #b32735;
--btn-primary-focus: #034fa0;
--btn-secondary-focus: #50565c;
--btn-success-focus: #1d7c33;
--btn-danger-focus: #a72532;
--font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;
}
html, body {
margin: 0;
width: 100vw;
height: 100vh;
font-size: 11pt;
line-height: 1.5; line-height: 1.5;
font-weight: 400; font-weight: 400;
color-scheme: light dark; color-scheme: light dark;
color: rgba(255, 255, 255, 0.87); color: var(--foreground);
background-color: #242424; background-color: var(--background);
font-synthesis: none; font-synthesis: none;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
@ -13,57 +52,119 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
a { * {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
&:hover {
color: #535bf2;
}
}
body {
margin: 0; margin: 0;
display: flex; padding: 0;
place-items: center; box-sizing: border-box;
min-width: 320px;
min-height: 100vh; font-family: var(--font-family);
} }
h1 { h1 {
font-size: 3.2em; font-size: 32pt;
line-height: 1.1;
} }
button { h2 {
border-radius: 8px; font-size: 24pt;
border: 1px solid transparent; }
padding: 0.6em 1.2em;
font-size: 1em; h3 {
font-weight: 500; font-size: 18pt;
font-family: inherit; }
background-color: #1a1a1a;
h4 {
font-size: 16pt;
}
h5 {
font-size: 15pt;
}
h6 {
font-size: 12pt;
}
a {
cursor: pointer; cursor: pointer;
transition: border-color 0.25s; user-select: none;
} text-decoration: none;
button:hover { transition-duration: 0.3s;
border-color: #646cff; color: var(--foreground);
}
button:focus, &:hover {
button:focus-visible { color: var(--hover);
outline: 4px auto -webkit-focus-ring-color;
} }
@media (prefers-color-scheme: light) { &:focus {
:root { color: var(--focus);
color: #213547;
background-color: #ffffff;
} }
a:hover {
color: #747bff;
} }
input {
background-color: var(--background);
}
button { button {
background-color: #f9f9f9; cursor: pointer;
align-items: center;
justify-content: center;
transition-duration: 0.3s;
background-color: var(--background);
&.primary {
background-color: var(--btn-primary);
&:hover {
background-color: var(--btn-primary-hover);
}
&:focus {
background-color: var(--btn-primary-focus);
} }
} }
&.secondary {
background-color: var(--btn-secondary);
&:hover {
background-color: var(--btn-secondary-hover);
}
&:focus {
background-color: var(--btn-secondary-focus);
}
}
&.success {
background-color: var(--btn-success);
&:hover {
background-color: var(--btn-success-hover);
}
&:focus {
background-color: var(--btn-success-focus);
}
}
&.danger {
background-color: var(--btn-danger);
&:hover {
background-color: var(--btn-danger-hover);
}
&:focus {
background-color: var(--btn-danger-focus);
}
}
}
input, button {
height: 40px;
border: none;
outline: none;
font-size: 12pt;
border-radius: 25px;
padding: 0.25rem 15px;
}