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/" } });