diff --git a/.gitignore b/.gitignore
index 136130e..b908d77 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,6 @@ dist-ssr
*.sln
*.sw?
-public/
+web/
ka_data/
kuma-archive
diff --git a/app.go b/app.go
index 63ebb64..720c605 100644
--- a/app.go
+++ b/app.go
@@ -22,12 +22,17 @@ func main() {
return err
}
+ apiOnly, err := option.ParseBool(*n.MustGetOpt("api-only"), n)
+ if err != nil {
+ return err
+ }
+
if !debug {
gin.SetMode(gin.ReleaseMode)
}
gin := gin.Default()
- routes.New(gin)
+ routes.New(gin, apiOnly)
if err := gin.Run(fmt.Sprintf(":%d", cnf.Port)); err != nil {
return err
@@ -39,6 +44,10 @@ func main() {
Desc: "service debugging mode",
Short: []string{"d"},
Type: types.BOOLEAN,
+ }, types.OptionData{
+ Name: "api-only",
+ Desc: "no serve frontend service",
+ Type: types.BOOLEAN,
})
if err := command.Execute(); err != nil {
diff --git a/bun.lock b/bun.lock
index ffb0ef5..9f58547 100644
--- a/bun.lock
+++ b/bun.lock
@@ -4,6 +4,7 @@
"": {
"name": "kuma-archive",
"dependencies": {
+ "bootstrap": "^5.3.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-router": "^7.3.0",
@@ -136,6 +137,8 @@
"@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="],
+ "@popperjs/core": ["@popperjs/core@2.11.8", "", {}, "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="],
+
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.35.0", "", { "os": "android", "cpu": "arm" }, "sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.35.0", "", { "os": "android", "cpu": "arm64" }, "sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA=="],
@@ -240,6 +243,8 @@
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
+ "bootstrap": ["bootstrap@5.3.3", "", { "peerDependencies": { "@popperjs/core": "^2.11.8" } }, "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg=="],
+
"brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
diff --git a/index.html b/index.html
index 14b7eee..cbcb9a6 100644
--- a/index.html
+++ b/index.html
@@ -2,6 +2,7 @@
+
Kuma Archive
diff --git a/internal/routes/mod.go b/internal/routes/mod.go
index 277e399..714c1e4 100644
--- a/internal/routes/mod.go
+++ b/internal/routes/mod.go
@@ -9,37 +9,26 @@ import (
"github.com/gin-gonic/gin"
)
-func New(app *gin.Engine) {
- app.Use(static.Serve("/", static.LocalFile("./public", true)))
- app.Use(static.Serve("/assets", static.LocalFile("./assets", false)))
-
- app.NoRoute(func(ctx *gin.Context) {
- ctx.File("./public/index.html")
- })
-
- app.GET("favicon.ico", func(ctx *gin.Context) {
- ctx.File("/assets/favicon.ico")
- })
-
+func New(app *gin.Engine, apiOnly bool) {
api := app.Group("/api")
{
api.GET("/path/*path", func(ctx *gin.Context) {
worker := service.NewWorkerService()
path := ctx.Param("path")
- info, err := worker.Read(path)
+ data, err := worker.Read(path)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
ctx.Status(404)
return
}
- if !info.IsDir {
- ctx.FileAttachment(info.FullPath, info.Name)
+ if !data.IsDir {
+ ctx.FileAttachment(data.Path, data.Name)
return
}
- raw, err := os.ReadDir(info.FullPath)
+ raw, err := os.ReadDir(data.Path)
if err != nil {
ctx.Status(500)
return
@@ -55,8 +44,8 @@ func New(app *gin.Engine) {
entries = append(entries, service.DirEntry{
Name: entry.Name(),
+ Path: path,
FileSize: uint64(finfo.Size()),
- FullPath: path,
IsDir: finfo.IsDir(),
})
}
@@ -68,4 +57,20 @@ func New(app *gin.Engine) {
})
})
}
+
+ if apiOnly {
+ return
+ }
+
+ app.Use(static.Serve("/", static.LocalFile("./web", true)))
+ app.Use(static.Serve("/assets", static.LocalFile("./assets", false)))
+
+ app.NoRoute(func(ctx *gin.Context) {
+ ctx.File("./web/index.html")
+ })
+
+ app.GET("favicon.ico", func(ctx *gin.Context) {
+ ctx.File("/web/assets/favicon.ico")
+ })
+
}
diff --git a/internal/service/worker.go b/internal/service/worker.go
index c24e3f1..3859d54 100644
--- a/internal/service/worker.go
+++ b/internal/service/worker.go
@@ -11,7 +11,7 @@ type WorkerService struct{}
type DirEntry struct {
Name string `json:"name"`
- FullPath string `json:"path"`
+ Path string `json:"path"`
FileSize uint64 `json:"file_size"`
IsDir bool `json:"is_dir"`
}
@@ -29,7 +29,7 @@ func (sv *WorkerService) Read(path string) (*DirEntry, error) {
ret := DirEntry{
Name: info.Name(),
- FullPath: fullpath,
+ Path: fullpath,
FileSize: uint64(info.Size()),
}
return &ret, nil
diff --git a/package.json b/package.json
index a0f256d..514e02a 100644
--- a/package.json
+++ b/package.json
@@ -5,14 +5,16 @@
"type": "module",
"scripts": {
"dev": "vite",
- "build": "tsc -b && vite build",
- "build-server": "go build -o kuma-archive",
- "build:all": "bun run build && bun run build-server",
+ "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:all": "bun run build && bun run build-server",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
+ "bootstrap": "^5.3.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-router": "^7.3.0",
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..6ba7e78
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/src/App.scss b/src/App.scss
index b9d355d..e69de29 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -1,42 +0,0 @@
-#root {
- max-width: 1280px;
- margin: 0 auto;
- padding: 2rem;
- text-align: center;
-}
-
-.logo {
- height: 6em;
- padding: 1.5em;
- will-change: filter;
- transition: filter 300ms;
-}
-.logo:hover {
- filter: drop-shadow(0 0 2em #646cffaa);
-}
-.logo.react:hover {
- filter: drop-shadow(0 0 2em #61dafbaa);
-}
-
-@keyframes logo-spin {
- from {
- transform: rotate(0deg);
- }
- 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;
-}
diff --git a/src/App.tsx b/src/App.tsx
index 92c4a3c..d653a1d 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,7 +1,8 @@
import { BrowserRouter, Route, Routes } from "react-router";
-import "./App.scss";
import Dashboard from "./components/dashboard";
+import "./App.scss";
+
function App() {
return (
diff --git a/src/assets/kuma.png b/src/assets/kuma.png
new file mode 100644
index 0000000..9d3b59e
Binary files /dev/null and b/src/assets/kuma.png differ
diff --git a/src/main.tsx b/src/main.tsx
index 9a8e659..fca56b6 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,8 +1,10 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
-import "./index.scss";
import App from "./App.tsx";
+import "bootstrap/dist/css/bootstrap.min.css";
+import "./index.scss";
+
createRoot(document.getElementById("root")!).render(
diff --git a/vite.config.ts b/vite.config.ts
index 6eba899..18b7cd0 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -5,6 +5,6 @@ import react from "@vitejs/plugin-react-swc";
export default defineConfig({
plugins: [react()],
build: {
- outDir: "public/"
+ outDir: "web/"
}
});