feat: add directory navigator
This commit is contained in:
parent
ca8300b27c
commit
f0a94070d2
12 changed files with 90 additions and 53 deletions
2
go.mod
2
go.mod
|
@ -7,6 +7,7 @@ require (
|
||||||
github.com/gin-contrib/static v1.1.3
|
github.com/gin-contrib/static v1.1.3
|
||||||
github.com/gin-gonic/gin v1.10.0
|
github.com/gin-gonic/gin v1.10.0
|
||||||
github.com/mattn/go-sqlite3 v1.14.24
|
github.com/mattn/go-sqlite3 v1.14.24
|
||||||
|
golang.org/x/term v0.30.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -33,7 +34,6 @@ require (
|
||||||
golang.org/x/crypto v0.36.0 // indirect
|
golang.org/x/crypto v0.36.0 // indirect
|
||||||
golang.org/x/net v0.37.0 // indirect
|
golang.org/x/net v0.37.0 // indirect
|
||||||
golang.org/x/sys v0.31.0 // indirect
|
golang.org/x/sys v0.31.0 // indirect
|
||||||
golang.org/x/term v0.30.0 // indirect
|
|
||||||
golang.org/x/text v0.23.0 // indirect
|
golang.org/x/text v0.23.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.5 // indirect
|
google.golang.org/protobuf v1.36.5 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|
17
src/App.scss
17
src/App.scss
|
@ -1,6 +1,17 @@
|
||||||
.ka-view {
|
.ka-view {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
animation: fadeIn 0.3s ease-in-out;
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ka-nav {
|
.ka-nav {
|
||||||
|
@ -44,6 +55,12 @@
|
||||||
span {
|
span {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-btn {
|
.login-btn {
|
||||||
|
|
14
src/App.tsx
14
src/App.tsx
|
@ -1,19 +1,18 @@
|
||||||
|
import Login from "./components/login";
|
||||||
|
import Logout from "./components/logout";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import Settings from "./components/settings";
|
||||||
import { useVersion } from "./store/version";
|
import { useVersion } from "./store/version";
|
||||||
|
import NotFound from "./components/notfound";
|
||||||
import FileView from "./components/file-view";
|
import FileView from "./components/file-view";
|
||||||
import Directory from "./components/directory";
|
import Directory from "./components/directory";
|
||||||
import { DirEntry, usePath } from "./store/path";
|
import { DirEntry, usePath } from "./store/path";
|
||||||
import { DynamicIcon } from "lucide-react/dynamic";
|
import { DynamicIcon } from "lucide-react/dynamic";
|
||||||
import { BrowserRouter, Route, Routes, useLocation } from "react-router";
|
import { BrowserRouter, Route, Routes, useLocation } from "react-router";
|
||||||
|
import { AccountData, useAuthStore } from "./store/auth";
|
||||||
|
|
||||||
import "./App.scss";
|
import "./App.scss";
|
||||||
import kuma from "./assets/kuma.png";
|
import kuma from "./assets/kuma.png";
|
||||||
import NotFound from "./components/notfound";
|
|
||||||
import Login from "./components/login";
|
|
||||||
import { AccountData, useAuthStore } from "./store/auth";
|
|
||||||
import Logout from "./components/logout";
|
|
||||||
import Settings from "./components/settings";
|
|
||||||
import { FileNavigator } from "./components/navigation";
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
|
@ -32,7 +31,6 @@ function Dashboard({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<main className="container-md ka-view">
|
<main className="container-md ka-view">
|
||||||
<Header />
|
<Header />
|
||||||
<FileNavigator />
|
|
||||||
{children}
|
{children}
|
||||||
<Footer />
|
<Footer />
|
||||||
</main>
|
</main>
|
||||||
|
@ -125,7 +123,7 @@ function Header() {
|
||||||
<DynamicIcon name="settings" size={15} />
|
<DynamicIcon name="settings" size={15} />
|
||||||
</a>
|
</a>
|
||||||
<div className="login-info">
|
<div className="login-info">
|
||||||
<span>Logged in as {username}</span>
|
<span className="username">Logged in as {username}</span>
|
||||||
<a className="login-btn" href="/logout">
|
<a className="login-btn" href="/logout">
|
||||||
Logout
|
Logout
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: 1rem;
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-bottom: 1px solid var(--foreground);
|
border-bottom: 1px solid var(--foreground);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import "./directory.scss";
|
||||||
import Markdown from "react-markdown";
|
import Markdown from "react-markdown";
|
||||||
import { Suspense, useEffect, useState } from "react";
|
import { Suspense, useEffect, useState } from "react";
|
||||||
import { useLocation } from "react-router";
|
import { useLocation } from "react-router";
|
||||||
|
import { FileNavigator } from "../navigation";
|
||||||
|
|
||||||
function Directory() {
|
function Directory() {
|
||||||
const path = usePath();
|
const path = usePath();
|
||||||
|
@ -16,6 +17,7 @@ function Directory() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="ka-dir">
|
<div className="ka-dir">
|
||||||
|
<FileNavigator />
|
||||||
<div className="ka-dir-row ka-dir-top">
|
<div className="ka-dir-row ka-dir-top">
|
||||||
<div className="ka-dir-item"></div>
|
<div className="ka-dir-item"></div>
|
||||||
<b className="ka-dir-item">Name</b>
|
<b className="ka-dir-item">Name</b>
|
||||||
|
|
|
@ -5,21 +5,6 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
.action-row {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.link {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
span {
|
|
||||||
margin: 0.2rem 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#icon {
|
#icon {
|
||||||
margin: 3.5rem 0;
|
margin: 3.5rem 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { usePath } from "../../store/path";
|
||||||
import { DynamicIcon, IconName } from "lucide-react/dynamic";
|
import { DynamicIcon, IconName } from "lucide-react/dynamic";
|
||||||
|
|
||||||
import "./fview.scss";
|
import "./fview.scss";
|
||||||
|
import { FileNavigator } from "../navigation";
|
||||||
|
|
||||||
function FileView() {
|
function FileView() {
|
||||||
const path = usePath();
|
const path = usePath();
|
||||||
|
@ -93,15 +94,7 @@ function FileView() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ka-fileview">
|
<div className="ka-fileview">
|
||||||
<div className="action-row">
|
<FileNavigator />
|
||||||
<a className="link" onClick={ev => {
|
|
||||||
ev.preventDefault();
|
|
||||||
document.location.href = document.location.href.substring(0, document.location.href.lastIndexOf("/"));
|
|
||||||
}}>
|
|
||||||
<DynamicIcon name="chevron-left" />
|
|
||||||
<span>Back to directory</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<DynamicIcon id="icon" name={type} size={120} />
|
<DynamicIcon id="icon" name={type} size={120} />
|
||||||
<b>{path.data.path}</b>
|
<b>{path.data.path}</b>
|
||||||
{convert(path.data.total)}
|
{convert(path.data.total)}
|
||||||
|
|
|
@ -1,28 +1,42 @@
|
||||||
import { useLocation } from "react-router";
|
import { useLocation } from "react-router";
|
||||||
|
|
||||||
|
import "./navigation.scss";
|
||||||
|
|
||||||
export function FileNavigator() {
|
export function FileNavigator() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const split = location.pathname === "/" ? Array<string>() : location.pathname.substring(1, location.pathname.length).split("/");
|
const split = location.pathname === "/" ? Array<string>() : location.pathname.substring(1, location.pathname.length).split("/");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="ka-navigator">
|
||||||
|
{location.pathname === "/" ? (
|
||||||
|
<span className="current">Index Directory</span>
|
||||||
|
) : (
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<span>Index Directory</span>
|
<span>Index Directory</span>
|
||||||
</a>
|
</a>
|
||||||
|
)}
|
||||||
{split.map((path, i) => {
|
{split.map((path, i) => {
|
||||||
if (i === split.length - 1) {
|
let route = "";
|
||||||
return (
|
split.forEach((str, j) => {
|
||||||
<a key={i}>
|
if (j > i)
|
||||||
<span>{path}</span>
|
return;
|
||||||
</a>
|
|
||||||
);
|
route += `/${str}`;
|
||||||
}
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a key={i} href="">
|
<>
|
||||||
<span>{path}</span>
|
<span className="heap">></span>
|
||||||
<span>>></span>
|
{i === split.length - 1 ? (
|
||||||
|
<div key={i}>
|
||||||
|
<span className="current">{decodeURIComponent(path)}</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<a key={i} href={route}>
|
||||||
|
<span>{decodeURIComponent(path)}</span>
|
||||||
</a>
|
</a>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
24
src/components/navigation/navigation.scss
Normal file
24
src/components/navigation/navigation.scss
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
.ka-navigator {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
margin: 10px 0;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.current {
|
||||||
|
color: var(--foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
color: var(--description-color);
|
||||||
|
transition-duration: 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--foreground);
|
||||||
|
transition-duration: 0.3s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.heap {
|
||||||
|
margin: 0 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,10 +35,10 @@ function Settings() {
|
||||||
<h2 className="ka-title">General</h2>
|
<h2 className="ka-title">General</h2>
|
||||||
<AccountSetting auth={auth} />
|
<AccountSetting auth={auth} />
|
||||||
|
|
||||||
<h2 className="ka-title">Private Directory</h2>
|
{/* <h2 className="ka-title">Private Directory</h2> */}
|
||||||
<SettingBox>
|
{/* <SettingBox> */}
|
||||||
<h3>Not provided features</h3>
|
{/* TODO: create private directory setting */}
|
||||||
</SettingBox>
|
{/* </SettingBox> */}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,10 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ka-desc {
|
||||||
|
color: var(--description-color);
|
||||||
|
}
|
||||||
|
|
||||||
.setting-box {
|
.setting-box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
--background: #242424;
|
--background: #242424;
|
||||||
--foreground: rgba(255, 255, 255, 0.87);
|
--foreground: rgba(255, 255, 255, 0.87);
|
||||||
--sidebar-color: #2a2a2a;
|
--sidebar-color: #2a2a2a;
|
||||||
|
--description-color: #818181;
|
||||||
|
|
||||||
--stroke: #3c3c3c;
|
--stroke: #3c3c3c;
|
||||||
--nav-color: #191919;
|
--nav-color: #191919;
|
||||||
|
|
Loading…
Reference in a new issue