mirror of
https://github.com/OpenListTeam/OpenList-Frontend.git
synced 2026-03-13 11:20:24 +00:00
style: setup prettier & husky (#23)
This commit is contained in:
3
.github/workflows/release.yml
vendored
3
.github/workflows/release.yml
vendored
@@ -3,8 +3,7 @@ name: release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
changelog:
|
||||
|
||||
1
.husky/.gitignore
vendored
Normal file
1
.husky/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
_
|
||||
4
.husky/pre-commit
Executable file
4
.husky/pre-commit
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged
|
||||
5
.prettierignore
Normal file
5
.prettierignore
Normal file
@@ -0,0 +1,5 @@
|
||||
dist/
|
||||
solid-router/
|
||||
pnpm-lock.yaml
|
||||
.husky
|
||||
.prettierignore
|
||||
@@ -27,7 +27,8 @@
|
||||
"start": "vite",
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"serve": "vite preview"
|
||||
"serve": "vite preview",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
@@ -35,6 +36,9 @@
|
||||
"@types/node": "^18.7.5",
|
||||
"@types/streamsaver": "^2.0.1",
|
||||
"@vitejs/plugin-legacy": "^2.0.1",
|
||||
"husky": "^8.0.2",
|
||||
"lint-staged": "^13.0.4",
|
||||
"prettier": "2.8.0",
|
||||
"terser": "^5.14.2",
|
||||
"typescript": "^4.7.4",
|
||||
"vite": "^3.0.8",
|
||||
@@ -65,5 +69,8 @@
|
||||
"solid-markdown": "^1.2.0",
|
||||
"solid-transition-group": "^0.0.12",
|
||||
"streamsaver": "^2.0.6"
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*": "prettier --write"
|
||||
}
|
||||
}
|
||||
|
||||
1188
pnpm-lock.yaml
generated
1188
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -13,12 +13,12 @@
|
||||
// This will prevent the sw from restarting
|
||||
let keepAlive = () => {
|
||||
keepAlive = () => {}
|
||||
var ping = location.href.substr(0, location.href.lastIndexOf('/')) + '/ping'
|
||||
var ping = location.href.substr(0, location.href.lastIndexOf("/")) + "/ping"
|
||||
var interval = setInterval(() => {
|
||||
if (sw) {
|
||||
sw.postMessage('ping')
|
||||
sw.postMessage("ping")
|
||||
} else {
|
||||
fetch(ping).then(res => res.text(!res.ok && clearInterval(interval)))
|
||||
fetch(ping).then((res) => res.text(!res.ok && clearInterval(interval)))
|
||||
}
|
||||
}, 10000)
|
||||
}
|
||||
@@ -29,33 +29,44 @@
|
||||
// but since we need to wait for the Service Worker registration, we store the
|
||||
// message for later
|
||||
let messages = []
|
||||
window.onmessage = evt => messages.push(evt)
|
||||
window.onmessage = (evt) => messages.push(evt)
|
||||
|
||||
let sw = null
|
||||
let scope = ''
|
||||
let scope = ""
|
||||
|
||||
function registerWorker() {
|
||||
return navigator.serviceWorker.getRegistration('./').then(swReg => {
|
||||
return swReg || navigator.serviceWorker.register('sw.js', { scope: './' })
|
||||
}).then(swReg => {
|
||||
return navigator.serviceWorker
|
||||
.getRegistration("./")
|
||||
.then((swReg) => {
|
||||
return (
|
||||
swReg || navigator.serviceWorker.register("sw.js", { scope: "./" })
|
||||
)
|
||||
})
|
||||
.then((swReg) => {
|
||||
const swRegTmp = swReg.installing || swReg.waiting
|
||||
|
||||
scope = swReg.scope
|
||||
|
||||
return (sw = swReg.active) || new Promise(resolve => {
|
||||
swRegTmp.addEventListener('statechange', fn = () => {
|
||||
if (swRegTmp.state === 'activated') {
|
||||
swRegTmp.removeEventListener('statechange', fn)
|
||||
return (
|
||||
(sw = swReg.active) ||
|
||||
new Promise((resolve) => {
|
||||
swRegTmp.addEventListener(
|
||||
"statechange",
|
||||
(fn = () => {
|
||||
if (swRegTmp.state === "activated") {
|
||||
swRegTmp.removeEventListener("statechange", fn)
|
||||
sw = swReg.active
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
)
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// Now that we have the Service Worker registered we can process messages
|
||||
function onMessage (event) {
|
||||
function onMessage(event) {
|
||||
let { data, ports, origin } = event
|
||||
|
||||
// It's important to have a messageChannel, don't want to interfere
|
||||
@@ -64,7 +75,7 @@
|
||||
throw new TypeError("[StreamSaver] You didn't send a messageChannel")
|
||||
}
|
||||
|
||||
if (typeof data !== 'object') {
|
||||
if (typeof data !== "object") {
|
||||
throw new TypeError("[StreamSaver] You didn't send a object")
|
||||
}
|
||||
|
||||
@@ -77,15 +88,19 @@
|
||||
data.referrer = data.referrer || document.referrer || origin
|
||||
|
||||
// pass along version for possible backwards compatibility in sw.js
|
||||
data.streamSaverVersion = new URLSearchParams(location.search).get('version')
|
||||
data.streamSaverVersion = new URLSearchParams(location.search).get(
|
||||
"version"
|
||||
)
|
||||
|
||||
if (data.streamSaverVersion === '1.2.0') {
|
||||
console.warn('[StreamSaver] please update streamsaver')
|
||||
if (data.streamSaverVersion === "1.2.0") {
|
||||
console.warn("[StreamSaver] please update streamsaver")
|
||||
}
|
||||
|
||||
/** @since v2.0.0 */
|
||||
if (!data.headers) {
|
||||
console.warn("[StreamSaver] pass `data.headers` that you would like to pass along to the service worker\nit should be a 2D array or a key/val object that fetch's Headers api accepts")
|
||||
console.warn(
|
||||
"[StreamSaver] pass `data.headers` that you would like to pass along to the service worker\nit should be a 2D array or a key/val object that fetch's Headers api accepts"
|
||||
)
|
||||
} else {
|
||||
// test if it's correct
|
||||
// should thorw a typeError if not
|
||||
@@ -93,39 +108,47 @@
|
||||
}
|
||||
|
||||
/** @since v2.0.0 */
|
||||
if (typeof data.filename === 'string') {
|
||||
console.warn("[StreamSaver] You shouldn't send `data.filename` anymore. It should be included in the Content-Disposition header option")
|
||||
if (typeof data.filename === "string") {
|
||||
console.warn(
|
||||
"[StreamSaver] You shouldn't send `data.filename` anymore. It should be included in the Content-Disposition header option"
|
||||
)
|
||||
// Do what File constructor do with fileNames
|
||||
data.filename = data.filename.replace(/\//g, ':')
|
||||
data.filename = data.filename.replace(/\//g, ":")
|
||||
}
|
||||
|
||||
/** @since v2.0.0 */
|
||||
if (data.size) {
|
||||
console.warn("[StreamSaver] You shouldn't send `data.size` anymore. It should be included in the content-length header option")
|
||||
console.warn(
|
||||
"[StreamSaver] You shouldn't send `data.size` anymore. It should be included in the content-length header option"
|
||||
)
|
||||
}
|
||||
|
||||
/** @since v2.0.0 */
|
||||
if (data.readableStream) {
|
||||
console.warn("[StreamSaver] You should send the readableStream in the messageChannel, not through mitm")
|
||||
console.warn(
|
||||
"[StreamSaver] You should send the readableStream in the messageChannel, not through mitm"
|
||||
)
|
||||
}
|
||||
|
||||
/** @since v2.0.0 */
|
||||
if (!data.pathname) {
|
||||
console.warn("[StreamSaver] Please send `data.pathname` (eg: /pictures/summer.jpg)")
|
||||
data.pathname = Math.random().toString().slice(-6) + '/' + data.filename
|
||||
console.warn(
|
||||
"[StreamSaver] Please send `data.pathname` (eg: /pictures/summer.jpg)"
|
||||
)
|
||||
data.pathname = Math.random().toString().slice(-6) + "/" + data.filename
|
||||
}
|
||||
|
||||
// remove all leading slashes
|
||||
data.pathname = data.pathname.replace(/^\/+/g, '')
|
||||
data.pathname = data.pathname.replace(/^\/+/g, "")
|
||||
|
||||
// remove protocol
|
||||
let org = origin.replace(/(^\w+:|^)\/\//, '')
|
||||
let org = origin.replace(/(^\w+:|^)\/\//, "")
|
||||
|
||||
// set the absolute pathname to the download url.
|
||||
data.url = new URL(`${scope + org}/${data.pathname}`).toString()
|
||||
|
||||
if (!data.url.startsWith(`${scope + org}/`)) {
|
||||
throw new TypeError('[StreamSaver] bad `data.pathname`')
|
||||
throw new TypeError("[StreamSaver] bad `data.pathname`")
|
||||
}
|
||||
|
||||
// This sends the message data as well as transferring
|
||||
@@ -134,8 +157,8 @@
|
||||
// will in turn trigger the onmessage handler on messageChannel.port1.
|
||||
|
||||
const transferable = data.readableStream
|
||||
? [ ports[0], data.readableStream ]
|
||||
: [ ports[0] ]
|
||||
? [ports[0], data.readableStream]
|
||||
: [ports[0]]
|
||||
|
||||
if (!(data.readableStream || data.transferringReadable)) {
|
||||
keepAlive()
|
||||
@@ -147,7 +170,7 @@
|
||||
if (window.opener) {
|
||||
// The opener can't listen to onload event, so we need to help em out!
|
||||
// (telling them that we are ready to accept postMessage's)
|
||||
window.opener.postMessage('StreamSaver::loadedPopup', '*')
|
||||
window.opener.postMessage("StreamSaver::loadedPopup", "*")
|
||||
}
|
||||
|
||||
if (navigator.serviceWorker) {
|
||||
@@ -160,5 +183,4 @@
|
||||
// shouldn't really be possible?
|
||||
keepAlive()
|
||||
}
|
||||
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* global self ReadableStream Response */
|
||||
|
||||
self.addEventListener('install', () => {
|
||||
self.addEventListener("install", () => {
|
||||
self.skipWaiting()
|
||||
})
|
||||
|
||||
self.addEventListener('activate', event => {
|
||||
self.addEventListener("activate", (event) => {
|
||||
event.waitUntil(self.clients.claim())
|
||||
})
|
||||
|
||||
@@ -12,15 +12,20 @@ const map = new Map()
|
||||
|
||||
// This should be called once per download
|
||||
// Each event has a dataChannel that the data will be piped through
|
||||
self.onmessage = event => {
|
||||
self.onmessage = (event) => {
|
||||
// We send a heartbeat every x second to keep the
|
||||
// service worker alive if a transferable stream is not sent
|
||||
if (event.data === 'ping') {
|
||||
if (event.data === "ping") {
|
||||
return
|
||||
}
|
||||
|
||||
const data = event.data
|
||||
const downloadUrl = data.url || self.registration.scope + Math.random() + '/' + (typeof data === 'string' ? data : data.filename)
|
||||
const downloadUrl =
|
||||
data.url ||
|
||||
self.registration.scope +
|
||||
Math.random() +
|
||||
"/" +
|
||||
(typeof data === "string" ? data : data.filename)
|
||||
const port = event.ports[0]
|
||||
const metadata = new Array(3) // [stream, data, port]
|
||||
|
||||
@@ -33,7 +38,7 @@ self.onmessage = event => {
|
||||
if (event.data.readableStream) {
|
||||
metadata[0] = event.data.readableStream
|
||||
} else if (event.data.transferringReadable) {
|
||||
port.onmessage = evt => {
|
||||
port.onmessage = (evt) => {
|
||||
port.onmessage = null
|
||||
metadata[0] = evt.data.readableStream
|
||||
}
|
||||
@@ -45,84 +50,92 @@ self.onmessage = event => {
|
||||
port.postMessage({ download: downloadUrl })
|
||||
}
|
||||
|
||||
function createStream (port) {
|
||||
function createStream(port) {
|
||||
// ReadableStream is only supported by chrome 52
|
||||
return new ReadableStream({
|
||||
start (controller) {
|
||||
start(controller) {
|
||||
// When we receive data on the messageChannel, we write
|
||||
port.onmessage = ({ data }) => {
|
||||
if (data === 'end') {
|
||||
if (data === "end") {
|
||||
return controller.close()
|
||||
}
|
||||
|
||||
if (data === 'abort') {
|
||||
controller.error('Aborted the download')
|
||||
if (data === "abort") {
|
||||
controller.error("Aborted the download")
|
||||
return
|
||||
}
|
||||
|
||||
controller.enqueue(data)
|
||||
}
|
||||
},
|
||||
cancel () {
|
||||
console.log('user aborted')
|
||||
}
|
||||
cancel() {
|
||||
console.log("user aborted")
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
self.onfetch = event => {
|
||||
self.onfetch = (event) => {
|
||||
const url = event.request.url
|
||||
|
||||
// this only works for Firefox
|
||||
if (url.endsWith('/ping')) {
|
||||
return event.respondWith(new Response('pong'))
|
||||
if (url.endsWith("/ping")) {
|
||||
return event.respondWith(new Response("pong"))
|
||||
}
|
||||
|
||||
const hijacke = map.get(url)
|
||||
|
||||
if (!hijacke) return null
|
||||
|
||||
const [ stream, data, port ] = hijacke
|
||||
const [stream, data, port] = hijacke
|
||||
|
||||
map.delete(url)
|
||||
|
||||
// Not comfortable letting any user control all headers
|
||||
// so we only copy over the length & disposition
|
||||
const responseHeaders = new Headers({
|
||||
'Content-Type': 'application/octet-stream; charset=utf-8',
|
||||
"Content-Type": "application/octet-stream; charset=utf-8",
|
||||
|
||||
// To be on the safe side, The link can be opened in a iframe.
|
||||
// but octet-stream should stop it.
|
||||
'Content-Security-Policy': "default-src 'none'",
|
||||
'X-Content-Security-Policy': "default-src 'none'",
|
||||
'X-WebKit-CSP': "default-src 'none'",
|
||||
'X-XSS-Protection': '1; mode=block'
|
||||
"Content-Security-Policy": "default-src 'none'",
|
||||
"X-Content-Security-Policy": "default-src 'none'",
|
||||
"X-WebKit-CSP": "default-src 'none'",
|
||||
"X-XSS-Protection": "1; mode=block",
|
||||
})
|
||||
|
||||
let headers = new Headers(data.headers || {})
|
||||
|
||||
if (headers.has('Content-Length')) {
|
||||
responseHeaders.set('Content-Length', headers.get('Content-Length'))
|
||||
if (headers.has("Content-Length")) {
|
||||
responseHeaders.set("Content-Length", headers.get("Content-Length"))
|
||||
}
|
||||
|
||||
if (headers.has('Content-Disposition')) {
|
||||
responseHeaders.set('Content-Disposition', headers.get('Content-Disposition'))
|
||||
if (headers.has("Content-Disposition")) {
|
||||
responseHeaders.set(
|
||||
"Content-Disposition",
|
||||
headers.get("Content-Disposition")
|
||||
)
|
||||
}
|
||||
|
||||
// data, data.filename and size should not be used anymore
|
||||
if (data.size) {
|
||||
console.warn('Depricated')
|
||||
responseHeaders.set('Content-Length', data.size)
|
||||
console.warn("Depricated")
|
||||
responseHeaders.set("Content-Length", data.size)
|
||||
}
|
||||
|
||||
let fileName = typeof data === 'string' ? data : data.filename
|
||||
let fileName = typeof data === "string" ? data : data.filename
|
||||
if (fileName) {
|
||||
console.warn('Depricated')
|
||||
console.warn("Depricated")
|
||||
// Make filename RFC5987 compatible
|
||||
fileName = encodeURIComponent(fileName).replace(/['()]/g, escape).replace(/\*/g, '%2A')
|
||||
responseHeaders.set('Content-Disposition', "attachment; filename*=UTF-8''" + fileName)
|
||||
fileName = encodeURIComponent(fileName)
|
||||
.replace(/['()]/g, escape)
|
||||
.replace(/\*/g, "%2A")
|
||||
responseHeaders.set(
|
||||
"Content-Disposition",
|
||||
"attachment; filename*=UTF-8''" + fileName
|
||||
)
|
||||
}
|
||||
|
||||
event.respondWith(new Response(stream, { headers: responseHeaders }))
|
||||
|
||||
port.postMessage({ debug: 'Download started' })
|
||||
port.postMessage({ debug: "Download started" })
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base"
|
||||
]
|
||||
"extends": ["config:base"]
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import fs from "fs"
|
||||
import path from "path"
|
||||
|
||||
const root = "./src/lang";
|
||||
const entry = "entry.ts";
|
||||
const langs = fs.readdirSync(root);
|
||||
const root = "./src/lang"
|
||||
const entry = "entry.ts"
|
||||
const langs = fs.readdirSync(root)
|
||||
langs
|
||||
.filter((lang) => lang !== "en")
|
||||
.forEach((lang) => {
|
||||
fs.copyFileSync(path.join(root, "en", entry), path.join(root, lang, entry));
|
||||
});
|
||||
fs.copyFileSync(path.join(root, "en", entry), path.join(root, lang, entry))
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Progress, ProgressIndicator } from "@hope-ui/solid";
|
||||
import { Route, Routes, useIsRouting } from "@solidjs/router";
|
||||
import { Progress, ProgressIndicator } from "@hope-ui/solid"
|
||||
import { Route, Routes, useIsRouting } from "@solidjs/router"
|
||||
import {
|
||||
Component,
|
||||
createSignal,
|
||||
@@ -7,54 +7,54 @@ import {
|
||||
Match,
|
||||
onCleanup,
|
||||
Switch,
|
||||
} from "solid-js";
|
||||
import { Portal } from "solid-js/web";
|
||||
import { useLoading, useRouter } from "~/hooks";
|
||||
import { globalStyles } from "./theme";
|
||||
import { bus, r, handleRespWithoutAuthAndNotify, base_path } from "~/utils";
|
||||
import { setSettings } from "~/store";
|
||||
import { Error, FullScreenLoading } from "~/components";
|
||||
import { MustUser } from "./MustUser";
|
||||
import "./index.css";
|
||||
import { useI18n } from "@solid-primitives/i18n";
|
||||
import { initialLang, langMap, loadedLangs } from "./i18n";
|
||||
import { Resp } from "~/types";
|
||||
} from "solid-js"
|
||||
import { Portal } from "solid-js/web"
|
||||
import { useLoading, useRouter } from "~/hooks"
|
||||
import { globalStyles } from "./theme"
|
||||
import { bus, r, handleRespWithoutAuthAndNotify, base_path } from "~/utils"
|
||||
import { setSettings } from "~/store"
|
||||
import { Error, FullScreenLoading } from "~/components"
|
||||
import { MustUser } from "./MustUser"
|
||||
import "./index.css"
|
||||
import { useI18n } from "@solid-primitives/i18n"
|
||||
import { initialLang, langMap, loadedLangs } from "./i18n"
|
||||
import { Resp } from "~/types"
|
||||
|
||||
const Home = lazy(() => import("~/pages/home/Layout"));
|
||||
const Manage = lazy(() => import("~/pages/manage"));
|
||||
const Login = lazy(() => import("~/pages/login"));
|
||||
const Test = lazy(() => import("~/pages/test"));
|
||||
const Home = lazy(() => import("~/pages/home/Layout"))
|
||||
const Manage = lazy(() => import("~/pages/manage"))
|
||||
const Login = lazy(() => import("~/pages/login"))
|
||||
const Test = lazy(() => import("~/pages/test"))
|
||||
|
||||
const App: Component = () => {
|
||||
globalStyles();
|
||||
const [, { add }] = useI18n();
|
||||
const isRouting = useIsRouting();
|
||||
const { to } = useRouter();
|
||||
globalStyles()
|
||||
const [, { add }] = useI18n()
|
||||
const isRouting = useIsRouting()
|
||||
const { to } = useRouter()
|
||||
const onTo = (path: string) => {
|
||||
to(path);
|
||||
};
|
||||
bus.on("to", onTo);
|
||||
to(path)
|
||||
}
|
||||
bus.on("to", onTo)
|
||||
onCleanup(() => {
|
||||
bus.off("to", onTo);
|
||||
});
|
||||
bus.off("to", onTo)
|
||||
})
|
||||
|
||||
const [err, setErr] = createSignal<string>();
|
||||
const [err, setErr] = createSignal<string>()
|
||||
const [loading, data] = useLoading(() =>
|
||||
Promise.all([
|
||||
(async () => {
|
||||
add(initialLang, (await langMap[initialLang]()).default);
|
||||
loadedLangs.add(initialLang);
|
||||
add(initialLang, (await langMap[initialLang]()).default)
|
||||
loadedLangs.add(initialLang)
|
||||
})(),
|
||||
(async () => {
|
||||
handleRespWithoutAuthAndNotify(
|
||||
(await r.get("/public/settings")) as Resp<Record<string, string>>,
|
||||
setSettings,
|
||||
setErr
|
||||
);
|
||||
)
|
||||
})(),
|
||||
])
|
||||
);
|
||||
data();
|
||||
)
|
||||
data()
|
||||
return (
|
||||
<>
|
||||
<Portal>
|
||||
@@ -103,7 +103,7 @@ const App: Component = () => {
|
||||
</Match>
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default App;
|
||||
export default App
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { createI18nContext } from "@solid-primitives/i18n";
|
||||
import { createSignal } from "solid-js";
|
||||
import { createI18nContext } from "@solid-primitives/i18n"
|
||||
import { createSignal } from "solid-js"
|
||||
|
||||
interface Language {
|
||||
code: string;
|
||||
lang: string;
|
||||
code: string
|
||||
lang: string
|
||||
}
|
||||
const langs = import.meta.glob("~/lang/*/index.json", {
|
||||
eager: true,
|
||||
import: "lang",
|
||||
});
|
||||
const languages: Language[] = [];
|
||||
})
|
||||
const languages: Language[] = []
|
||||
|
||||
for (const path in langs) {
|
||||
const name = path.split("/")[3];
|
||||
const name = path.split("/")[3]
|
||||
languages.push({
|
||||
code: name,
|
||||
lang: langs[path] as string,
|
||||
});
|
||||
})
|
||||
}
|
||||
const defaultLang =
|
||||
languages.find(
|
||||
@@ -27,25 +27,25 @@ const defaultLang =
|
||||
lang.code.toLowerCase().split("_")[0] ===
|
||||
navigator.language.toLowerCase().split("_")[0]
|
||||
)?.code ||
|
||||
"en";
|
||||
"en"
|
||||
|
||||
export let initialLang = localStorage.getItem("lang") ?? "";
|
||||
export let initialLang = localStorage.getItem("lang") ?? ""
|
||||
if (!initialLang || !languages.find((lang) => lang.code === initialLang)) {
|
||||
initialLang = defaultLang;
|
||||
initialLang = defaultLang
|
||||
}
|
||||
|
||||
// store lang and import
|
||||
export const langMap: Record<string, any> = {};
|
||||
const imports = import.meta.glob("~/lang/*/entry.ts");
|
||||
export const langMap: Record<string, any> = {}
|
||||
const imports = import.meta.glob("~/lang/*/entry.ts")
|
||||
for (const path in imports) {
|
||||
const name = path.split("/")[3];
|
||||
langMap[name] = imports[path];
|
||||
const name = path.split("/")[3]
|
||||
langMap[name] = imports[path]
|
||||
}
|
||||
|
||||
export const loadedLangs = new Set<string>();
|
||||
export const loadedLangs = new Set<string>()
|
||||
|
||||
const i18n = createI18nContext({}, initialLang);
|
||||
const i18n = createI18nContext({}, initialLang)
|
||||
|
||||
const [currentLang, setLang] = createSignal(initialLang);
|
||||
const [currentLang, setLang] = createSignal(initialLang)
|
||||
|
||||
export { languages, i18n, currentLang, setLang };
|
||||
export { languages, i18n, currentLang, setLang }
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
background-color: rgba(0, 0, 0, 0.38);
|
||||
}
|
||||
|
||||
|
||||
/* dark */
|
||||
|
||||
.hope-ui-dark ::-webkit-scrollbar-corner,
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { HopeProvider, NotificationsProvider } from "@hope-ui/solid";
|
||||
import { I18nContext } from "@solid-primitives/i18n";
|
||||
import { ErrorBoundary, Suspense } from "solid-js";
|
||||
import { Error, FullScreenLoading } from "~/components";
|
||||
import App from "./App";
|
||||
import { i18n } from "./i18n";
|
||||
import { globalStyles, theme } from "./theme";
|
||||
import { HopeProvider, NotificationsProvider } from "@hope-ui/solid"
|
||||
import { I18nContext } from "@solid-primitives/i18n"
|
||||
import { ErrorBoundary, Suspense } from "solid-js"
|
||||
import { Error, FullScreenLoading } from "~/components"
|
||||
import App from "./App"
|
||||
import { i18n } from "./i18n"
|
||||
import { globalStyles, theme } from "./theme"
|
||||
|
||||
const Index = () => {
|
||||
globalStyles();
|
||||
globalStyles()
|
||||
return (
|
||||
<HopeProvider config={theme}>
|
||||
<ErrorBoundary
|
||||
fallback={(err) => {
|
||||
console.error("error", err);
|
||||
return <Error msg={`System error: ${err}`} h="100vh" />;
|
||||
console.error("error", err)
|
||||
return <Error msg={`System error: ${err}`} h="100vh" />
|
||||
}}
|
||||
>
|
||||
<I18nContext.Provider value={i18n}>
|
||||
@@ -25,7 +25,7 @@ const Index = () => {
|
||||
</I18nContext.Provider>
|
||||
</ErrorBoundary>
|
||||
</HopeProvider>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export { Index };
|
||||
export { Index }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { globalCss, HopeThemeConfig } from "@hope-ui/solid";
|
||||
import { hoverColor } from "~/utils";
|
||||
import { globalCss, HopeThemeConfig } from "@hope-ui/solid"
|
||||
import { hoverColor } from "~/utils"
|
||||
|
||||
const theme: HopeThemeConfig = {
|
||||
initialColorMode: "system",
|
||||
@@ -157,7 +157,7 @@ const theme: HopeThemeConfig = {
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const globalStyles = globalCss({
|
||||
"*": {
|
||||
@@ -176,6 +176,6 @@ export const globalStyles = globalCss({
|
||||
flexWrap: "wrap",
|
||||
rowGap: "0 !important",
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
export { theme };
|
||||
export { theme }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Center, ElementType, Spinner, SpinnerProps } from "@hope-ui/solid";
|
||||
import { JSXElement, mergeProps, Show } from "solid-js";
|
||||
import { getMainColor } from "~/store";
|
||||
import { Center, ElementType, Spinner, SpinnerProps } from "@hope-ui/solid"
|
||||
import { JSXElement, mergeProps, Show } from "solid-js"
|
||||
import { getMainColor } from "~/store"
|
||||
export const FullScreenLoading = () => {
|
||||
return (
|
||||
<Center h="100vh">
|
||||
@@ -12,14 +12,14 @@ export const FullScreenLoading = () => {
|
||||
size="xl"
|
||||
/>
|
||||
</Center>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export const FullLoading = (props: {
|
||||
py?: string;
|
||||
size?: string;
|
||||
thickness?: number;
|
||||
ref?: any;
|
||||
py?: string
|
||||
size?: string
|
||||
thickness?: number
|
||||
ref?: any
|
||||
}) => {
|
||||
const merged = mergeProps(
|
||||
{
|
||||
@@ -28,7 +28,7 @@ export const FullLoading = (props: {
|
||||
thickness: 4,
|
||||
},
|
||||
props
|
||||
);
|
||||
)
|
||||
return (
|
||||
<Center ref={props.ref} h="$full" w="$full" py={merged.py}>
|
||||
<Spinner
|
||||
@@ -39,19 +39,19 @@ export const FullLoading = (props: {
|
||||
size={merged.size as any}
|
||||
/>
|
||||
</Center>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export const MaybeLoading = (props: {
|
||||
children?: JSXElement;
|
||||
loading: boolean;
|
||||
children?: JSXElement
|
||||
loading: boolean
|
||||
}) => {
|
||||
return (
|
||||
<Show when={!props.loading} fallback={<FullLoading />}>
|
||||
{props.children}
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export const CenterLoading = <C extends ElementType = "div">(
|
||||
props: SpinnerProps<C>
|
||||
@@ -60,5 +60,5 @@ export const CenterLoading = <C extends ElementType = "div">(
|
||||
<Center w="$full" h="$full">
|
||||
<Spinner color={getMainColor()} {...props} />
|
||||
</Center>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const Hello = ()=>{
|
||||
const Hello = () => {
|
||||
return <h1>Hello, Solidjs</h1>
|
||||
}
|
||||
export default Hello;
|
||||
export default Hello
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { ElementType, Image, ImageProps } from "@hope-ui/solid";
|
||||
import { createSignal, JSXElement, Show } from "solid-js";
|
||||
import { ElementType, Image, ImageProps } from "@hope-ui/solid"
|
||||
import { createSignal, JSXElement, Show } from "solid-js"
|
||||
|
||||
export const ImageWithError = <C extends ElementType = "img">(
|
||||
props: ImageProps<C> & {
|
||||
fallbackErr?: JSXElement;
|
||||
fallbackErr?: JSXElement
|
||||
}
|
||||
) => {
|
||||
const [err, setErr] = createSignal(false);
|
||||
const [err, setErr] = createSignal(false)
|
||||
return (
|
||||
<Show when={!err()} fallback={props.fallbackErr}>
|
||||
<Image
|
||||
{...props}
|
||||
onError={() => {
|
||||
setErr(true);
|
||||
setErr(true)
|
||||
}}
|
||||
/>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { Link, LinkProps } from "@solidjs/router";
|
||||
import { Anchor, AnchorProps, ElementType } from "@hope-ui/solid";
|
||||
import { joinBase } from "~/utils";
|
||||
import { useRouter } from "~/hooks";
|
||||
import { Link, LinkProps } from "@solidjs/router"
|
||||
import { Anchor, AnchorProps, ElementType } from "@hope-ui/solid"
|
||||
import { joinBase } from "~/utils"
|
||||
import { useRouter } from "~/hooks"
|
||||
export const LinkWithBase = (props: LinkProps) => (
|
||||
<Link {...props} href={joinBase(props.href)} />
|
||||
);
|
||||
)
|
||||
export const AnchorWithBase = <C extends ElementType = "a">(
|
||||
props: AnchorProps<C>
|
||||
) => <Anchor {...props} href={joinBase(props.href)} />;
|
||||
) => <Anchor {...props} href={joinBase(props.href)} />
|
||||
|
||||
export const LinkWithPush = (props: LinkProps) => {
|
||||
const { pushHref } = useRouter();
|
||||
return <LinkWithBase {...props} href={pushHref(props.href)} />;
|
||||
};
|
||||
const { pushHref } = useRouter()
|
||||
return <LinkWithBase {...props} href={pushHref(props.href)} />
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// @ts-ignore
|
||||
import { hljs } from "./highlight.js";
|
||||
import SolidMarkdown from "solid-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import rehypeRaw from "rehype-raw";
|
||||
import "./markdown.css";
|
||||
import { onMount } from "solid-js";
|
||||
import { hljs } from "./highlight.js"
|
||||
import SolidMarkdown from "solid-markdown"
|
||||
import remarkGfm from "remark-gfm"
|
||||
import rehypeRaw from "rehype-raw"
|
||||
import "./markdown.css"
|
||||
import { onMount } from "solid-js"
|
||||
|
||||
export const Markdown = (props: { children?: string }) => {
|
||||
onMount(() => {
|
||||
hljs.highlightAll();
|
||||
});
|
||||
hljs.highlightAll()
|
||||
})
|
||||
return (
|
||||
<SolidMarkdown
|
||||
class="markdown-body"
|
||||
@@ -17,5 +17,5 @@ export const Markdown = (props: { children?: string }) => {
|
||||
rehypePlugins={[rehypeRaw]}
|
||||
children={props.children}
|
||||
/>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,31 +9,31 @@ import {
|
||||
Input,
|
||||
Textarea,
|
||||
FormHelperText,
|
||||
} from "@hope-ui/solid";
|
||||
import { createSignal, Show } from "solid-js";
|
||||
import { useT } from "~/hooks";
|
||||
import { notify } from "~/utils";
|
||||
} from "@hope-ui/solid"
|
||||
import { createSignal, Show } from "solid-js"
|
||||
import { useT } from "~/hooks"
|
||||
import { notify } from "~/utils"
|
||||
export type ModalInputProps = {
|
||||
opened: boolean;
|
||||
onClose: () => void;
|
||||
title: string;
|
||||
onSubmit?: (text: string) => void;
|
||||
type?: string;
|
||||
defaultValue?: string;
|
||||
loading?: boolean;
|
||||
tips?: string;
|
||||
};
|
||||
opened: boolean
|
||||
onClose: () => void
|
||||
title: string
|
||||
onSubmit?: (text: string) => void
|
||||
type?: string
|
||||
defaultValue?: string
|
||||
loading?: boolean
|
||||
tips?: string
|
||||
}
|
||||
export const ModalInput = (props: ModalInputProps) => {
|
||||
const [value, setValue] = createSignal(props.defaultValue ?? "");
|
||||
const t = useT();
|
||||
const [value, setValue] = createSignal(props.defaultValue ?? "")
|
||||
const t = useT()
|
||||
const submit = () => {
|
||||
if (!value()) {
|
||||
notify.warning(t("global.empty_input"));
|
||||
return;
|
||||
notify.warning(t("global.empty_input"))
|
||||
return
|
||||
}
|
||||
props.onSubmit?.(value())
|
||||
setValue("")
|
||||
}
|
||||
props.onSubmit?.(value());
|
||||
setValue("");
|
||||
};
|
||||
return (
|
||||
<Modal
|
||||
blockScrollOnMount={false}
|
||||
@@ -54,11 +54,11 @@ export const ModalInput = (props: ModalInputProps) => {
|
||||
type={props.type}
|
||||
value={value()}
|
||||
onInput={(e) => {
|
||||
setValue(e.currentTarget.value);
|
||||
setValue(e.currentTarget.value)
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
submit();
|
||||
submit()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -68,7 +68,7 @@ export const ModalInput = (props: ModalInputProps) => {
|
||||
id="modal-input"
|
||||
value={value()}
|
||||
onInput={(e) => {
|
||||
setValue(e.currentTarget.value);
|
||||
setValue(e.currentTarget.value)
|
||||
}}
|
||||
/>
|
||||
</Show>
|
||||
@@ -86,5 +86,5 @@ export const ModalInput = (props: ModalInputProps) => {
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,62 +1,62 @@
|
||||
import { Box } from "@hope-ui/solid";
|
||||
import { createEffect, createSignal, onCleanup, onMount } from "solid-js";
|
||||
import { MaybeLoading } from "./FullLoading";
|
||||
import loader from "@monaco-editor/loader";
|
||||
import { monaco_cdn } from "~/utils";
|
||||
import { Box } from "@hope-ui/solid"
|
||||
import { createEffect, createSignal, onCleanup, onMount } from "solid-js"
|
||||
import { MaybeLoading } from "./FullLoading"
|
||||
import loader from "@monaco-editor/loader"
|
||||
import { monaco_cdn } from "~/utils"
|
||||
|
||||
loader.config({
|
||||
paths: {
|
||||
vs: monaco_cdn,
|
||||
},
|
||||
});
|
||||
})
|
||||
export interface MonacoEditorProps {
|
||||
value: string;
|
||||
onChange?: (value: string) => void;
|
||||
theme: "vs" | "vs-dark";
|
||||
path?: string;
|
||||
language?: string;
|
||||
value: string
|
||||
onChange?: (value: string) => void
|
||||
theme: "vs" | "vs-dark"
|
||||
path?: string
|
||||
language?: string
|
||||
}
|
||||
let monaco: any;
|
||||
let monaco: any
|
||||
|
||||
export const MonacoEditorLoader = (props: MonacoEditorProps) => {
|
||||
const [loading, setLoading] = createSignal(true);
|
||||
const [loading, setLoading] = createSignal(true)
|
||||
loader.init().then((m) => {
|
||||
monaco = m;
|
||||
setLoading(false);
|
||||
});
|
||||
monaco = m
|
||||
setLoading(false)
|
||||
})
|
||||
return (
|
||||
<MaybeLoading loading={loading()}>
|
||||
<MonacoEditor {...props} />
|
||||
</MaybeLoading>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export const MonacoEditor = (props: MonacoEditorProps) => {
|
||||
let monacoEditorDiv: HTMLDivElement;
|
||||
let monacoEditor: any /*monaco.editor.IStandaloneCodeEditor*/;
|
||||
let model: any /*monaco.editor.ITextModel*/;
|
||||
let monacoEditorDiv: HTMLDivElement
|
||||
let monacoEditor: any /*monaco.editor.IStandaloneCodeEditor*/
|
||||
let model: any /*monaco.editor.ITextModel*/
|
||||
onMount(() => {
|
||||
monacoEditor = monaco.editor.create(monacoEditorDiv!, {
|
||||
value: props.value,
|
||||
theme: props.theme,
|
||||
});
|
||||
})
|
||||
model = monaco.editor.createModel(
|
||||
props.value,
|
||||
props.language,
|
||||
props.path ? monaco.Uri.parse(props.path) : undefined
|
||||
);
|
||||
monacoEditor.setModel(model);
|
||||
)
|
||||
monacoEditor.setModel(model)
|
||||
monacoEditor.onDidChangeModelContent(() => {
|
||||
props.onChange?.(monacoEditor.getValue());
|
||||
});
|
||||
});
|
||||
props.onChange?.(monacoEditor.getValue())
|
||||
})
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
monaco.editor.setTheme(props.theme);
|
||||
});
|
||||
monaco.editor.setTheme(props.theme)
|
||||
})
|
||||
onCleanup(() => {
|
||||
model && model.dispose();
|
||||
monacoEditor && monacoEditor.dispose();
|
||||
});
|
||||
return <Box w="$full" h="70vh" ref={monacoEditorDiv!} />;
|
||||
};
|
||||
model && model.dispose()
|
||||
monacoEditor && monacoEditor.dispose()
|
||||
})
|
||||
return <Box w="$full" h="70vh" ref={monacoEditorDiv!} />
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Button, HStack, IconButton } from "@hope-ui/solid";
|
||||
import { createMemo, For, mergeProps, Show } from "solid-js";
|
||||
import { createStore } from "solid-js/store";
|
||||
import { FaSolidAngleLeft, FaSolidAngleRight } from "solid-icons/fa";
|
||||
import { Button, HStack, IconButton } from "@hope-ui/solid"
|
||||
import { createMemo, For, mergeProps, Show } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { FaSolidAngleLeft, FaSolidAngleRight } from "solid-icons/fa"
|
||||
|
||||
export interface PaginatorProps {
|
||||
colorScheme?:
|
||||
@@ -11,14 +11,14 @@ export interface PaginatorProps {
|
||||
| "success"
|
||||
| "info"
|
||||
| "warning"
|
||||
| "danger";
|
||||
| "danger"
|
||||
// size?: "xs" | "sm" | "lg" | "xl" | "md";
|
||||
defaultCurrent?: number;
|
||||
onChange?: (current: number) => void;
|
||||
hideOnSinglePage?: boolean;
|
||||
total: number;
|
||||
defaultPageSize?: number;
|
||||
maxShowPage?: number;
|
||||
defaultCurrent?: number
|
||||
onChange?: (current: number) => void
|
||||
hideOnSinglePage?: boolean
|
||||
total: number
|
||||
defaultPageSize?: number
|
||||
maxShowPage?: number
|
||||
}
|
||||
export const Paginator = (props: PaginatorProps) => {
|
||||
const merged = mergeProps(
|
||||
@@ -29,35 +29,35 @@ export const Paginator = (props: PaginatorProps) => {
|
||||
hideOnSinglePage: true,
|
||||
},
|
||||
props
|
||||
);
|
||||
)
|
||||
const [store, setStore] = createStore({
|
||||
pageSize: merged.defaultPageSize,
|
||||
current: merged.defaultCurrent,
|
||||
});
|
||||
})
|
||||
const pages = createMemo(() => {
|
||||
return Math.ceil(merged.total / store.pageSize);
|
||||
});
|
||||
return Math.ceil(merged.total / store.pageSize)
|
||||
})
|
||||
const leftPages = createMemo(() => {
|
||||
const current = store.current;
|
||||
const min = Math.max(2, current - Math.floor(merged.maxShowPage / 2));
|
||||
return Array.from({ length: current - min }, (_, i) => min + i);
|
||||
});
|
||||
const current = store.current
|
||||
const min = Math.max(2, current - Math.floor(merged.maxShowPage / 2))
|
||||
return Array.from({ length: current - min }, (_, i) => min + i)
|
||||
})
|
||||
const rightPages = createMemo(() => {
|
||||
const current = store.current;
|
||||
const current = store.current
|
||||
const max = Math.min(
|
||||
pages() - 1,
|
||||
current + Math.floor(merged.maxShowPage / 2)
|
||||
);
|
||||
return Array.from({ length: max - current }, (_, i) => current + 1 + i);
|
||||
});
|
||||
)
|
||||
return Array.from({ length: max - current }, (_, i) => current + 1 + i)
|
||||
})
|
||||
const size = {
|
||||
"@initial": "sm",
|
||||
"@md": "md",
|
||||
} as const;
|
||||
} as const
|
||||
const onPageChange = (page: number) => {
|
||||
setStore("current", page);
|
||||
merged.onChange?.(page);
|
||||
};
|
||||
setStore("current", page)
|
||||
merged.onChange?.(page)
|
||||
}
|
||||
return (
|
||||
<Show when={!merged.hideOnSinglePage || pages() > 1}>
|
||||
<HStack spacing="$1">
|
||||
@@ -66,7 +66,7 @@ export const Paginator = (props: PaginatorProps) => {
|
||||
size={size}
|
||||
colorScheme={merged.colorScheme}
|
||||
onClick={() => {
|
||||
onPageChange(1);
|
||||
onPageChange(1)
|
||||
}}
|
||||
px="$3"
|
||||
>
|
||||
@@ -78,7 +78,7 @@ export const Paginator = (props: PaginatorProps) => {
|
||||
aria-label="Previous"
|
||||
colorScheme={merged.colorScheme}
|
||||
onClick={() => {
|
||||
onPageChange(store.current - 1);
|
||||
onPageChange(store.current - 1)
|
||||
}}
|
||||
w="2rem !important"
|
||||
/>
|
||||
@@ -89,7 +89,7 @@ export const Paginator = (props: PaginatorProps) => {
|
||||
size={size}
|
||||
colorScheme={merged.colorScheme}
|
||||
onClick={() => {
|
||||
onPageChange(page);
|
||||
onPageChange(page)
|
||||
}}
|
||||
px={page > 10 ? "$2_5" : "$3"}
|
||||
>
|
||||
@@ -111,7 +111,7 @@ export const Paginator = (props: PaginatorProps) => {
|
||||
size={size}
|
||||
colorScheme={merged.colorScheme}
|
||||
onClick={() => {
|
||||
onPageChange(page);
|
||||
onPageChange(page)
|
||||
}}
|
||||
px={page > 10 ? "$2_5" : "$3"}
|
||||
>
|
||||
@@ -126,7 +126,7 @@ export const Paginator = (props: PaginatorProps) => {
|
||||
aria-label="Next"
|
||||
colorScheme={merged.colorScheme}
|
||||
onClick={() => {
|
||||
onPageChange(store.current + 1);
|
||||
onPageChange(store.current + 1)
|
||||
}}
|
||||
w="2rem !important"
|
||||
/>
|
||||
@@ -134,7 +134,7 @@ export const Paginator = (props: PaginatorProps) => {
|
||||
size={size}
|
||||
colorScheme={merged.colorScheme}
|
||||
onClick={() => {
|
||||
onPageChange(pages());
|
||||
onPageChange(pages())
|
||||
}}
|
||||
px={pages() > 10 ? "$2_5" : "$3"}
|
||||
>
|
||||
@@ -143,5 +143,5 @@ export const Paginator = (props: PaginatorProps) => {
|
||||
</Show>
|
||||
</HStack>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Icon, useColorMode, useColorModeValue } from "@hope-ui/solid";
|
||||
import { Icon, useColorMode, useColorModeValue } from "@hope-ui/solid"
|
||||
// import { IoMoonOutline as Moon } from "solid-icons/io";
|
||||
import { FiSun as Sun } from "solid-icons/fi";
|
||||
import { FiMoon as Moon } from "solid-icons/fi";
|
||||
import { FiSun as Sun } from "solid-icons/fi"
|
||||
import { FiMoon as Moon } from "solid-icons/fi"
|
||||
|
||||
const SwitchColorMode = () => {
|
||||
const { toggleColorMode } = useColorMode();
|
||||
const { toggleColorMode } = useColorMode()
|
||||
const icon = useColorModeValue(
|
||||
{
|
||||
size: "$8",
|
||||
@@ -16,7 +16,7 @@ const SwitchColorMode = () => {
|
||||
component: Sun,
|
||||
p: "$0_5",
|
||||
}
|
||||
);
|
||||
)
|
||||
return (
|
||||
<Icon
|
||||
cursor="pointer"
|
||||
@@ -25,6 +25,6 @@ const SwitchColorMode = () => {
|
||||
onClick={toggleColorMode}
|
||||
p={icon().p}
|
||||
/>
|
||||
);
|
||||
};
|
||||
export { SwitchColorMode };
|
||||
)
|
||||
}
|
||||
export { SwitchColorMode }
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { Badge } from "@hope-ui/solid";
|
||||
import { useT } from "~/hooks";
|
||||
import { Badge } from "@hope-ui/solid"
|
||||
import { useT } from "~/hooks"
|
||||
|
||||
export interface WetherProps {
|
||||
yes?: boolean;
|
||||
yes?: boolean
|
||||
}
|
||||
|
||||
export const Wether = (props: WetherProps) => {
|
||||
const t = useT();
|
||||
const t = useT()
|
||||
return (
|
||||
<Badge colorScheme={props.yes ? "success" : "danger"}>
|
||||
{t(`global.${props.yes ? "yes" : "no"}`)}
|
||||
</Badge>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,12 +1,12 @@
|
||||
export * from "./FullLoading";
|
||||
export * from "./SwitchColorMode";
|
||||
export * from "./SwitchLanguage";
|
||||
export * from "./Hello";
|
||||
export * from "./FolderTree";
|
||||
export * from "./Wether";
|
||||
export * from "./LinkWithBase";
|
||||
export * from "./ImageWithError";
|
||||
export * from "./Markdown";
|
||||
export * from "./ModalInput";
|
||||
export * from "./Base";
|
||||
export * from "./Paginator";
|
||||
export * from "./FullLoading"
|
||||
export * from "./SwitchColorMode"
|
||||
export * from "./SwitchLanguage"
|
||||
export * from "./Hello"
|
||||
export * from "./FolderTree"
|
||||
export * from "./Wether"
|
||||
export * from "./LinkWithBase"
|
||||
export * from "./ImageWithError"
|
||||
export * from "./Markdown"
|
||||
export * from "./ModalInput"
|
||||
export * from "./Base"
|
||||
export * from "./Paginator"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
export * from "./useFetch";
|
||||
export * from "./useRouter";
|
||||
export * from "./useT";
|
||||
export * from "./useTitle";
|
||||
export * from "./usePath";
|
||||
export * from "./useLink";
|
||||
export * from "./useUtil";
|
||||
export * from "./useDownload";
|
||||
export * from "./useFetch"
|
||||
export * from "./useRouter"
|
||||
export * from "./useT"
|
||||
export * from "./useTitle"
|
||||
export * from "./usePath"
|
||||
export * from "./useLink"
|
||||
export * from "./useUtil"
|
||||
export * from "./useDownload"
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import axios from "axios";
|
||||
import { local, selectedObjs } from "~/store";
|
||||
import { notify } from "~/utils";
|
||||
import { useSelectedLink, useLink, useT } from ".";
|
||||
import axios from "axios"
|
||||
import { local, selectedObjs } from "~/store"
|
||||
import { notify } from "~/utils"
|
||||
import { useSelectedLink, useLink, useT } from "."
|
||||
|
||||
export const useDownload = () => {
|
||||
const { rawLinks } = useSelectedLink();
|
||||
const { rawLink } = useLink();
|
||||
const t = useT();
|
||||
const { rawLinks } = useSelectedLink()
|
||||
const { rawLink } = useLink()
|
||||
const t = useT()
|
||||
return {
|
||||
batchDownloadSelected: () => {
|
||||
const urls = rawLinks(true);
|
||||
const urls = rawLinks(true)
|
||||
urls.forEach((url) => {
|
||||
window.open(url, "_blank");
|
||||
});
|
||||
window.open(url, "_blank")
|
||||
})
|
||||
},
|
||||
sendToAria2: async () => {
|
||||
const selectedFiles = selectedObjs().filter((obj) => !obj.is_dir);
|
||||
const { aria2_rpc_url, aria2_rpc_secret, aria2_dir } = local;
|
||||
const selectedFiles = selectedObjs().filter((obj) => !obj.is_dir)
|
||||
const { aria2_rpc_url, aria2_rpc_secret, aria2_dir } = local
|
||||
if (!aria2_rpc_url) {
|
||||
notify.warning(t("home.toolbar.aria2_not_set"));
|
||||
return;
|
||||
notify.warning(t("home.toolbar.aria2_not_set"))
|
||||
return
|
||||
}
|
||||
try {
|
||||
for (const file of selectedFiles) {
|
||||
@@ -36,14 +36,14 @@ export const useDownload = () => {
|
||||
"check-certificate": "false",
|
||||
},
|
||||
],
|
||||
});
|
||||
console.log(resp);
|
||||
})
|
||||
console.log(resp)
|
||||
}
|
||||
notify.success(t("home.toolbar.send_aria2_success"));
|
||||
notify.success(t("home.toolbar.send_aria2_success"))
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
notify.error(`failed to send to aria2: ${e}`);
|
||||
console.error(e)
|
||||
notify.error(`failed to send to aria2: ${e}`)
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
import { objStore, selectedObjs, State, me } from "~/store";
|
||||
import { Obj } from "~/types";
|
||||
import {
|
||||
api,
|
||||
encodePath,
|
||||
pathDir,
|
||||
pathJoin,
|
||||
standardizePath,
|
||||
} from "~/utils";
|
||||
import { useRouter, useUtil } from ".";
|
||||
import { objStore, selectedObjs, State, me } from "~/store"
|
||||
import { Obj } from "~/types"
|
||||
import { api, encodePath, pathDir, pathJoin, standardizePath } from "~/utils"
|
||||
import { useRouter, useUtil } from "."
|
||||
|
||||
type URLType = "preview" | "direct" | "proxy";
|
||||
type URLType = "preview" | "direct" | "proxy"
|
||||
|
||||
// get download url by dir and obj
|
||||
export const getLinkByDirAndObj = (
|
||||
@@ -18,81 +12,81 @@ export const getLinkByDirAndObj = (
|
||||
type: URLType = "direct",
|
||||
encodeAll?: boolean
|
||||
) => {
|
||||
dir = standardizePath(pathJoin(me().base_path, dir), true);
|
||||
let path = `${dir}/${obj.name}`;
|
||||
path = encodePath(path, encodeAll);
|
||||
let host = api;
|
||||
let prefix = type === "direct" ? "/d" : "/p";
|
||||
dir = standardizePath(pathJoin(me().base_path, dir), true)
|
||||
let path = `${dir}/${obj.name}`
|
||||
path = encodePath(path, encodeAll)
|
||||
let host = api
|
||||
let prefix = type === "direct" ? "/d" : "/p"
|
||||
if (type === "preview") {
|
||||
host = location.origin;
|
||||
prefix = "";
|
||||
host = location.origin
|
||||
prefix = ""
|
||||
}
|
||||
let ans = `${host}${prefix}${path}`;
|
||||
let ans = `${host}${prefix}${path}`
|
||||
if (type !== "preview" && obj.sign) {
|
||||
ans += `?sign=${obj.sign}`;
|
||||
ans += `?sign=${obj.sign}`
|
||||
}
|
||||
return ans;
|
||||
};
|
||||
return ans
|
||||
}
|
||||
|
||||
// get download link by current state and pathname
|
||||
export const useLink = () => {
|
||||
const { pathname } = useRouter();
|
||||
const { pathname } = useRouter()
|
||||
const getLinkByObj = (obj: Obj, type?: URLType, encodeAll?: boolean) => {
|
||||
const dir =
|
||||
objStore.state === State.Folder ? pathname() : pathDir(pathname());
|
||||
return getLinkByDirAndObj(dir, obj, type, encodeAll);
|
||||
};
|
||||
objStore.state === State.Folder ? pathname() : pathDir(pathname())
|
||||
return getLinkByDirAndObj(dir, obj, type, encodeAll)
|
||||
}
|
||||
const rawLink = (obj: Obj, encodeAll?: boolean) => {
|
||||
return getLinkByObj(obj, "direct", encodeAll);
|
||||
};
|
||||
return getLinkByObj(obj, "direct", encodeAll)
|
||||
}
|
||||
return {
|
||||
getLinkByObj: getLinkByObj,
|
||||
rawLink: rawLink,
|
||||
proxyLink: (obj: Obj, encodeAll?: boolean) => {
|
||||
return getLinkByObj(obj, "proxy", encodeAll);
|
||||
return getLinkByObj(obj, "proxy", encodeAll)
|
||||
},
|
||||
previewPage: (obj: Obj, encodeAll?: boolean) => {
|
||||
return getLinkByObj(obj, "preview", encodeAll);
|
||||
return getLinkByObj(obj, "preview", encodeAll)
|
||||
},
|
||||
currentObjLink: (encodeAll?: boolean) => {
|
||||
return rawLink(objStore.obj, encodeAll);
|
||||
return rawLink(objStore.obj, encodeAll)
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const useSelectedLink = () => {
|
||||
const { previewPage, rawLink: rawUrl } = useLink();
|
||||
const { previewPage, rawLink: rawUrl } = useLink()
|
||||
const rawLinks = (encodeAll?: boolean) => {
|
||||
return selectedObjs()
|
||||
.filter((obj) => !obj.is_dir)
|
||||
.map((obj) => rawUrl(obj, encodeAll));
|
||||
};
|
||||
.map((obj) => rawUrl(obj, encodeAll))
|
||||
}
|
||||
return {
|
||||
rawLinks: rawLinks,
|
||||
previewPagesText: () => {
|
||||
return selectedObjs()
|
||||
.map((obj) => previewPage(obj, true))
|
||||
.join("\n");
|
||||
.join("\n")
|
||||
},
|
||||
rawLinksText: (encodeAll?: boolean) => {
|
||||
return rawLinks(encodeAll).join("\n");
|
||||
return rawLinks(encodeAll).join("\n")
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const useCopyLink = () => {
|
||||
const { copy } = useUtil();
|
||||
const { previewPagesText, rawLinksText } = useSelectedLink();
|
||||
const { currentObjLink } = useLink();
|
||||
const { copy } = useUtil()
|
||||
const { previewPagesText, rawLinksText } = useSelectedLink()
|
||||
const { currentObjLink } = useLink()
|
||||
return {
|
||||
copySelectedPreviewPage: () => {
|
||||
copy(previewPagesText());
|
||||
copy(previewPagesText())
|
||||
},
|
||||
copySelectedRawLink: (encodeAll?: boolean) => {
|
||||
copy(rawLinksText(encodeAll));
|
||||
copy(rawLinksText(encodeAll))
|
||||
},
|
||||
copyCurrentRawLink: (encodeAll?: boolean) => {
|
||||
copy(currentObjLink(encodeAll));
|
||||
copy(currentObjLink(encodeAll))
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import { useI18n } from "@solid-primitives/i18n";
|
||||
import { firstUpperCase } from "~/utils";
|
||||
import { useI18n } from "@solid-primitives/i18n"
|
||||
import { firstUpperCase } from "~/utils"
|
||||
|
||||
const useT = () => {
|
||||
const [t] = useI18n();
|
||||
const [t] = useI18n()
|
||||
return (
|
||||
key: string,
|
||||
params?: Record<string, string> | undefined,
|
||||
defaultValue?: string | undefined
|
||||
) => {
|
||||
const value = t(key, params, defaultValue);
|
||||
const value = t(key, params, defaultValue)
|
||||
if (!value) {
|
||||
if (import.meta.env.DEV) return key;
|
||||
let lastDotIndex = key.lastIndexOf(".");
|
||||
if (import.meta.env.DEV) return key
|
||||
let lastDotIndex = key.lastIndexOf(".")
|
||||
if (lastDotIndex === key.length - 1) {
|
||||
lastDotIndex = key.lastIndexOf(".", lastDotIndex - 1);
|
||||
lastDotIndex = key.lastIndexOf(".", lastDotIndex - 1)
|
||||
}
|
||||
const last = key.slice(lastDotIndex + 1);
|
||||
return firstUpperCase(last).split("_").join(" ");
|
||||
const last = key.slice(lastDotIndex + 1)
|
||||
return firstUpperCase(last).split("_").join(" ")
|
||||
}
|
||||
return value;
|
||||
};
|
||||
};
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
export { useT };
|
||||
export { useT }
|
||||
|
||||
@@ -1,55 +1,55 @@
|
||||
import { createEffect, onCleanup } from "solid-js";
|
||||
import { getSetting } from "~/store";
|
||||
import { pathBase } from "~/utils";
|
||||
import { useRouter } from "./useRouter";
|
||||
import { useT } from "./useT";
|
||||
import { createEffect, onCleanup } from "solid-js"
|
||||
import { getSetting } from "~/store"
|
||||
import { pathBase } from "~/utils"
|
||||
import { useRouter } from "./useRouter"
|
||||
import { useT } from "./useT"
|
||||
|
||||
let id = 0;
|
||||
const effects: Record<string, boolean> = {};
|
||||
let id = 0
|
||||
const effects: Record<string, boolean> = {}
|
||||
|
||||
const useTitle = (title: string | (() => string)) => {
|
||||
const cid = (id++).toString();
|
||||
const valids: string[] = [];
|
||||
const cid = (id++).toString()
|
||||
const valids: string[] = []
|
||||
for (const key in effects) {
|
||||
if (effects[key]) {
|
||||
valids.push(key);
|
||||
effects[key] = false;
|
||||
valids.push(key)
|
||||
effects[key] = false
|
||||
}
|
||||
}
|
||||
effects[cid] = true;
|
||||
const pre = document.title;
|
||||
effects[cid] = true
|
||||
const pre = document.title
|
||||
if (typeof title === "function") {
|
||||
createEffect(() => {
|
||||
if (effects[cid]) {
|
||||
document.title = title();
|
||||
document.title = title()
|
||||
}
|
||||
});
|
||||
})
|
||||
} else {
|
||||
document.title = title;
|
||||
document.title = title
|
||||
}
|
||||
onCleanup(() => {
|
||||
// document.title = pre;
|
||||
delete effects[cid];
|
||||
delete effects[cid]
|
||||
for (const key in valids) {
|
||||
effects[key] = true;
|
||||
effects[key] = true
|
||||
}
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
export const useObjTitle = () => {
|
||||
const t = useT();
|
||||
const { pathname } = useRouter();
|
||||
const t = useT()
|
||||
const { pathname } = useRouter()
|
||||
useTitle(
|
||||
() =>
|
||||
`${
|
||||
pathname() === "/" ? t("manage.sidemenu.home") : pathBase(pathname())
|
||||
} | ${getSetting("site_title")}`
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export const useManageTitle = (title: string) => {
|
||||
const t = useT();
|
||||
useTitle(() => `${t(title)} | ${t("manage.title")}`);
|
||||
};
|
||||
const t = useT()
|
||||
useTitle(() => `${t(title)} | ${t("manage.title")}`)
|
||||
}
|
||||
|
||||
export { useTitle };
|
||||
export { useTitle }
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import copy from "copy-to-clipboard";
|
||||
import { createResource } from "solid-js";
|
||||
import { getHideFiles, objStore } from "~/store";
|
||||
import { Obj } from "~/types";
|
||||
import { fetchText, notify, pathJoin } from "~/utils";
|
||||
import { useT, useLink, useRouter } from ".";
|
||||
import copy from "copy-to-clipboard"
|
||||
import { createResource } from "solid-js"
|
||||
import { getHideFiles, objStore } from "~/store"
|
||||
import { Obj } from "~/types"
|
||||
import { fetchText, notify, pathJoin } from "~/utils"
|
||||
import { useT, useLink, useRouter } from "."
|
||||
|
||||
export const useUtil = () => {
|
||||
const t = useT();
|
||||
const { pathname } = useRouter();
|
||||
const t = useT()
|
||||
const { pathname } = useRouter()
|
||||
return {
|
||||
copy: (text: string) => {
|
||||
copy(text);
|
||||
notify.success(t("global.copied"));
|
||||
copy(text)
|
||||
notify.success(t("global.copied"))
|
||||
},
|
||||
isHide: (obj: Obj) => {
|
||||
const hideFiles = getHideFiles();
|
||||
const hideFiles = getHideFiles()
|
||||
for (const reg of hideFiles) {
|
||||
if (reg.test(pathJoin(pathname(), obj.name))) {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const useFetchText = () => {
|
||||
const { proxyLink } = useLink();
|
||||
const { proxyLink } = useLink()
|
||||
const fetchContent = async () => {
|
||||
return fetchText(proxyLink(objStore.obj, true));
|
||||
};
|
||||
return createResource("", fetchContent);
|
||||
};
|
||||
return fetchText(proxyLink(objStore.obj, true))
|
||||
}
|
||||
return createResource("", fetchContent)
|
||||
}
|
||||
|
||||
6
src/index.d.ts
vendored
6
src/index.d.ts
vendored
@@ -1,7 +1,7 @@
|
||||
declare module "aplayer";
|
||||
declare module "aplayer"
|
||||
declare namespace aliyun {
|
||||
class Config {
|
||||
setToken(token: { token: string }): any;
|
||||
setToken(token: { token: string }): any
|
||||
}
|
||||
function config(options: { mount: Element; url: string }): Config;
|
||||
function config(options: { mount: Element; url: string }): Config
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
const jsons = import.meta.glob("./*.json", { eager: true, import: "default" });
|
||||
const langs: any = {};
|
||||
const jsons = import.meta.glob("./*.json", { eager: true, import: "default" })
|
||||
const langs: any = {}
|
||||
for (const path in jsons) {
|
||||
const name = path.split("/")[1].split(".")[0];
|
||||
langs[name] = jsons[path];
|
||||
const name = path.split("/")[1].split(".")[0]
|
||||
langs[name] = jsons[path]
|
||||
}
|
||||
export default langs;
|
||||
export default langs
|
||||
|
||||
10
src/main.tsx
10
src/main.tsx
@@ -1,12 +1,12 @@
|
||||
/* @refresh reload */
|
||||
import { Router } from "@solidjs/router";
|
||||
import { render } from "solid-js/web";
|
||||
import { Router } from "@solidjs/router"
|
||||
import { render } from "solid-js/web"
|
||||
|
||||
import { Index } from "./app";
|
||||
import { Index } from "./app"
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
[key: string]: any;
|
||||
[key: string]: any
|
||||
}
|
||||
}
|
||||
render(
|
||||
@@ -16,4 +16,4 @@ render(
|
||||
</Router>
|
||||
),
|
||||
document.getElementById("root") as HTMLElement
|
||||
);
|
||||
)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { VStack } from "@hope-ui/solid";
|
||||
import { Nav } from "./Nav";
|
||||
import { Obj } from "./Obj";
|
||||
import { Readme } from "./Readme";
|
||||
import { Container } from "./Container";
|
||||
import { VStack } from "@hope-ui/solid"
|
||||
import { Nav } from "./Nav"
|
||||
import { Obj } from "./Obj"
|
||||
import { Readme } from "./Readme"
|
||||
import { Container } from "./Container"
|
||||
|
||||
export const Body = () => {
|
||||
return (
|
||||
@@ -21,5 +21,5 @@ export const Body = () => {
|
||||
<Readme />
|
||||
</VStack>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { JSXElement, Match, Switch } from "solid-js";
|
||||
import { getSetting } from "~/store";
|
||||
import { Box, Container as HopeContainer } from "@hope-ui/solid";
|
||||
import { JSXElement, Match, Switch } from "solid-js"
|
||||
import { getSetting } from "~/store"
|
||||
import { Box, Container as HopeContainer } from "@hope-ui/solid"
|
||||
|
||||
export const Container = (props: { children: JSXElement }) => {
|
||||
const container = getSetting("home_container");
|
||||
const container = getSetting("home_container")
|
||||
return (
|
||||
<Switch fallback={<Box w="min(99%, 980px)">{props.children}</Box>}>
|
||||
<Match when={container === "hope_container"}>
|
||||
<HopeContainer>{props.children}</HopeContainer>
|
||||
</Match>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Anchor, HStack, VStack } from "@hope-ui/solid";
|
||||
import { Link } from "@solidjs/router";
|
||||
import { AnchorWithBase } from "~/components";
|
||||
import { useT } from "~/hooks";
|
||||
import { me } from "~/store";
|
||||
import { UserMethods } from "~/types";
|
||||
import { Anchor, HStack, VStack } from "@hope-ui/solid"
|
||||
import { Link } from "@solidjs/router"
|
||||
import { AnchorWithBase } from "~/components"
|
||||
import { useT } from "~/hooks"
|
||||
import { me } from "~/store"
|
||||
import { UserMethods } from "~/types"
|
||||
|
||||
export const Footer = () => {
|
||||
const t = useT();
|
||||
const t = useT()
|
||||
return (
|
||||
<VStack class="footer" w="$full" py="$4">
|
||||
<HStack spacing="$1">
|
||||
@@ -18,11 +18,9 @@ export const Footer = () => {
|
||||
as={Link}
|
||||
href={UserMethods.is_guest(me()) ? "/@login" : "/@manage"}
|
||||
>
|
||||
{t(
|
||||
UserMethods.is_guest(me()) ? "login.login" : "home.footer.manage"
|
||||
)}
|
||||
{t(UserMethods.is_guest(me()) ? "login.login" : "home.footer.manage")}
|
||||
</AnchorWithBase>
|
||||
</HStack>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { Markdown } from "~/components";
|
||||
import { useTitle } from "~/hooks";
|
||||
import { getSetting } from "~/store";
|
||||
import { notify } from "~/utils";
|
||||
import { Body } from "./Body";
|
||||
import { Footer } from "./Footer";
|
||||
import { Header } from "./Header";
|
||||
import { Toolbar } from "./toolbar/Toolbar";
|
||||
import { Markdown } from "~/components"
|
||||
import { useTitle } from "~/hooks"
|
||||
import { getSetting } from "~/store"
|
||||
import { notify } from "~/utils"
|
||||
import { Body } from "./Body"
|
||||
import { Footer } from "./Footer"
|
||||
import { Header } from "./Header"
|
||||
import { Toolbar } from "./toolbar/Toolbar"
|
||||
|
||||
const Index = () => {
|
||||
useTitle(getSetting("site_title"));
|
||||
const announcement = getSetting("announcement");
|
||||
useTitle(getSetting("site_title"))
|
||||
const announcement = getSetting("announcement")
|
||||
if (announcement) {
|
||||
notify.render(() => <Markdown children={announcement} />);
|
||||
notify.render(() => <Markdown children={announcement} />)
|
||||
}
|
||||
return (
|
||||
<>
|
||||
@@ -20,7 +20,7 @@ const Index = () => {
|
||||
<Body />
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Index;
|
||||
export default Index
|
||||
|
||||
@@ -3,33 +3,30 @@ import {
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbSeparator,
|
||||
} from "@hope-ui/solid";
|
||||
import { Link } from "@solidjs/router";
|
||||
import { createMemo, For, Show } from "solid-js";
|
||||
import { usePath, useRouter, useT } from "~/hooks";
|
||||
import { getSetting } from "~/store";
|
||||
import { encodePath, hoverColor, joinBase } from "~/utils";
|
||||
} from "@hope-ui/solid"
|
||||
import { Link } from "@solidjs/router"
|
||||
import { createMemo, For, Show } from "solid-js"
|
||||
import { usePath, useRouter, useT } from "~/hooks"
|
||||
import { getSetting } from "~/store"
|
||||
import { encodePath, hoverColor, joinBase } from "~/utils"
|
||||
|
||||
export const Nav = () => {
|
||||
const { pathname } = useRouter();
|
||||
const paths = createMemo(() => [
|
||||
"",
|
||||
...pathname().split("/").filter(Boolean),
|
||||
]);
|
||||
const t = useT();
|
||||
const { setPathAs } = usePath();
|
||||
const { pathname } = useRouter()
|
||||
const paths = createMemo(() => ["", ...pathname().split("/").filter(Boolean)])
|
||||
const t = useT()
|
||||
const { setPathAs } = usePath()
|
||||
return (
|
||||
<Breadcrumb class="nav" w="$full">
|
||||
<For each={paths()}>
|
||||
{(name, i) => {
|
||||
const isLast = createMemo(() => i() === paths().length - 1);
|
||||
const isLast = createMemo(() => i() === paths().length - 1)
|
||||
const path = paths()
|
||||
.slice(0, i() + 1)
|
||||
.join("/");
|
||||
const href = encodePath(path);
|
||||
let text = () => name;
|
||||
.join("/")
|
||||
const href = encodePath(path)
|
||||
let text = () => name
|
||||
if (text() === "") {
|
||||
text = () => getSetting("home_icon") + t("manage.sidemenu.home");
|
||||
text = () => getSetting("home_icon") + t("manage.sidemenu.home")
|
||||
}
|
||||
return (
|
||||
<BreadcrumbItem class="nav-item">
|
||||
@@ -55,9 +52,9 @@ export const Nav = () => {
|
||||
<BreadcrumbSeparator class="nav-separator" />
|
||||
</Show>
|
||||
</BreadcrumbItem>
|
||||
);
|
||||
)
|
||||
}}
|
||||
</For>
|
||||
</Breadcrumb>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,15 +7,15 @@ import {
|
||||
Text,
|
||||
useColorModeValue,
|
||||
VStack,
|
||||
} from "@hope-ui/solid";
|
||||
import { LinkWithBase } from "~/components";
|
||||
import { usePath, useRouter, useT } from "~/hooks";
|
||||
import { password, setPassword } from "~/store";
|
||||
} from "@hope-ui/solid"
|
||||
import { LinkWithBase } from "~/components"
|
||||
import { usePath, useRouter, useT } from "~/hooks"
|
||||
import { password, setPassword } from "~/store"
|
||||
|
||||
const Password = () => {
|
||||
const t = useT();
|
||||
const { refresh } = usePath();
|
||||
const { back } = useRouter();
|
||||
const t = useT()
|
||||
const { refresh } = usePath()
|
||||
const { back } = useRouter()
|
||||
return (
|
||||
<VStack
|
||||
w={{
|
||||
@@ -33,7 +33,7 @@ const Password = () => {
|
||||
background={useColorModeValue("$neutral3", "$neutral2")()}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
refresh(true);
|
||||
refresh(true)
|
||||
}
|
||||
}}
|
||||
onInput={(e) => setPassword(e.currentTarget.value)}
|
||||
@@ -62,6 +62,6 @@ const Password = () => {
|
||||
</HStack>
|
||||
</HStack>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
export default Password;
|
||||
)
|
||||
}
|
||||
export default Password
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { HStack, VStack } from "@hope-ui/solid";
|
||||
import { createMemo, createSignal, Show, Suspense } from "solid-js";
|
||||
import { Dynamic } from "solid-js/web";
|
||||
import { FullLoading, SelectWrapper } from "~/components";
|
||||
import { objStore } from "~/store";
|
||||
import { Download } from "../previews/download";
|
||||
import { OpenWith } from "./open-with";
|
||||
import { getPreviews } from "../previews";
|
||||
import { HStack, VStack } from "@hope-ui/solid"
|
||||
import { createMemo, createSignal, Show, Suspense } from "solid-js"
|
||||
import { Dynamic } from "solid-js/web"
|
||||
import { FullLoading, SelectWrapper } from "~/components"
|
||||
import { objStore } from "~/store"
|
||||
import { Download } from "../previews/download"
|
||||
import { OpenWith } from "./open-with"
|
||||
import { getPreviews } from "../previews"
|
||||
|
||||
const File = () => {
|
||||
const previews = createMemo(() => {
|
||||
return getPreviews({ ...objStore.obj, provider: objStore.provider });
|
||||
});
|
||||
const [cur, setCur] = createSignal(previews()[0]);
|
||||
return getPreviews({ ...objStore.obj, provider: objStore.provider })
|
||||
})
|
||||
const [cur, setCur] = createSignal(previews()[0])
|
||||
return (
|
||||
<Show when={previews().length > 1} fallback={<Download openWith />}>
|
||||
<VStack w="$full" spacing="$2">
|
||||
@@ -20,7 +20,7 @@ const File = () => {
|
||||
alwaysShowBorder
|
||||
value={cur().name}
|
||||
onChange={(name) => {
|
||||
setCur(previews().find((p) => p.name === name)!);
|
||||
setCur(previews().find((p) => p.name === name)!)
|
||||
}}
|
||||
options={previews().map((item) => ({ value: item.name }))}
|
||||
/>
|
||||
@@ -31,7 +31,7 @@ const File = () => {
|
||||
</Suspense>
|
||||
</VStack>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default File;
|
||||
export default File
|
||||
|
||||
@@ -5,18 +5,18 @@ import {
|
||||
MenuContent,
|
||||
MenuItem,
|
||||
MenuTrigger,
|
||||
} from "@hope-ui/solid";
|
||||
import { createMemo, For, Show } from "solid-js";
|
||||
import { useT } from "~/hooks";
|
||||
import { getExternalPreviews, objStore } from "~/store";
|
||||
import { FaSolidAngleDown } from "solid-icons/fa";
|
||||
import { convertURL } from "~/utils";
|
||||
} from "@hope-ui/solid"
|
||||
import { createMemo, For, Show } from "solid-js"
|
||||
import { useT } from "~/hooks"
|
||||
import { getExternalPreviews, objStore } from "~/store"
|
||||
import { FaSolidAngleDown } from "solid-icons/fa"
|
||||
import { convertURL } from "~/utils"
|
||||
|
||||
export const OpenWith = () => {
|
||||
const t = useT();
|
||||
const t = useT()
|
||||
const previews = createMemo(() => {
|
||||
return getExternalPreviews(objStore.obj.name);
|
||||
});
|
||||
return getExternalPreviews(objStore.obj.name)
|
||||
})
|
||||
return (
|
||||
<Show when={previews().length}>
|
||||
<Menu>
|
||||
@@ -46,5 +46,5 @@ export const OpenWith = () => {
|
||||
</MenuContent>
|
||||
</Menu>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,55 +1,55 @@
|
||||
import { lazy, Show, createEffect, createMemo, onCleanup } from "solid-js";
|
||||
import { layout } from "~/store";
|
||||
import { ContextMenu } from "./context-menu";
|
||||
import { Pager } from "./Pager";
|
||||
import { useLink } from "~/hooks";
|
||||
import { objStore } from "~/store";
|
||||
import { ObjType } from "~/types";
|
||||
import { bus } from "~/utils";
|
||||
import lightGallery from "lightgallery";
|
||||
import lgThumbnail from "lightgallery/plugins/thumbnail";
|
||||
import lgZoom from "lightgallery/plugins/zoom";
|
||||
import lgRotate from "lightgallery/plugins/rotate";
|
||||
import lgAutoplay from "lightgallery/plugins/autoplay";
|
||||
import lgFullscreen from "lightgallery/plugins/fullscreen";
|
||||
import "lightgallery/css/lightgallery-bundle.css";
|
||||
import { LightGallery } from "lightgallery/lightgallery";
|
||||
import { Search } from "./Search";
|
||||
import { lazy, Show, createEffect, createMemo, onCleanup } from "solid-js"
|
||||
import { layout } from "~/store"
|
||||
import { ContextMenu } from "./context-menu"
|
||||
import { Pager } from "./Pager"
|
||||
import { useLink } from "~/hooks"
|
||||
import { objStore } from "~/store"
|
||||
import { ObjType } from "~/types"
|
||||
import { bus } from "~/utils"
|
||||
import lightGallery from "lightgallery"
|
||||
import lgThumbnail from "lightgallery/plugins/thumbnail"
|
||||
import lgZoom from "lightgallery/plugins/zoom"
|
||||
import lgRotate from "lightgallery/plugins/rotate"
|
||||
import lgAutoplay from "lightgallery/plugins/autoplay"
|
||||
import lgFullscreen from "lightgallery/plugins/fullscreen"
|
||||
import "lightgallery/css/lightgallery-bundle.css"
|
||||
import { LightGallery } from "lightgallery/lightgallery"
|
||||
import { Search } from "./Search"
|
||||
|
||||
const ListLayout = lazy(() => import("./List"));
|
||||
const GridLayout = lazy(() => import("./Grid"));
|
||||
const ListLayout = lazy(() => import("./List"))
|
||||
const GridLayout = lazy(() => import("./Grid"))
|
||||
|
||||
const Folder = () => {
|
||||
const { rawLink } = useLink();
|
||||
const { rawLink } = useLink()
|
||||
const images = createMemo(() =>
|
||||
objStore.objs.filter((obj) => obj.type === ObjType.IMAGE)
|
||||
);
|
||||
let dynamicGallery: LightGallery | undefined;
|
||||
)
|
||||
let dynamicGallery: LightGallery | undefined
|
||||
createEffect(() => {
|
||||
dynamicGallery?.destroy();
|
||||
dynamicGallery?.destroy()
|
||||
if (images().length > 0) {
|
||||
dynamicGallery = lightGallery(document.createElement("div"), {
|
||||
dynamic: true,
|
||||
thumbnail: true,
|
||||
plugins: [lgZoom, lgThumbnail, lgRotate, lgAutoplay, lgFullscreen],
|
||||
dynamicEl: images().map((obj) => {
|
||||
const raw = rawLink(obj, true);
|
||||
const raw = rawLink(obj, true)
|
||||
return {
|
||||
src: raw,
|
||||
thumb: obj.thumb === "" ? raw : obj.thumb,
|
||||
subHtml: `<h4>${obj.name}</h4>`,
|
||||
};
|
||||
}),
|
||||
});
|
||||
}
|
||||
});
|
||||
}),
|
||||
})
|
||||
}
|
||||
})
|
||||
bus.on("gallery", (name) => {
|
||||
dynamicGallery?.openGallery(images().findIndex((obj) => obj.name === name));
|
||||
});
|
||||
dynamicGallery?.openGallery(images().findIndex((obj) => obj.name === name))
|
||||
})
|
||||
onCleanup(() => {
|
||||
bus.off("gallery");
|
||||
dynamicGallery?.destroy();
|
||||
});
|
||||
bus.off("gallery")
|
||||
dynamicGallery?.destroy()
|
||||
})
|
||||
return (
|
||||
<>
|
||||
<Show when={layout() === "list"} fallback={<GridLayout />}>
|
||||
@@ -59,7 +59,7 @@ const Folder = () => {
|
||||
<Search />
|
||||
<ContextMenu />
|
||||
</>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Folder;
|
||||
export default Folder
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Grid } from "@hope-ui/solid";
|
||||
import { For } from "solid-js";
|
||||
import { GridItem } from "./GridItem";
|
||||
import "lightgallery/css/lightgallery-bundle.css";
|
||||
import { objStore } from "~/store";
|
||||
import { Grid } from "@hope-ui/solid"
|
||||
import { For } from "solid-js"
|
||||
import { GridItem } from "./GridItem"
|
||||
import "lightgallery/css/lightgallery-bundle.css"
|
||||
import { objStore } from "~/store"
|
||||
|
||||
const GridLayout = () => {
|
||||
return (
|
||||
@@ -13,11 +13,11 @@ const GridLayout = () => {
|
||||
>
|
||||
<For each={objStore.objs}>
|
||||
{(obj, i) => {
|
||||
return <GridItem obj={obj} index={i()} />;
|
||||
return <GridItem obj={obj} index={i()} />
|
||||
}}
|
||||
</For>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default GridLayout;
|
||||
export default GridLayout
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Grid, Skeleton } from "@hope-ui/solid";
|
||||
import { For } from "solid-js";
|
||||
import { Grid, Skeleton } from "@hope-ui/solid"
|
||||
import { For } from "solid-js"
|
||||
|
||||
const GridSkeleton = () => {
|
||||
return (
|
||||
@@ -12,7 +12,7 @@ const GridSkeleton = () => {
|
||||
{() => <Skeleton w="$full" h="$28" rounded="$lg" />}
|
||||
</For>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default GridSkeleton;
|
||||
export default GridSkeleton
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Skeleton, VStack } from "@hope-ui/solid";
|
||||
import { For } from "solid-js";
|
||||
import { Skeleton, VStack } from "@hope-ui/solid"
|
||||
import { For } from "solid-js"
|
||||
|
||||
const ListSkeleton = () => {
|
||||
return (
|
||||
@@ -8,7 +8,7 @@ const ListSkeleton = () => {
|
||||
{() => <Skeleton rounded="$lg" w="$full" h="$8" />}
|
||||
</For>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default ListSkeleton;
|
||||
export default ListSkeleton
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { Menu, Item } from "solid-contextmenu";
|
||||
import { useCopyLink, useDownload, useT } from "~/hooks";
|
||||
import "solid-contextmenu/dist/style.css";
|
||||
import { HStack, Icon, Text, useColorMode } from "@hope-ui/solid";
|
||||
import { operations } from "../toolbar/operations";
|
||||
import { For } from "solid-js";
|
||||
import { bus, notify } from "~/utils";
|
||||
import { UserMethods, UserPermissions } from "~/types";
|
||||
import { getSettingBool, me } from "~/store";
|
||||
import { Menu, Item } from "solid-contextmenu"
|
||||
import { useCopyLink, useDownload, useT } from "~/hooks"
|
||||
import "solid-contextmenu/dist/style.css"
|
||||
import { HStack, Icon, Text, useColorMode } from "@hope-ui/solid"
|
||||
import { operations } from "../toolbar/operations"
|
||||
import { For } from "solid-js"
|
||||
import { bus, notify } from "~/utils"
|
||||
import { UserMethods, UserPermissions } from "~/types"
|
||||
import { getSettingBool, me } from "~/store"
|
||||
|
||||
const ItemContent = (props: { name: string }) => {
|
||||
const t = useT();
|
||||
const t = useT()
|
||||
return (
|
||||
<HStack spacing="$2">
|
||||
<Icon
|
||||
@@ -20,17 +20,17 @@ const ItemContent = (props: { name: string }) => {
|
||||
/>
|
||||
<Text>{t(`home.toolbar.${props.name}`)}</Text>
|
||||
</HStack>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export const ContextMenu = () => {
|
||||
const t = useT();
|
||||
const { colorMode } = useColorMode();
|
||||
const { copySelectedRawLink, copySelectedPreviewPage } = useCopyLink();
|
||||
const { batchDownloadSelected } = useDownload();
|
||||
const t = useT()
|
||||
const { colorMode } = useColorMode()
|
||||
const { copySelectedRawLink, copySelectedPreviewPage } = useCopyLink()
|
||||
const { batchDownloadSelected } = useDownload()
|
||||
const canPackageDownload = () => {
|
||||
return UserMethods.is_admin(me()) || getSettingBool("package_download");
|
||||
};
|
||||
return UserMethods.is_admin(me()) || getSettingBool("package_download")
|
||||
}
|
||||
return (
|
||||
<Menu
|
||||
id={1}
|
||||
@@ -41,11 +41,11 @@ export const ContextMenu = () => {
|
||||
{(name) => (
|
||||
<Item
|
||||
hidden={() => {
|
||||
const index = UserPermissions.findIndex((item) => item === name);
|
||||
return !UserMethods.can(me(), index);
|
||||
const index = UserPermissions.findIndex((item) => item === name)
|
||||
return !UserMethods.can(me(), index)
|
||||
}}
|
||||
onClick={() => {
|
||||
bus.emit("tool", name);
|
||||
bus.emit("tool", name)
|
||||
}}
|
||||
>
|
||||
<ItemContent name={name} />
|
||||
@@ -55,9 +55,9 @@ export const ContextMenu = () => {
|
||||
<Item
|
||||
onClick={({ props }) => {
|
||||
if (props.is_dir) {
|
||||
copySelectedPreviewPage();
|
||||
copySelectedPreviewPage()
|
||||
} else {
|
||||
copySelectedRawLink(true);
|
||||
copySelectedRawLink(true)
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -67,17 +67,17 @@ export const ContextMenu = () => {
|
||||
onClick={({ props }) => {
|
||||
if (props.is_dir) {
|
||||
if (!canPackageDownload()) {
|
||||
notify.warning(t("home.toolbar.package_download_disabled"));
|
||||
return;
|
||||
notify.warning(t("home.toolbar.package_download_disabled"))
|
||||
return
|
||||
}
|
||||
bus.emit("tool", "package_download");
|
||||
bus.emit("tool", "package_download")
|
||||
} else {
|
||||
batchDownloadSelected();
|
||||
batchDownloadSelected()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ItemContent name="download" />
|
||||
</Item>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
import "aplayer/dist/APlayer.min.css";
|
||||
import "./audio.css";
|
||||
import APlayer from "aplayer";
|
||||
import { Box } from "@hope-ui/solid";
|
||||
import { onCleanup, onMount } from "solid-js";
|
||||
import { useLink } from "~/hooks";
|
||||
import { getSetting, getSettingBool, objStore } from "~/store";
|
||||
import { ObjType, StoreObj } from "~/types";
|
||||
import { baseName } from "~/utils";
|
||||
import "aplayer/dist/APlayer.min.css"
|
||||
import "./audio.css"
|
||||
import APlayer from "aplayer"
|
||||
import { Box } from "@hope-ui/solid"
|
||||
import { onCleanup, onMount } from "solid-js"
|
||||
import { useLink } from "~/hooks"
|
||||
import { getSetting, getSettingBool, objStore } from "~/store"
|
||||
import { ObjType, StoreObj } from "~/types"
|
||||
import { baseName } from "~/utils"
|
||||
|
||||
const Preview = () => {
|
||||
const { proxyLink, rawLink } = useLink();
|
||||
let audios = objStore.objs.filter((obj) => obj.type === ObjType.AUDIO);
|
||||
const { proxyLink, rawLink } = useLink()
|
||||
let audios = objStore.objs.filter((obj) => obj.type === ObjType.AUDIO)
|
||||
if (audios.length === 0) {
|
||||
audios = [objStore.obj];
|
||||
audios = [objStore.obj]
|
||||
}
|
||||
let ap: any;
|
||||
let ap: any
|
||||
const objToAudio = (obj: StoreObj) => {
|
||||
let lrc = undefined;
|
||||
let lrc = undefined
|
||||
const lrcObj = objStore.objs.find((o) => {
|
||||
return baseName(o.name) === baseName(obj.name) && o.name.endsWith(".lrc");
|
||||
});
|
||||
return baseName(o.name) === baseName(obj.name) && o.name.endsWith(".lrc")
|
||||
})
|
||||
if (lrcObj) {
|
||||
lrc = proxyLink(lrcObj, true);
|
||||
lrc = proxyLink(lrcObj, true)
|
||||
}
|
||||
return {
|
||||
name: obj.name,
|
||||
@@ -31,8 +31,8 @@ const Preview = () => {
|
||||
getSetting("audio_cover") ||
|
||||
"https://jsd.nn.ci/gh/alist-org/logo@main/logo.svg",
|
||||
lrc: lrc,
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
onMount(() => {
|
||||
ap = new APlayer({
|
||||
container: document.querySelector("#audio-player"),
|
||||
@@ -46,16 +46,16 @@ const Preview = () => {
|
||||
listFolded: false,
|
||||
lrcType: 3,
|
||||
audio: audios.map(objToAudio),
|
||||
});
|
||||
const curIndex = audios.findIndex((obj) => obj.name === objStore.obj.name);
|
||||
})
|
||||
const curIndex = audios.findIndex((obj) => obj.name === objStore.obj.name)
|
||||
if (curIndex !== -1) {
|
||||
ap.list.switch(curIndex);
|
||||
ap.list.switch(curIndex)
|
||||
}
|
||||
});
|
||||
})
|
||||
onCleanup(() => {
|
||||
ap?.destroy();
|
||||
});
|
||||
return <Box w="$full" id="audio-player" />;
|
||||
};
|
||||
ap?.destroy()
|
||||
})
|
||||
return <Box w="$full" id="audio-player" />
|
||||
}
|
||||
|
||||
export default Preview;
|
||||
export default Preview
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Button, HStack } from "@hope-ui/solid";
|
||||
import { useCopyLink, useT } from "~/hooks";
|
||||
import { objStore } from "~/store";
|
||||
import { FileInfo } from "./info";
|
||||
import { OpenWith } from "../file/open-with";
|
||||
import { Show } from "solid-js";
|
||||
import { Button, HStack } from "@hope-ui/solid"
|
||||
import { useCopyLink, useT } from "~/hooks"
|
||||
import { objStore } from "~/store"
|
||||
import { FileInfo } from "./info"
|
||||
import { OpenWith } from "../file/open-with"
|
||||
import { Show } from "solid-js"
|
||||
|
||||
export const Download = (props: { openWith?: boolean }) => {
|
||||
const t = useT();
|
||||
const { copyCurrentRawLink } = useCopyLink();
|
||||
const t = useT()
|
||||
const { copyCurrentRawLink } = useCopyLink()
|
||||
return (
|
||||
<FileInfo>
|
||||
<HStack spacing="$2">
|
||||
@@ -22,7 +22,7 @@ export const Download = (props: { openWith?: boolean }) => {
|
||||
<OpenWith />
|
||||
</Show>
|
||||
</FileInfo>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Download;
|
||||
export default Download
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { hope } from "@hope-ui/solid";
|
||||
import { BoxWithFullScreen, MaybeLoading } from "~/components";
|
||||
import { useFetchText } from "~/hooks";
|
||||
import { hope } from "@hope-ui/solid"
|
||||
import { BoxWithFullScreen, MaybeLoading } from "~/components"
|
||||
import { useFetchText } from "~/hooks"
|
||||
|
||||
const HtmlPreview = () => {
|
||||
const [content] = useFetchText();
|
||||
const [content] = useFetchText()
|
||||
return (
|
||||
<MaybeLoading loading={content.loading}>
|
||||
<BoxWithFullScreen w="$full" h="70vh">
|
||||
@@ -16,7 +16,7 @@ const HtmlPreview = () => {
|
||||
/>
|
||||
</BoxWithFullScreen>
|
||||
</MaybeLoading>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default HtmlPreview;
|
||||
export default HtmlPreview
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { BoxWithFullScreen } from "~/components";
|
||||
import { objStore } from "~/store";
|
||||
import { hope } from "@hope-ui/solid";
|
||||
import { convertURL } from "~/utils";
|
||||
import { Component } from "solid-js";
|
||||
import { BoxWithFullScreen } from "~/components"
|
||||
import { objStore } from "~/store"
|
||||
import { hope } from "@hope-ui/solid"
|
||||
import { convertURL } from "~/utils"
|
||||
import { Component } from "solid-js"
|
||||
|
||||
const IframePreview = (props: { scheme: string }) => {
|
||||
return (
|
||||
@@ -13,11 +13,11 @@ const IframePreview = (props: { scheme: string }) => {
|
||||
src={convertURL(props.scheme, objStore.raw_url, objStore.obj.name)}
|
||||
/>
|
||||
</BoxWithFullScreen>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export const generateIframePreview = (scheme: string): Component => {
|
||||
return () => {
|
||||
return <IframePreview scheme={scheme} />;
|
||||
};
|
||||
};
|
||||
return <IframePreview scheme={scheme} />
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Error, FullLoading, ImageWithError } from "~/components";
|
||||
import { useT } from "~/hooks";
|
||||
import { objStore } from "~/store";
|
||||
import { Error, FullLoading, ImageWithError } from "~/components"
|
||||
import { useT } from "~/hooks"
|
||||
import { objStore } from "~/store"
|
||||
|
||||
const Preview = () => {
|
||||
const t = useT();
|
||||
const t = useT()
|
||||
return (
|
||||
<ImageWithError
|
||||
maxH="75vh"
|
||||
@@ -12,7 +12,7 @@ const Preview = () => {
|
||||
fallback={<FullLoading />}
|
||||
fallbackErr={<Error msg={t("home.preview.failed_load_img")} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Preview;
|
||||
export default Preview
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { Component, lazy } from "solid-js";
|
||||
import { getIframePreviews } from "~/store";
|
||||
import { Obj, ObjType } from "~/types";
|
||||
import { ext } from "~/utils";
|
||||
import { generateIframePreview } from "./iframe";
|
||||
import { Component, lazy } from "solid-js"
|
||||
import { getIframePreviews } from "~/store"
|
||||
import { Obj, ObjType } from "~/types"
|
||||
import { ext } from "~/utils"
|
||||
import { generateIframePreview } from "./iframe"
|
||||
|
||||
export interface Preview {
|
||||
name: string;
|
||||
type?: ObjType;
|
||||
exts?: string[] | "*";
|
||||
provider?: RegExp;
|
||||
component: Component;
|
||||
name: string
|
||||
type?: ObjType
|
||||
exts?: string[] | "*"
|
||||
provider?: RegExp
|
||||
component: Component
|
||||
}
|
||||
|
||||
export type PreviewComponent = Pick<Preview, "name" | "component">;
|
||||
export type PreviewComponent = Pick<Preview, "name" | "component">
|
||||
|
||||
const previews: Preview[] = [
|
||||
{
|
||||
@@ -61,37 +61,37 @@ const previews: Preview[] = [
|
||||
provider: /Aliyundrive/,
|
||||
component: lazy(() => import("./aliyun_office")),
|
||||
},
|
||||
];
|
||||
]
|
||||
|
||||
export const getPreviews = (
|
||||
file: Obj & { provider: string }
|
||||
): PreviewComponent[] => {
|
||||
const res: PreviewComponent[] = [];
|
||||
const res: PreviewComponent[] = []
|
||||
// internal previews
|
||||
previews.forEach((preview) => {
|
||||
if (preview.provider && !preview.provider.test(file.provider)) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
if (
|
||||
preview.type === file.type ||
|
||||
preview.exts === "*" ||
|
||||
preview.exts?.includes(ext(file.name).toLowerCase())
|
||||
) {
|
||||
res.push({ name: preview.name, component: preview.component });
|
||||
res.push({ name: preview.name, component: preview.component })
|
||||
}
|
||||
});
|
||||
})
|
||||
// iframe previews
|
||||
const iframePreviews = getIframePreviews(file.name);
|
||||
const iframePreviews = getIframePreviews(file.name)
|
||||
iframePreviews.forEach((preview) => {
|
||||
res.push({
|
||||
name: preview.key,
|
||||
component: generateIframePreview(preview.value),
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
// download page
|
||||
res.push({
|
||||
name: "Download",
|
||||
component: lazy(() => import("./download")),
|
||||
});
|
||||
return res;
|
||||
};
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Heading, Icon, Text, VStack } from "@hope-ui/solid";
|
||||
import { JSXElement } from "solid-js";
|
||||
import { getMainColor, objStore } from "~/store";
|
||||
import { formatDate, getFileSize } from "~/utils";
|
||||
import { getIconByObj } from "~/utils/icon";
|
||||
import { Heading, Icon, Text, VStack } from "@hope-ui/solid"
|
||||
import { JSXElement } from "solid-js"
|
||||
import { getMainColor, objStore } from "~/store"
|
||||
import { formatDate, getFileSize } from "~/utils"
|
||||
import { getIconByObj } from "~/utils/icon"
|
||||
|
||||
export const FileInfo = (props: { children: JSXElement }) => {
|
||||
return (
|
||||
@@ -27,5 +27,5 @@ export const FileInfo = (props: { children: JSXElement }) => {
|
||||
</VStack>
|
||||
<VStack spacing="$2">{props.children}</VStack>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Button } from "@hope-ui/solid";
|
||||
import { createSignal } from "solid-js";
|
||||
import { useT } from "~/hooks";
|
||||
import { objStore } from "~/store";
|
||||
import { api, baseName, safeBtoa } from "~/utils";
|
||||
import { FileInfo } from "./info";
|
||||
import { Button } from "@hope-ui/solid"
|
||||
import { createSignal } from "solid-js"
|
||||
import { useT } from "~/hooks"
|
||||
import { objStore } from "~/store"
|
||||
import { api, baseName, safeBtoa } from "~/utils"
|
||||
import { FileInfo } from "./info"
|
||||
|
||||
const Ipa = () => {
|
||||
const t = useT();
|
||||
const [installing, setInstalling] = createSignal(false);
|
||||
const t = useT()
|
||||
const [installing, setInstalling] = createSignal(false)
|
||||
return (
|
||||
<FileInfo>
|
||||
<Button
|
||||
@@ -21,13 +21,13 @@ const Ipa = () => {
|
||||
)}.plist`
|
||||
}
|
||||
onClick={() => {
|
||||
setInstalling(true);
|
||||
setInstalling(true)
|
||||
}}
|
||||
>
|
||||
{t(`home.preview.${installing() ? "installing" : "install"}`)}
|
||||
</Button>
|
||||
</FileInfo>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Ipa;
|
||||
export default Ipa
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Button } from "@hope-ui/solid";
|
||||
import { createSignal } from "solid-js";
|
||||
import { useT } from "~/hooks";
|
||||
import { objStore } from "~/store";
|
||||
import { FileInfo } from "./info";
|
||||
import { Button } from "@hope-ui/solid"
|
||||
import { createSignal } from "solid-js"
|
||||
import { useT } from "~/hooks"
|
||||
import { objStore } from "~/store"
|
||||
import { FileInfo } from "./info"
|
||||
|
||||
const Plist = () => {
|
||||
const t = useT();
|
||||
const [installing, setInstalling] = createSignal(false);
|
||||
const t = useT()
|
||||
const [installing, setInstalling] = createSignal(false)
|
||||
return (
|
||||
<FileInfo>
|
||||
<Button
|
||||
@@ -15,13 +15,13 @@ const Plist = () => {
|
||||
"itms-services://?action=download-manifest&url=" + objStore.raw_url
|
||||
}
|
||||
onClick={() => {
|
||||
setInstalling(true);
|
||||
setInstalling(true)
|
||||
}}
|
||||
>
|
||||
{t(`home.preview.${installing() ? "installing" : "install"}`)}
|
||||
</Button>
|
||||
</FileInfo>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Plist;
|
||||
export default Plist
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import { createDisclosure } from "@hope-ui/solid";
|
||||
import { ModalInput } from "~/components";
|
||||
import { useFetch, useRouter, useT } from "~/hooks";
|
||||
import { addAria2, bus, handleRespWithNotifySuccess } from "~/utils";
|
||||
import { onCleanup } from "solid-js";
|
||||
import { createDisclosure } from "@hope-ui/solid"
|
||||
import { ModalInput } from "~/components"
|
||||
import { useFetch, useRouter, useT } from "~/hooks"
|
||||
import { addAria2, bus, handleRespWithNotifySuccess } from "~/utils"
|
||||
import { onCleanup } from "solid-js"
|
||||
|
||||
export const Aria2 = () => {
|
||||
const t = useT();
|
||||
const { isOpen, onOpen, onClose } = createDisclosure();
|
||||
const [loading, ok] = useFetch(addAria2);
|
||||
const { pathname } = useRouter();
|
||||
const t = useT()
|
||||
const { isOpen, onOpen, onClose } = createDisclosure()
|
||||
const [loading, ok] = useFetch(addAria2)
|
||||
const { pathname } = useRouter()
|
||||
const handler = (name: string) => {
|
||||
if (name === "offline_download") {
|
||||
onOpen();
|
||||
onOpen()
|
||||
}
|
||||
};
|
||||
bus.on("tool", handler);
|
||||
}
|
||||
bus.on("tool", handler)
|
||||
onCleanup(() => {
|
||||
bus.off("tool", handler);
|
||||
});
|
||||
bus.off("tool", handler)
|
||||
})
|
||||
return (
|
||||
<ModalInput
|
||||
title="home.toolbar.offline_download"
|
||||
@@ -27,11 +27,11 @@ export const Aria2 = () => {
|
||||
loading={loading()}
|
||||
tips={t("home.toolbar.offline_download-tips")}
|
||||
onSubmit={async (urls) => {
|
||||
const resp = await ok(pathname(), urls.split("\n"));
|
||||
const resp = await ok(pathname(), urls.split("\n"))
|
||||
handleRespWithNotifySuccess(resp, () => {
|
||||
onClose();
|
||||
});
|
||||
onClose()
|
||||
})
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
import { Box, HStack, useColorModeValue } from "@hope-ui/solid";
|
||||
import { createMemo, For, Show } from "solid-js";
|
||||
import {
|
||||
checkboxOpen,
|
||||
haveSelected,
|
||||
objStore,
|
||||
selectAll,
|
||||
State,
|
||||
} from "~/store";
|
||||
import { CopyLink } from "./CopyLink";
|
||||
import { CenterIcon } from "./Icon";
|
||||
import { bus } from "~/utils";
|
||||
import { Download } from "./Download";
|
||||
import { Motion, Presence } from "@motionone/solid";
|
||||
import { Box, HStack, useColorModeValue } from "@hope-ui/solid"
|
||||
import { createMemo, For, Show } from "solid-js"
|
||||
import { checkboxOpen, haveSelected, objStore, selectAll, State } from "~/store"
|
||||
import { CopyLink } from "./CopyLink"
|
||||
import { CenterIcon } from "./Icon"
|
||||
import { bus } from "~/utils"
|
||||
import { Download } from "./Download"
|
||||
import { Motion, Presence } from "@motionone/solid"
|
||||
|
||||
export const Center = () => {
|
||||
const show = createMemo(
|
||||
@@ -19,7 +13,7 @@ export const Center = () => {
|
||||
[State.Folder, State.FetchingMore].includes(objStore.state) &&
|
||||
checkboxOpen() &&
|
||||
haveSelected()
|
||||
);
|
||||
)
|
||||
return (
|
||||
<Presence exitBeforeEnter>
|
||||
<Show when={show()}>
|
||||
@@ -53,10 +47,10 @@ export const Center = () => {
|
||||
<CenterIcon
|
||||
name={name}
|
||||
onClick={() => {
|
||||
bus.emit("tool", name);
|
||||
bus.emit("tool", name)
|
||||
}}
|
||||
/>
|
||||
);
|
||||
)
|
||||
}}
|
||||
</For>
|
||||
<CopyLink />
|
||||
@@ -64,12 +58,12 @@ export const Center = () => {
|
||||
<CenterIcon
|
||||
name="cancel_select"
|
||||
onClick={() => {
|
||||
selectAll(false);
|
||||
selectAll(false)
|
||||
}}
|
||||
/>
|
||||
</HStack>
|
||||
</Box>
|
||||
</Show>
|
||||
</Presence>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Menu, MenuTrigger, MenuContent, MenuItem } from "@hope-ui/solid";
|
||||
import { useT, useCopyLink } from "~/hooks";
|
||||
import { CenterIcon } from "./Icon";
|
||||
import { Menu, MenuTrigger, MenuContent, MenuItem } from "@hope-ui/solid"
|
||||
import { useT, useCopyLink } from "~/hooks"
|
||||
import { CenterIcon } from "./Icon"
|
||||
|
||||
export const CopyLink = () => {
|
||||
const t = useT();
|
||||
const { copySelectedPreviewPage, copySelectedRawLink } = useCopyLink();
|
||||
const colorScheme = "neutral";
|
||||
const t = useT()
|
||||
const { copySelectedPreviewPage, copySelectedRawLink } = useCopyLink()
|
||||
const colorScheme = "neutral"
|
||||
return (
|
||||
<Menu placement="top" offset={10}>
|
||||
<MenuTrigger as={CenterIcon} name="copy_link" />
|
||||
@@ -13,7 +13,7 @@ export const CopyLink = () => {
|
||||
<MenuItem
|
||||
colorScheme={colorScheme}
|
||||
onSelect={() => {
|
||||
copySelectedPreviewPage();
|
||||
copySelectedPreviewPage()
|
||||
}}
|
||||
>
|
||||
{t("home.toolbar.preview_page")}
|
||||
@@ -21,7 +21,7 @@ export const CopyLink = () => {
|
||||
<MenuItem
|
||||
colorScheme={colorScheme}
|
||||
onSelect={() => {
|
||||
copySelectedRawLink();
|
||||
copySelectedRawLink()
|
||||
}}
|
||||
>
|
||||
{t("home.toolbar.down_link")}
|
||||
@@ -29,12 +29,12 @@ export const CopyLink = () => {
|
||||
<MenuItem
|
||||
colorScheme={colorScheme}
|
||||
onSelect={() => {
|
||||
copySelectedRawLink(true);
|
||||
copySelectedRawLink(true)
|
||||
}}
|
||||
>
|
||||
{t("home.toolbar.encode_down_link")}
|
||||
</MenuItem>
|
||||
</MenuContent>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { createDisclosure } from "@hope-ui/solid";
|
||||
import { onCleanup } from "solid-js";
|
||||
import { ModalFolderChoose } from "~/components";
|
||||
import { useFetch, usePath, useRouter } from "~/hooks";
|
||||
import { selectedObjs } from "~/store";
|
||||
import { bus, fsCopy, fsMove, handleRespWithNotifySuccess } from "~/utils";
|
||||
import { createDisclosure } from "@hope-ui/solid"
|
||||
import { onCleanup } from "solid-js"
|
||||
import { ModalFolderChoose } from "~/components"
|
||||
import { useFetch, usePath, useRouter } from "~/hooks"
|
||||
import { selectedObjs } from "~/store"
|
||||
import { bus, fsCopy, fsMove, handleRespWithNotifySuccess } from "~/utils"
|
||||
|
||||
export const Copy = () => {
|
||||
const { isOpen, onOpen, onClose } = createDisclosure();
|
||||
const [loading, ok] = useFetch(fsCopy);
|
||||
const { pathname } = useRouter();
|
||||
const { refresh } = usePath();
|
||||
const { isOpen, onOpen, onClose } = createDisclosure()
|
||||
const [loading, ok] = useFetch(fsCopy)
|
||||
const { pathname } = useRouter()
|
||||
const { refresh } = usePath()
|
||||
const handler = (name: string) => {
|
||||
if (name === "copy") {
|
||||
onOpen();
|
||||
onOpen()
|
||||
}
|
||||
};
|
||||
bus.on("tool", handler);
|
||||
}
|
||||
bus.on("tool", handler)
|
||||
onCleanup(() => {
|
||||
bus.off("tool", handler);
|
||||
});
|
||||
bus.off("tool", handler)
|
||||
})
|
||||
return (
|
||||
<ModalFolderChoose
|
||||
opened={isOpen()}
|
||||
@@ -29,30 +29,30 @@ export const Copy = () => {
|
||||
pathname(),
|
||||
dst,
|
||||
selectedObjs().map((obj) => obj.name)
|
||||
);
|
||||
)
|
||||
handleRespWithNotifySuccess(resp, () => {
|
||||
refresh();
|
||||
onClose();
|
||||
});
|
||||
refresh()
|
||||
onClose()
|
||||
})
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export const Move = () => {
|
||||
const { isOpen, onOpen, onClose } = createDisclosure();
|
||||
const [loading, ok] = useFetch(fsMove);
|
||||
const { pathname } = useRouter();
|
||||
const { refresh } = usePath();
|
||||
const { isOpen, onOpen, onClose } = createDisclosure()
|
||||
const [loading, ok] = useFetch(fsMove)
|
||||
const { pathname } = useRouter()
|
||||
const { refresh } = usePath()
|
||||
const handler = (name: string) => {
|
||||
if (name === "move") {
|
||||
onOpen();
|
||||
onOpen()
|
||||
}
|
||||
};
|
||||
bus.on("tool", handler);
|
||||
}
|
||||
bus.on("tool", handler)
|
||||
onCleanup(() => {
|
||||
bus.off("tool", handler);
|
||||
});
|
||||
bus.off("tool", handler)
|
||||
})
|
||||
return (
|
||||
<ModalFolderChoose
|
||||
opened={isOpen()}
|
||||
@@ -63,16 +63,16 @@ export const Move = () => {
|
||||
pathname(),
|
||||
dst,
|
||||
selectedObjs().map((obj) => obj.name)
|
||||
);
|
||||
)
|
||||
handleRespWithNotifySuccess(resp, () => {
|
||||
refresh();
|
||||
onClose();
|
||||
});
|
||||
refresh()
|
||||
onClose()
|
||||
})
|
||||
}}
|
||||
/>
|
||||
// <CenterIcon tip="move" viewBox="0 0 1024 1024" fill="currentColor">
|
||||
// <path d="M840.704 256h-36.992c-82.624 0-82.496-128-140.864-128H311.232C245.44 128 192 181.44 192 247.296V384h64V247.296C256 216.832 280.832 192 311.232 192h339.456c3.968 6.144 9.024 15.36 12.672 22.208C684.8 253.76 720.704 320 803.712 320h36.992C869.12 320 896 351.104 896 384v392.768c0 30.4-24.832 55.232-55.296 55.232H311.232c-30.4 0-55.232-24.832-55.232-55.232V704h-64v72.768C192 842.624 245.44 896 311.232 896H840.64C906.56 896 960 842.624 960 776.768V384c0-65.856-53.44-128-119.296-128z"></path>
|
||||
// <path d="M497.344 693.824L630.4 563.968c0.128-0.128 0.192-0.32 0.32-0.512 2.816-2.816 5.184-9.536 6.784-13.248 1.344-3.456 1.856-0.64 2.112-4.096 0-0.768 0.384-1.408 0.384-2.112 0-0.512-0.256-0.896-0.256-1.344-0.192-3.84-0.896-5.76-2.24-9.344-1.344-3.264-3.52-6.016-5.76-8.64-0.512-0.64-0.768-1.536-1.344-2.112L497.344 389.632c-12.8-12.864-33.6-6.976-46.4 5.888-12.864 12.8-12.864 33.6 0 46.464l76.864 70.976-429.632 0.064c-18.752 0-33.984 12.8-33.92 30.912-0.064 18.112 15.168 29.696 33.984 29.696h429.632l-76.864 79.552c-12.864 12.864-12.864 33.6 0 46.528 6.4 6.4 14.72 3.776 23.168 3.776s16.832-3.328 23.168-9.664z"></path>
|
||||
// </CenterIcon>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,27 +7,27 @@ import {
|
||||
ModalFooter,
|
||||
Button,
|
||||
createDisclosure,
|
||||
} from "@hope-ui/solid";
|
||||
import { onCleanup } from "solid-js";
|
||||
import { useFetch, usePath, useRouter, useT } from "~/hooks";
|
||||
import { selectedObjs } from "~/store";
|
||||
import { bus, fsRemove, handleRespWithNotifySuccess } from "~/utils";
|
||||
} from "@hope-ui/solid"
|
||||
import { onCleanup } from "solid-js"
|
||||
import { useFetch, usePath, useRouter, useT } from "~/hooks"
|
||||
import { selectedObjs } from "~/store"
|
||||
import { bus, fsRemove, handleRespWithNotifySuccess } from "~/utils"
|
||||
|
||||
export const Delete = () => {
|
||||
const t = useT();
|
||||
const { isOpen, onOpen, onClose } = createDisclosure();
|
||||
const [loading, ok] = useFetch(fsRemove);
|
||||
const { refresh } = usePath();
|
||||
const { pathname } = useRouter();
|
||||
const t = useT()
|
||||
const { isOpen, onOpen, onClose } = createDisclosure()
|
||||
const [loading, ok] = useFetch(fsRemove)
|
||||
const { refresh } = usePath()
|
||||
const { pathname } = useRouter()
|
||||
const handler = (name: string) => {
|
||||
if (name === "delete") {
|
||||
onOpen();
|
||||
onOpen()
|
||||
}
|
||||
};
|
||||
bus.on("tool", handler);
|
||||
}
|
||||
bus.on("tool", handler)
|
||||
onCleanup(() => {
|
||||
bus.off("tool", handler);
|
||||
});
|
||||
bus.off("tool", handler)
|
||||
})
|
||||
return (
|
||||
<Modal
|
||||
blockScrollOnMount={false}
|
||||
@@ -55,11 +55,11 @@ export const Delete = () => {
|
||||
const resp = await ok(
|
||||
pathname(),
|
||||
selectedObjs().map((obj) => obj.name)
|
||||
);
|
||||
)
|
||||
handleRespWithNotifySuccess(resp, () => {
|
||||
refresh();
|
||||
onClose();
|
||||
});
|
||||
refresh()
|
||||
onClose()
|
||||
})
|
||||
}}
|
||||
>
|
||||
{t("global.confirm")}
|
||||
@@ -67,5 +67,5 @@ export const Delete = () => {
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,19 +11,19 @@ import {
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
createDisclosure,
|
||||
} from "@hope-ui/solid";
|
||||
import { createSignal, lazy, onCleanup, Show, Suspense } from "solid-js";
|
||||
import { FullLoading } from "~/components";
|
||||
import { useT, useDownload } from "~/hooks";
|
||||
import { getSettingBool, me } from "~/store";
|
||||
import { UserMethods } from "~/types";
|
||||
import { bus } from "~/utils";
|
||||
import { CenterIcon } from "./Icon";
|
||||
} from "@hope-ui/solid"
|
||||
import { createSignal, lazy, onCleanup, Show, Suspense } from "solid-js"
|
||||
import { FullLoading } from "~/components"
|
||||
import { useT, useDownload } from "~/hooks"
|
||||
import { getSettingBool, me } from "~/store"
|
||||
import { UserMethods } from "~/types"
|
||||
import { bus } from "~/utils"
|
||||
import { CenterIcon } from "./Icon"
|
||||
|
||||
export const Download = () => {
|
||||
const t = useT();
|
||||
const colorScheme = "neutral";
|
||||
const { batchDownloadSelected, sendToAria2 } = useDownload();
|
||||
const t = useT()
|
||||
const colorScheme = "neutral"
|
||||
const { batchDownloadSelected, sendToAria2 } = useDownload()
|
||||
return (
|
||||
<Menu placement="top" offset={10}>
|
||||
<MenuTrigger as={CenterIcon} name="download" />
|
||||
@@ -39,7 +39,7 @@ export const Download = () => {
|
||||
<MenuItem
|
||||
colorScheme={colorScheme}
|
||||
onSelect={() => {
|
||||
bus.emit("tool", "package_download");
|
||||
bus.emit("tool", "package_download")
|
||||
}}
|
||||
>
|
||||
{t("home.toolbar.package_download")}
|
||||
@@ -50,24 +50,24 @@ export const Download = () => {
|
||||
</MenuItem>
|
||||
</MenuContent>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
const PackageDownload = lazy(() => import("./PackageDownload"));
|
||||
const PackageDownload = lazy(() => import("./PackageDownload"))
|
||||
|
||||
export const PackageDownloadModal = () => {
|
||||
const t = useT();
|
||||
const t = useT()
|
||||
const handler = (name: string) => {
|
||||
if (name === "package_download") {
|
||||
onOpen();
|
||||
onOpen()
|
||||
}
|
||||
};
|
||||
bus.on("tool", handler);
|
||||
}
|
||||
bus.on("tool", handler)
|
||||
onCleanup(() => {
|
||||
bus.off("tool", handler);
|
||||
});
|
||||
const { isOpen, onOpen, onClose } = createDisclosure();
|
||||
const [show, setShow] = createSignal("pre_tips");
|
||||
bus.off("tool", handler)
|
||||
})
|
||||
const { isOpen, onOpen, onClose } = createDisclosure()
|
||||
const [show, setShow] = createSignal("pre_tips")
|
||||
return (
|
||||
<Modal
|
||||
blockScrollOnMount={false}
|
||||
@@ -98,7 +98,7 @@ export const PackageDownloadModal = () => {
|
||||
<Button
|
||||
colorScheme="info"
|
||||
onClick={() => {
|
||||
setShow("package_download");
|
||||
setShow("package_download")
|
||||
}}
|
||||
>
|
||||
{t("global.confirm")}
|
||||
@@ -108,5 +108,5 @@ export const PackageDownloadModal = () => {
|
||||
</Suspense>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { ElementType, Icon, IconProps, Tooltip } from "@hope-ui/solid";
|
||||
import { IconTypes } from "solid-icons";
|
||||
import { useT } from "~/hooks";
|
||||
import { getMainColor, me } from "~/store";
|
||||
import { UserMethods, UserPermissions } from "~/types";
|
||||
import { hoverColor } from "~/utils";
|
||||
import { operations } from "./operations";
|
||||
import { ElementType, Icon, IconProps, Tooltip } from "@hope-ui/solid"
|
||||
import { IconTypes } from "solid-icons"
|
||||
import { useT } from "~/hooks"
|
||||
import { getMainColor, me } from "~/store"
|
||||
import { UserMethods, UserPermissions } from "~/types"
|
||||
import { hoverColor } from "~/utils"
|
||||
import { operations } from "./operations"
|
||||
|
||||
export const CenterIcon = <C extends ElementType = "svg">(
|
||||
props: IconProps<C> & {
|
||||
name: string;
|
||||
name: string
|
||||
}
|
||||
) => {
|
||||
const index = UserPermissions.findIndex((p) => p === props.name);
|
||||
if (index !== -1 && !UserMethods.can(me(), index)) return null;
|
||||
const t = useT();
|
||||
const index = UserPermissions.findIndex((p) => p === props.name)
|
||||
if (index !== -1 && !UserMethods.can(me(), index)) return null
|
||||
const t = useT()
|
||||
return (
|
||||
<Tooltip placement="top" withArrow label={t(`home.toolbar.${props.name}`)}>
|
||||
<Icon
|
||||
@@ -37,16 +37,16 @@ export const CenterIcon = <C extends ElementType = "svg">(
|
||||
{...props}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export const RightIcon = <C extends ElementType = "svg">(
|
||||
props: IconProps<C> & {
|
||||
tips?: string;
|
||||
icon?: IconTypes;
|
||||
tips?: string
|
||||
icon?: IconTypes
|
||||
}
|
||||
) => {
|
||||
const t = useT();
|
||||
const t = useT()
|
||||
return (
|
||||
<Tooltip
|
||||
disabled={!props.tips}
|
||||
@@ -76,8 +76,8 @@ export const RightIcon = <C extends ElementType = "svg">(
|
||||
{...props}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
// export const ToolIcon = <C extends ElementType = "button">(
|
||||
// props: IconButtonProps<C>
|
||||
|
||||
@@ -12,40 +12,40 @@ import {
|
||||
HStack,
|
||||
Input,
|
||||
VStack,
|
||||
} from "@hope-ui/solid";
|
||||
import { For, onCleanup } from "solid-js";
|
||||
import { SwitchLanguageWhite, SwitchColorMode } from "~/components";
|
||||
import { useT } from "~/hooks";
|
||||
import { initialLocalSettings, local, setLocal } from "~/store";
|
||||
import { bus } from "~/utils";
|
||||
} from "@hope-ui/solid"
|
||||
import { For, onCleanup } from "solid-js"
|
||||
import { SwitchLanguageWhite, SwitchColorMode } from "~/components"
|
||||
import { useT } from "~/hooks"
|
||||
import { initialLocalSettings, local, setLocal } from "~/store"
|
||||
import { bus } from "~/utils"
|
||||
|
||||
const LocalSettingsInput = (props: { name: string }) => {
|
||||
const t = useT();
|
||||
const t = useT()
|
||||
return (
|
||||
<FormControl>
|
||||
<FormLabel>{t(`home.local_settings.${props.name}`)}</FormLabel>
|
||||
<Input
|
||||
value={local[props.name]}
|
||||
onInput={(e) => {
|
||||
setLocal(props.name, e.currentTarget.value);
|
||||
setLocal(props.name, e.currentTarget.value)
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export const LocalSettings = () => {
|
||||
const { isOpen, onOpen, onClose } = createDisclosure();
|
||||
const t = useT();
|
||||
const { isOpen, onOpen, onClose } = createDisclosure()
|
||||
const t = useT()
|
||||
const handler = (name: string) => {
|
||||
if (name === "local_settings") {
|
||||
onOpen();
|
||||
onOpen()
|
||||
}
|
||||
};
|
||||
bus.on("tool", handler);
|
||||
}
|
||||
bus.on("tool", handler)
|
||||
onCleanup(() => {
|
||||
bus.off("tool", handler);
|
||||
});
|
||||
bus.off("tool", handler)
|
||||
})
|
||||
return (
|
||||
<Drawer opened={isOpen()} placement="right" onClose={onClose}>
|
||||
<DrawerOverlay />
|
||||
@@ -69,5 +69,5 @@ export const LocalSettings = () => {
|
||||
</DrawerBody>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import { createDisclosure } from "@hope-ui/solid";
|
||||
import { ModalInput } from "~/components";
|
||||
import { useFetch, usePath, useRouter } from "~/hooks";
|
||||
import { bus, fsMkdir, handleRespWithNotifySuccess, pathJoin } from "~/utils";
|
||||
import { onCleanup } from "solid-js";
|
||||
import { createDisclosure } from "@hope-ui/solid"
|
||||
import { ModalInput } from "~/components"
|
||||
import { useFetch, usePath, useRouter } from "~/hooks"
|
||||
import { bus, fsMkdir, handleRespWithNotifySuccess, pathJoin } from "~/utils"
|
||||
import { onCleanup } from "solid-js"
|
||||
|
||||
export const Mkdir = () => {
|
||||
const { isOpen, onOpen, onClose } = createDisclosure();
|
||||
const [loading, ok] = useFetch(fsMkdir);
|
||||
const { pathname } = useRouter();
|
||||
const { refresh } = usePath();
|
||||
const { isOpen, onOpen, onClose } = createDisclosure()
|
||||
const [loading, ok] = useFetch(fsMkdir)
|
||||
const { pathname } = useRouter()
|
||||
const { refresh } = usePath()
|
||||
const handler = (name: string) => {
|
||||
if (name === "mkdir") {
|
||||
onOpen();
|
||||
onOpen()
|
||||
}
|
||||
};
|
||||
bus.on("tool", handler);
|
||||
}
|
||||
bus.on("tool", handler)
|
||||
onCleanup(() => {
|
||||
bus.off("tool", handler);
|
||||
});
|
||||
bus.off("tool", handler)
|
||||
})
|
||||
return (
|
||||
<ModalInput
|
||||
title="home.toolbar.input_dir_name"
|
||||
@@ -25,12 +25,12 @@ export const Mkdir = () => {
|
||||
onClose={onClose}
|
||||
loading={loading()}
|
||||
onSubmit={async (name) => {
|
||||
const resp = await ok(pathJoin(pathname(), name));
|
||||
const resp = await ok(pathJoin(pathname(), name))
|
||||
handleRespWithNotifySuccess(resp, () => {
|
||||
refresh();
|
||||
onClose();
|
||||
});
|
||||
refresh()
|
||||
onClose()
|
||||
})
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,29 +6,29 @@ import {
|
||||
ModalOverlay,
|
||||
createDisclosure,
|
||||
ModalCloseButton,
|
||||
} from "@hope-ui/solid";
|
||||
import { JSXElement, onCleanup, Show, Suspense } from "solid-js";
|
||||
import { FullLoading } from "~/components";
|
||||
import { useT } from "~/hooks";
|
||||
import { bus } from "~/utils";
|
||||
} from "@hope-ui/solid"
|
||||
import { JSXElement, onCleanup, Show, Suspense } from "solid-js"
|
||||
import { FullLoading } from "~/components"
|
||||
import { useT } from "~/hooks"
|
||||
import { bus } from "~/utils"
|
||||
|
||||
export const ModalWrapper = (props: {
|
||||
children: JSXElement;
|
||||
name: string;
|
||||
title: string;
|
||||
blockScrollOnMount?: boolean;
|
||||
children: JSXElement
|
||||
name: string
|
||||
title: string
|
||||
blockScrollOnMount?: boolean
|
||||
}) => {
|
||||
const t = useT();
|
||||
const t = useT()
|
||||
const handler = (name: string) => {
|
||||
if (name === props.name) {
|
||||
onOpen();
|
||||
onOpen()
|
||||
}
|
||||
};
|
||||
bus.on("tool", handler);
|
||||
}
|
||||
bus.on("tool", handler)
|
||||
onCleanup(() => {
|
||||
bus.off("tool", handler);
|
||||
});
|
||||
const { isOpen, onOpen, onClose } = createDisclosure();
|
||||
bus.off("tool", handler)
|
||||
})
|
||||
const { isOpen, onOpen, onClose } = createDisclosure()
|
||||
return (
|
||||
<Modal
|
||||
blockScrollOnMount={props.blockScrollOnMount}
|
||||
@@ -55,5 +55,5 @@ export const ModalWrapper = (props: {
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,29 +1,24 @@
|
||||
import { createDisclosure } from "@hope-ui/solid";
|
||||
import { onCleanup } from "solid-js";
|
||||
import { ModalInput } from "~/components";
|
||||
import { useFetch, usePath, useRouter } from "~/hooks";
|
||||
import { password } from "~/store";
|
||||
import {
|
||||
bus,
|
||||
fsNewFile,
|
||||
handleRespWithNotifySuccess,
|
||||
pathJoin,
|
||||
} from "~/utils";
|
||||
import { createDisclosure } from "@hope-ui/solid"
|
||||
import { onCleanup } from "solid-js"
|
||||
import { ModalInput } from "~/components"
|
||||
import { useFetch, usePath, useRouter } from "~/hooks"
|
||||
import { password } from "~/store"
|
||||
import { bus, fsNewFile, handleRespWithNotifySuccess, pathJoin } from "~/utils"
|
||||
|
||||
export const NewFile = () => {
|
||||
const { isOpen, onOpen, onClose } = createDisclosure();
|
||||
const [loading, ok] = useFetch(fsNewFile);
|
||||
const { refresh } = usePath();
|
||||
const { pathname } = useRouter();
|
||||
const { isOpen, onOpen, onClose } = createDisclosure()
|
||||
const [loading, ok] = useFetch(fsNewFile)
|
||||
const { refresh } = usePath()
|
||||
const { pathname } = useRouter()
|
||||
const handler = (name: string) => {
|
||||
if (name === "new_file") {
|
||||
onOpen();
|
||||
onOpen()
|
||||
}
|
||||
};
|
||||
bus.on("tool", handler);
|
||||
}
|
||||
bus.on("tool", handler)
|
||||
onCleanup(() => {
|
||||
bus.off("tool", handler);
|
||||
});
|
||||
bus.off("tool", handler)
|
||||
})
|
||||
return (
|
||||
<ModalInput
|
||||
title="home.toolbar.input_filename"
|
||||
@@ -31,12 +26,12 @@ export const NewFile = () => {
|
||||
onClose={onClose}
|
||||
loading={loading()}
|
||||
onSubmit={async (name) => {
|
||||
const resp = await ok(pathJoin(pathname(), name), password());
|
||||
const resp = await ok(pathJoin(pathname(), name), password())
|
||||
handleRespWithNotifySuccess(resp, () => {
|
||||
refresh();
|
||||
onClose();
|
||||
});
|
||||
refresh()
|
||||
onClose()
|
||||
})
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import { createDisclosure } from "@hope-ui/solid";
|
||||
import { onCleanup, Show } from "solid-js";
|
||||
import { ModalInput } from "~/components";
|
||||
import { useFetch, usePath, useRouter, useT } from "~/hooks";
|
||||
import { oneChecked, selectedObjs } from "~/store";
|
||||
import { createDisclosure } from "@hope-ui/solid"
|
||||
import { onCleanup, Show } from "solid-js"
|
||||
import { ModalInput } from "~/components"
|
||||
import { useFetch, usePath, useRouter, useT } from "~/hooks"
|
||||
import { oneChecked, selectedObjs } from "~/store"
|
||||
import {
|
||||
bus,
|
||||
fsRename,
|
||||
handleRespWithNotifySuccess,
|
||||
notify,
|
||||
pathJoin,
|
||||
} from "~/utils";
|
||||
} from "~/utils"
|
||||
|
||||
export const Rename = () => {
|
||||
const { isOpen, onOpen, onClose } = createDisclosure();
|
||||
const t = useT();
|
||||
const [loading, ok] = useFetch(fsRename);
|
||||
const { pathname } = useRouter();
|
||||
const { refresh } = usePath();
|
||||
const { isOpen, onOpen, onClose } = createDisclosure()
|
||||
const t = useT()
|
||||
const [loading, ok] = useFetch(fsRename)
|
||||
const { pathname } = useRouter()
|
||||
const { refresh } = usePath()
|
||||
const handler = (name: string) => {
|
||||
if (name === "rename") {
|
||||
if (!oneChecked()) {
|
||||
notify.warning(t("home.toolbar.only_one-tips"));
|
||||
return;
|
||||
notify.warning(t("home.toolbar.only_one-tips"))
|
||||
return
|
||||
}
|
||||
onOpen();
|
||||
onOpen()
|
||||
}
|
||||
};
|
||||
bus.on("tool", handler);
|
||||
}
|
||||
bus.on("tool", handler)
|
||||
onCleanup(() => {
|
||||
bus.off("tool", handler);
|
||||
});
|
||||
bus.off("tool", handler)
|
||||
})
|
||||
return (
|
||||
<Show when={isOpen()}>
|
||||
<ModalInput
|
||||
@@ -42,13 +42,13 @@ export const Rename = () => {
|
||||
const resp = await ok(
|
||||
pathJoin(pathname(), selectedObjs()[0].name),
|
||||
name
|
||||
);
|
||||
)
|
||||
handleRespWithNotifySuccess(resp, () => {
|
||||
refresh();
|
||||
onClose();
|
||||
});
|
||||
refresh()
|
||||
onClose()
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,29 +3,29 @@ import {
|
||||
createDisclosure,
|
||||
useColorModeValue,
|
||||
VStack,
|
||||
} from "@hope-ui/solid";
|
||||
import { createMemo, Show } from "solid-js";
|
||||
import { RightIcon } from "./Icon";
|
||||
import { CgMoreO } from "solid-icons/cg";
|
||||
import { TbCheckbox } from "solid-icons/tb";
|
||||
import { objStore, State, toggleCheckbox, userCan } from "~/store";
|
||||
import { bus } from "~/utils";
|
||||
import { operations } from "./operations";
|
||||
import { IoMagnetOutline } from "solid-icons/io";
|
||||
import { AiOutlineCloudUpload, AiOutlineSetting } from "solid-icons/ai";
|
||||
import { RiSystemRefreshLine } from "solid-icons/ri";
|
||||
import { usePath } from "~/hooks";
|
||||
import { Motion } from "@motionone/solid";
|
||||
} from "@hope-ui/solid"
|
||||
import { createMemo, Show } from "solid-js"
|
||||
import { RightIcon } from "./Icon"
|
||||
import { CgMoreO } from "solid-icons/cg"
|
||||
import { TbCheckbox } from "solid-icons/tb"
|
||||
import { objStore, State, toggleCheckbox, userCan } from "~/store"
|
||||
import { bus } from "~/utils"
|
||||
import { operations } from "./operations"
|
||||
import { IoMagnetOutline } from "solid-icons/io"
|
||||
import { AiOutlineCloudUpload, AiOutlineSetting } from "solid-icons/ai"
|
||||
import { RiSystemRefreshLine } from "solid-icons/ri"
|
||||
import { usePath } from "~/hooks"
|
||||
import { Motion } from "@motionone/solid"
|
||||
|
||||
export const Right = () => {
|
||||
const { isOpen, onToggle } = createDisclosure({
|
||||
defaultIsOpen: localStorage.getItem("more-open") === "true",
|
||||
onClose: () => localStorage.setItem("more-open", "false"),
|
||||
onOpen: () => localStorage.setItem("more-open", "true"),
|
||||
});
|
||||
const margin = createMemo(() => (isOpen() ? "$4" : "$5"));
|
||||
const isFolder = createMemo(() => objStore.state === State.Folder);
|
||||
const { refresh } = usePath();
|
||||
})
|
||||
const margin = createMemo(() => (isOpen() ? "$4" : "$5"))
|
||||
const isFolder = createMemo(() => objStore.state === State.Folder)
|
||||
const { refresh } = usePath()
|
||||
return (
|
||||
<Box
|
||||
class="left-toolbar-box"
|
||||
@@ -40,7 +40,7 @@ export const Right = () => {
|
||||
class="toolbar-toggle"
|
||||
as={CgMoreO}
|
||||
onClick={() => {
|
||||
onToggle();
|
||||
onToggle()
|
||||
}}
|
||||
/>
|
||||
}
|
||||
@@ -67,14 +67,14 @@ export const Right = () => {
|
||||
as={RiSystemRefreshLine}
|
||||
tips="refresh"
|
||||
onClick={() => {
|
||||
refresh(undefined, true);
|
||||
refresh(undefined, true)
|
||||
}}
|
||||
/>
|
||||
<RightIcon
|
||||
as={operations.new_file.icon}
|
||||
tips="new_file"
|
||||
onClick={() => {
|
||||
bus.emit("tool", "new_file");
|
||||
bus.emit("tool", "new_file")
|
||||
}}
|
||||
/>
|
||||
<RightIcon
|
||||
@@ -82,14 +82,14 @@ export const Right = () => {
|
||||
p="$1_5"
|
||||
tips="mkdir"
|
||||
onClick={() => {
|
||||
bus.emit("tool", "mkdir");
|
||||
bus.emit("tool", "mkdir")
|
||||
}}
|
||||
/>
|
||||
<RightIcon
|
||||
as={AiOutlineCloudUpload}
|
||||
tips="upload"
|
||||
onClick={() => {
|
||||
bus.emit("tool", "upload");
|
||||
bus.emit("tool", "upload")
|
||||
}}
|
||||
/>
|
||||
</Show>
|
||||
@@ -99,7 +99,7 @@ export const Right = () => {
|
||||
pl="0"
|
||||
tips="offline_download"
|
||||
onClick={() => {
|
||||
bus.emit("tool", "offline_download");
|
||||
bus.emit("tool", "offline_download")
|
||||
}}
|
||||
/>
|
||||
</Show>
|
||||
@@ -112,7 +112,7 @@ export const Right = () => {
|
||||
as={AiOutlineSetting}
|
||||
tips="local_settings"
|
||||
onClick={() => {
|
||||
bus.emit("tool", "local_settings");
|
||||
bus.emit("tool", "local_settings")
|
||||
}}
|
||||
/>
|
||||
</VStack>
|
||||
@@ -120,5 +120,5 @@ export const Right = () => {
|
||||
</VStack>
|
||||
</Show>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { Portal } from "solid-js/web";
|
||||
import { Center } from "./Center";
|
||||
import { Right } from "./Right";
|
||||
import { Copy, Move } from "./CopyMove";
|
||||
import { Delete } from "./Delete";
|
||||
import { Rename } from "./Rename";
|
||||
import { NewFile } from "./NewFile";
|
||||
import { Mkdir } from "./Mkdir";
|
||||
import { Aria2 } from "./Aria2";
|
||||
import { PackageDownloadModal } from "./Download";
|
||||
import { lazy } from "solid-js";
|
||||
import { ModalWrapper } from "./ModalWrapper";
|
||||
import { LocalSettings } from "./LocalSettings";
|
||||
const Upload = lazy(() => import("../uploads/Upload"));
|
||||
import { Portal } from "solid-js/web"
|
||||
import { Center } from "./Center"
|
||||
import { Right } from "./Right"
|
||||
import { Copy, Move } from "./CopyMove"
|
||||
import { Delete } from "./Delete"
|
||||
import { Rename } from "./Rename"
|
||||
import { NewFile } from "./NewFile"
|
||||
import { Mkdir } from "./Mkdir"
|
||||
import { Aria2 } from "./Aria2"
|
||||
import { PackageDownloadModal } from "./Download"
|
||||
import { lazy } from "solid-js"
|
||||
import { ModalWrapper } from "./ModalWrapper"
|
||||
import { LocalSettings } from "./LocalSettings"
|
||||
const Upload = lazy(() => import("../uploads/Upload"))
|
||||
|
||||
export const Modal = () => {
|
||||
return (
|
||||
@@ -29,8 +29,8 @@ export const Modal = () => {
|
||||
</ModalWrapper>
|
||||
<LocalSettings />
|
||||
</>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export const Toolbar = () => {
|
||||
return (
|
||||
@@ -39,5 +39,5 @@ export const Toolbar = () => {
|
||||
<Center />
|
||||
<Modal />
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { IconTypes } from "solid-icons";
|
||||
import { TiDeleteOutline } from "solid-icons/ti";
|
||||
import { CgRename } from "solid-icons/cg";
|
||||
import { TbFileArrowRight } from "solid-icons/tb";
|
||||
import { TbCopy, TbLink } from "solid-icons/tb";
|
||||
import { AiTwotoneDelete } from "solid-icons/ai";
|
||||
import { CgFileAdd, CgFolderAdd } from "solid-icons/cg";
|
||||
import { AiOutlineCloudDownload } from "solid-icons/ai";
|
||||
import { IconTypes } from "solid-icons"
|
||||
import { TiDeleteOutline } from "solid-icons/ti"
|
||||
import { CgRename } from "solid-icons/cg"
|
||||
import { TbFileArrowRight } from "solid-icons/tb"
|
||||
import { TbCopy, TbLink } from "solid-icons/tb"
|
||||
import { AiTwotoneDelete } from "solid-icons/ai"
|
||||
import { CgFileAdd, CgFolderAdd } from "solid-icons/cg"
|
||||
import { AiOutlineCloudDownload } from "solid-icons/ai"
|
||||
|
||||
interface Operations {
|
||||
[key: string]: {
|
||||
icon: IconTypes;
|
||||
color?: string;
|
||||
p?: boolean;
|
||||
};
|
||||
icon: IconTypes
|
||||
color?: string
|
||||
p?: boolean
|
||||
}
|
||||
}
|
||||
export const operations: Operations = {
|
||||
rename: { icon: CgRename, color: "$accent9" },
|
||||
@@ -24,7 +24,7 @@ export const operations: Operations = {
|
||||
new_file: { icon: CgFileAdd, p: true },
|
||||
cancel_select: { icon: TiDeleteOutline },
|
||||
download: { icon: AiOutlineCloudDownload, color: "$primary9" },
|
||||
};
|
||||
}
|
||||
// interface Operation {
|
||||
// label: string;
|
||||
// icon: IconTypes;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { mergeProps } from "solid-js";
|
||||
import { mergeProps } from "solid-js"
|
||||
|
||||
interface Props {
|
||||
/** 过渡的开始颜色 */
|
||||
startColor?: string;
|
||||
startColor?: string
|
||||
/** 过渡的结束颜色 */
|
||||
endColor?: string;
|
||||
endColor?: string
|
||||
}
|
||||
|
||||
const CornerBottom = (props: Props) => {
|
||||
@@ -14,7 +14,7 @@ const CornerBottom = (props: Props) => {
|
||||
endColor: "#120fc4",
|
||||
},
|
||||
props
|
||||
);
|
||||
)
|
||||
return (
|
||||
<svg
|
||||
version="1.1"
|
||||
@@ -43,7 +43,7 @@ const CornerBottom = (props: Props) => {
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default CornerBottom;
|
||||
export default CornerBottom
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { mergeProps } from "solid-js";
|
||||
import { mergeProps } from "solid-js"
|
||||
|
||||
interface Props {
|
||||
/** 过渡的开始颜色 */
|
||||
startColor?: string;
|
||||
startColor?: string
|
||||
/** 过渡的结束颜色 */
|
||||
endColor?: string;
|
||||
endColor?: string
|
||||
}
|
||||
|
||||
const CornerTop = (props: Props) => {
|
||||
@@ -14,7 +14,7 @@ const CornerTop = (props: Props) => {
|
||||
endColor: "#120fc4",
|
||||
},
|
||||
props
|
||||
);
|
||||
)
|
||||
return (
|
||||
<svg height="1337" width="1337">
|
||||
<defs>
|
||||
@@ -43,7 +43,7 @@ const CornerTop = (props: Props) => {
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default CornerTop;
|
||||
export default CornerTop
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Box, useColorModeValue } from "@hope-ui/solid";
|
||||
import CornerBottom from "./CornerBottom";
|
||||
import CornerTop from "./CornerTop";
|
||||
import { Box, useColorModeValue } from "@hope-ui/solid"
|
||||
import CornerBottom from "./CornerBottom"
|
||||
import CornerTop from "./CornerTop"
|
||||
|
||||
const LoginBg = () => {
|
||||
const bgColor = useColorModeValue("#a9c6ff", "#062b74");
|
||||
const bgColor = useColorModeValue("#a9c6ff", "#062b74")
|
||||
return (
|
||||
<Box
|
||||
bgColor={bgColor()}
|
||||
@@ -42,7 +42,7 @@ const LoginBg = () => {
|
||||
<CornerBottom />
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default LoginBg;
|
||||
export default LoginBg
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { createResource } from "solid-js";
|
||||
import { Markdown, MaybeLoading } from "~/components";
|
||||
import { createResource } from "solid-js"
|
||||
import { Markdown, MaybeLoading } from "~/components"
|
||||
|
||||
const fetchReadme = async () =>
|
||||
await (
|
||||
await fetch("https://jsd.nn.ci/gh/alist-org/alist@main/README.md")
|
||||
).text();
|
||||
).text()
|
||||
|
||||
const About = () => {
|
||||
const [readme] = createResource(fetchReadme);
|
||||
const [readme] = createResource(fetchReadme)
|
||||
return (
|
||||
<MaybeLoading loading={readme.loading}>
|
||||
<Markdown children={readme()} />
|
||||
</MaybeLoading>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default About;
|
||||
export default About
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Center, Heading } from "@hope-ui/solid";
|
||||
import { useManageTitle } from "~/hooks";
|
||||
import { Center, Heading } from "@hope-ui/solid"
|
||||
import { useManageTitle } from "~/hooks"
|
||||
|
||||
const Dashboard = () => {
|
||||
useManageTitle("manage.sidemenu.dashboard");
|
||||
useManageTitle("manage.sidemenu.dashboard")
|
||||
return (
|
||||
<Center h="$full">
|
||||
<Heading>Dashboard</Heading>
|
||||
</Center>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Dashboard;
|
||||
export default Dashboard
|
||||
|
||||
@@ -13,19 +13,19 @@ import {
|
||||
HStack,
|
||||
IconButton,
|
||||
useColorModeValue,
|
||||
} from "@hope-ui/solid";
|
||||
import { TiThMenu } from "solid-icons/ti";
|
||||
import { IoExit } from "solid-icons/io";
|
||||
import { SwitchColorMode, SwitchLanguageWhite } from "~/components";
|
||||
import { useRouter, useT } from "~/hooks";
|
||||
import { SideMenu } from "./SideMenu";
|
||||
import { side_menu_items } from "./sidemenu_items";
|
||||
import { changeToken, notify } from "~/utils";
|
||||
const { isOpen, onOpen, onClose } = createDisclosure();
|
||||
} from "@hope-ui/solid"
|
||||
import { TiThMenu } from "solid-icons/ti"
|
||||
import { IoExit } from "solid-icons/io"
|
||||
import { SwitchColorMode, SwitchLanguageWhite } from "~/components"
|
||||
import { useRouter, useT } from "~/hooks"
|
||||
import { SideMenu } from "./SideMenu"
|
||||
import { side_menu_items } from "./sidemenu_items"
|
||||
import { changeToken, notify } from "~/utils"
|
||||
const { isOpen, onOpen, onClose } = createDisclosure()
|
||||
|
||||
const Header = () => {
|
||||
const t = useT();
|
||||
const { to } = useRouter();
|
||||
const t = useT()
|
||||
const { to } = useRouter()
|
||||
return (
|
||||
<Box
|
||||
as="header"
|
||||
@@ -54,7 +54,7 @@ const Header = () => {
|
||||
color="$info9"
|
||||
cursor="pointer"
|
||||
onClick={() => {
|
||||
to("/@manage");
|
||||
to("/@manage")
|
||||
}}
|
||||
>
|
||||
{t("manage.title")}
|
||||
@@ -65,9 +65,9 @@ const Header = () => {
|
||||
aria-label="logout"
|
||||
icon={<IoExit />}
|
||||
onClick={() => {
|
||||
changeToken();
|
||||
notify.success(t("manage.logout_success"));
|
||||
to(`/@login?redirect=${encodeURIComponent(location.pathname)}`);
|
||||
changeToken()
|
||||
notify.success(t("manage.logout_success"))
|
||||
to(`/@login?redirect=${encodeURIComponent(location.pathname)}`)
|
||||
}}
|
||||
size="sm"
|
||||
/>
|
||||
@@ -90,7 +90,7 @@ const Header = () => {
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export { Header, onClose };
|
||||
export { Header, onClose }
|
||||
|
||||
@@ -1,36 +1,33 @@
|
||||
import { Box, Flex, Heading, HStack, Icon, VStack } from "@hope-ui/solid";
|
||||
import { createMemo, createSignal, For, Match, Show, Switch } from "solid-js";
|
||||
import { useRouter, useT } from "~/hooks";
|
||||
import { BiSolidRightArrow } from "solid-icons/bi";
|
||||
import { onClose } from "./Header";
|
||||
import { UserMethods, UserRole } from "~/types";
|
||||
import { me } from "~/store";
|
||||
import { AnchorWithBase } from "~/components";
|
||||
import { Link } from "@solidjs/router";
|
||||
import { hoverColor } from "~/utils";
|
||||
import { IconTypes } from "solid-icons";
|
||||
import { Box, Flex, Heading, HStack, Icon, VStack } from "@hope-ui/solid"
|
||||
import { createMemo, createSignal, For, Match, Show, Switch } from "solid-js"
|
||||
import { useRouter, useT } from "~/hooks"
|
||||
import { BiSolidRightArrow } from "solid-icons/bi"
|
||||
import { onClose } from "./Header"
|
||||
import { UserMethods, UserRole } from "~/types"
|
||||
import { me } from "~/store"
|
||||
import { AnchorWithBase } from "~/components"
|
||||
import { Link } from "@solidjs/router"
|
||||
import { hoverColor } from "~/utils"
|
||||
import { IconTypes } from "solid-icons"
|
||||
|
||||
export interface SideMenuItemProps {
|
||||
title: string;
|
||||
to: string;
|
||||
icon?: IconTypes;
|
||||
children?: SideMenuItemProps[];
|
||||
role?: number;
|
||||
external?: true;
|
||||
title: string
|
||||
to: string
|
||||
icon?: IconTypes
|
||||
children?: SideMenuItemProps[]
|
||||
role?: number
|
||||
external?: true
|
||||
}
|
||||
|
||||
const SideMenuItem = (props: SideMenuItemProps) => {
|
||||
const ifShow = createMemo(() => {
|
||||
if (!UserMethods.is_admin(me())) {
|
||||
if (props.role === undefined) return false;
|
||||
else if (
|
||||
props.role === UserRole.GENERAL &&
|
||||
!UserMethods.is_general(me())
|
||||
)
|
||||
return false;
|
||||
if (props.role === undefined) return false
|
||||
else if (props.role === UserRole.GENERAL && !UserMethods.is_general(me()))
|
||||
return false
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return true
|
||||
})
|
||||
return (
|
||||
<Switch fallback={<SideMenuItemWithTo {...props} />}>
|
||||
<Match when={!ifShow()}>{null}</Match>
|
||||
@@ -38,13 +35,13 @@ const SideMenuItem = (props: SideMenuItemProps) => {
|
||||
<SideMenuItemWithChildren {...props} />
|
||||
</Match>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
const SideMenuItemWithTo = (props: SideMenuItemProps) => {
|
||||
const { pathname } = useRouter();
|
||||
const t = useT();
|
||||
const isActive = () => pathname() === props.to;
|
||||
const { pathname } = useRouter()
|
||||
const t = useT()
|
||||
const isActive = () => pathname() === props.to
|
||||
return (
|
||||
<AnchorWithBase
|
||||
display="flex"
|
||||
@@ -52,7 +49,7 @@ const SideMenuItemWithTo = (props: SideMenuItemProps) => {
|
||||
href={props.to}
|
||||
onClick={() => {
|
||||
// to(props.to!);
|
||||
onClose();
|
||||
onClose()
|
||||
}}
|
||||
w="$full"
|
||||
alignItems="center"
|
||||
@@ -72,19 +69,19 @@ const SideMenuItemWithTo = (props: SideMenuItemProps) => {
|
||||
<Show when={props.icon}>{<Icon mr="$2" as={props.icon} />}</Show>
|
||||
<Heading>{t(props.title)}</Heading>
|
||||
</AnchorWithBase>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
const SideMenuItemWithChildren = (props: SideMenuItemProps) => {
|
||||
const { pathname } = useRouter();
|
||||
const [open, setOpen] = createSignal(pathname().includes(props.to));
|
||||
const t = useT();
|
||||
const { pathname } = useRouter()
|
||||
const [open, setOpen] = createSignal(pathname().includes(props.to))
|
||||
const t = useT()
|
||||
return (
|
||||
<Box w="$full">
|
||||
<Flex
|
||||
justifyContent="space-between"
|
||||
onClick={() => {
|
||||
setOpen(!open());
|
||||
setOpen(!open())
|
||||
}}
|
||||
w="$full"
|
||||
alignItems="center"
|
||||
@@ -112,17 +109,17 @@ const SideMenuItemWithChildren = (props: SideMenuItemProps) => {
|
||||
</Box>
|
||||
</Show>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export const SideMenu = (props: { items: SideMenuItemProps[] }) => {
|
||||
return (
|
||||
<VStack p="$2" w="$full" color="$neutral11" spacing="$1">
|
||||
<For each={props.items}>
|
||||
{(item) => {
|
||||
return <SideMenuItem {...item} />;
|
||||
return <SideMenuItem {...item} />
|
||||
}}
|
||||
</For>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,16 +7,16 @@ import {
|
||||
PopoverHeader,
|
||||
PopoverBody,
|
||||
HStack,
|
||||
} from "@hope-ui/solid";
|
||||
import { useT } from "~/hooks";
|
||||
} from "@hope-ui/solid"
|
||||
import { useT } from "~/hooks"
|
||||
|
||||
export interface DeletePopoverProps {
|
||||
name: string;
|
||||
loading: boolean;
|
||||
onClick: () => void;
|
||||
name: string
|
||||
loading: boolean
|
||||
onClick: () => void
|
||||
}
|
||||
export const DeletePopover = (props: DeletePopoverProps) => {
|
||||
const t = useT();
|
||||
const t = useT()
|
||||
return (
|
||||
<Popover>
|
||||
{({ onClose }) => (
|
||||
@@ -49,5 +49,5 @@ export const DeletePopover = (props: DeletePopoverProps) => {
|
||||
</>
|
||||
)}
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Grid } from "@hope-ui/solid";
|
||||
import { JSXElement } from "solid-js";
|
||||
import { Grid } from "@hope-ui/solid"
|
||||
import { JSXElement } from "solid-js"
|
||||
|
||||
export const ResponsiveGrid = (props: { children: JSXElement }) => {
|
||||
return (
|
||||
@@ -13,5 +13,5 @@ export const ResponsiveGrid = (props: { children: JSXElement }) => {
|
||||
>
|
||||
{props.children}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
import { Box, Center, Flex, HStack, useColorModeValue } from "@hope-ui/solid";
|
||||
import {
|
||||
FullLoading,
|
||||
SwitchColorMode,
|
||||
SwitchLanguageWhite,
|
||||
} from "~/components";
|
||||
import { useT, useTitle } from "~/hooks";
|
||||
import { Header } from "./Header";
|
||||
import { SideMenu } from "./SideMenu";
|
||||
import { side_menu_items } from "./sidemenu_items";
|
||||
import { Route, Routes } from "@solidjs/router";
|
||||
import { For, Suspense } from "solid-js";
|
||||
import { routes } from "./routes";
|
||||
import { Box, Center, Flex, HStack, useColorModeValue } from "@hope-ui/solid"
|
||||
import { FullLoading, SwitchColorMode, SwitchLanguageWhite } from "~/components"
|
||||
import { useT, useTitle } from "~/hooks"
|
||||
import { Header } from "./Header"
|
||||
import { SideMenu } from "./SideMenu"
|
||||
import { side_menu_items } from "./sidemenu_items"
|
||||
import { Route, Routes } from "@solidjs/router"
|
||||
import { For, Suspense } from "solid-js"
|
||||
import { routes } from "./routes"
|
||||
|
||||
const Manage = () => {
|
||||
const t = useT();
|
||||
useTitle(() => t("manage.title"));
|
||||
const t = useT()
|
||||
useTitle(() => t("manage.title"))
|
||||
return (
|
||||
<Box
|
||||
css={{
|
||||
@@ -52,14 +48,14 @@ const Manage = () => {
|
||||
<Routes>
|
||||
<For each={routes}>
|
||||
{(route) => {
|
||||
return <Route path={route.to!} component={route.component} />;
|
||||
return <Route path={route.to!} component={route.component} />
|
||||
}}
|
||||
</For>
|
||||
</Routes>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Manage;
|
||||
export default Manage
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Message } from "./Messenger";
|
||||
import { Heading, Image } from "@hope-ui/solid";
|
||||
import { Message } from "./Messenger"
|
||||
import { Heading, Image } from "@hope-ui/solid"
|
||||
|
||||
export const StringShow = (props: Message) => {
|
||||
return <Heading>{props.content}</Heading>;
|
||||
};
|
||||
return <Heading>{props.content}</Heading>
|
||||
}
|
||||
|
||||
export const ImageShow = (props: Message) => {
|
||||
return <Image src={props.content} />;
|
||||
};
|
||||
return <Image src={props.content} />
|
||||
}
|
||||
|
||||
@@ -9,35 +9,35 @@ import {
|
||||
Thead,
|
||||
Tr,
|
||||
VStack,
|
||||
} from "@hope-ui/solid";
|
||||
import { createSignal, For } from "solid-js";
|
||||
} from "@hope-ui/solid"
|
||||
import { createSignal, For } from "solid-js"
|
||||
import {
|
||||
useFetch,
|
||||
useListFetch,
|
||||
useManageTitle,
|
||||
useRouter,
|
||||
useT,
|
||||
} from "~/hooks";
|
||||
import { handleResp, notify, r } from "~/utils";
|
||||
import { Meta, PageResp } from "~/types";
|
||||
import { DeletePopover } from "../common/DeletePopover";
|
||||
import { Wether } from "~/components";
|
||||
} from "~/hooks"
|
||||
import { handleResp, notify, r } from "~/utils"
|
||||
import { Meta, PageResp } from "~/types"
|
||||
import { DeletePopover } from "../common/DeletePopover"
|
||||
import { Wether } from "~/components"
|
||||
|
||||
const Metas = () => {
|
||||
const t = useT();
|
||||
useManageTitle("manage.sidemenu.metas");
|
||||
const { to } = useRouter();
|
||||
const [getMetasLoading, getMetas] = useFetch(() => r.get("/admin/meta/list"));
|
||||
const [metas, setMetas] = createSignal<Meta[]>([]);
|
||||
const t = useT()
|
||||
useManageTitle("manage.sidemenu.metas")
|
||||
const { to } = useRouter()
|
||||
const [getMetasLoading, getMetas] = useFetch(() => r.get("/admin/meta/list"))
|
||||
const [metas, setMetas] = createSignal<Meta[]>([])
|
||||
const refresh = async () => {
|
||||
const resp: PageResp<Meta> = await getMetas();
|
||||
handleResp(resp, (data) => setMetas(data.content));
|
||||
};
|
||||
refresh();
|
||||
const resp: PageResp<Meta> = await getMetas()
|
||||
handleResp(resp, (data) => setMetas(data.content))
|
||||
}
|
||||
refresh()
|
||||
|
||||
const [deleting, deleteMeta] = useListFetch((id: number) =>
|
||||
r.post(`/admin/meta/delete?id=${id}`)
|
||||
);
|
||||
)
|
||||
return (
|
||||
<VStack spacing="$2" alignItems="start" w="$full">
|
||||
<HStack spacing="$2">
|
||||
@@ -50,7 +50,7 @@ const Metas = () => {
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
to("/@manage/metas/add");
|
||||
to("/@manage/metas/add")
|
||||
}}
|
||||
>
|
||||
{t("global.add")}
|
||||
@@ -80,7 +80,7 @@ const Metas = () => {
|
||||
<HStack spacing="$2">
|
||||
<Button
|
||||
onClick={() => {
|
||||
to(`/@manage/metas/edit/${meta.id}`);
|
||||
to(`/@manage/metas/edit/${meta.id}`)
|
||||
}}
|
||||
>
|
||||
{t("global.edit")}
|
||||
@@ -89,11 +89,11 @@ const Metas = () => {
|
||||
name={meta.path}
|
||||
loading={deleting() === meta.id}
|
||||
onClick={async () => {
|
||||
const resp = await deleteMeta(meta.id);
|
||||
const resp = await deleteMeta(meta.id)
|
||||
handleResp(resp, () => {
|
||||
notify.success(t("global.delete_success"));
|
||||
refresh();
|
||||
});
|
||||
notify.success(t("global.delete_success"))
|
||||
refresh()
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</HStack>
|
||||
@@ -105,7 +105,7 @@ const Metas = () => {
|
||||
</Table>
|
||||
</Box>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Metas;
|
||||
export default Metas
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { lazy } from "solid-js";
|
||||
import { Center, Heading } from "@hope-ui/solid";
|
||||
import { trimLeft } from "~/utils";
|
||||
import { SideMenuItem, side_menu_items } from "./sidemenu_items";
|
||||
import { useManageTitle } from "~/hooks";
|
||||
import { lazy } from "solid-js"
|
||||
import { Center, Heading } from "@hope-ui/solid"
|
||||
import { trimLeft } from "~/utils"
|
||||
import { SideMenuItem, side_menu_items } from "./sidemenu_items"
|
||||
import { useManageTitle } from "~/hooks"
|
||||
|
||||
type Route = Pick<SideMenuItem, "to" | "component">;
|
||||
type Route = Pick<SideMenuItem, "to" | "component">
|
||||
|
||||
const hide_routes: Route[] = [
|
||||
{
|
||||
@@ -39,32 +39,32 @@ const hide_routes: Route[] = [
|
||||
to: "/messenger",
|
||||
component: lazy(() => import("./messenger/Messenger")),
|
||||
},
|
||||
];
|
||||
]
|
||||
|
||||
const Placeholder = (props: { title: string; to: string }) => {
|
||||
useManageTitle(props.title);
|
||||
useManageTitle(props.title)
|
||||
return (
|
||||
<Center h="$full">
|
||||
<Heading>{props.title}</Heading>
|
||||
</Center>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
const get_routes = (items: SideMenuItem[], acc: Route[] = []) => {
|
||||
items.forEach((item) => {
|
||||
if (item.children) {
|
||||
get_routes(item.children, acc);
|
||||
get_routes(item.children, acc)
|
||||
} else {
|
||||
acc.push({
|
||||
to: trimLeft(item.to!, "/@manage"),
|
||||
component:
|
||||
item.component ||
|
||||
(() => <Placeholder title={item.title} to={item.to || "empty"} />),
|
||||
});
|
||||
})
|
||||
}
|
||||
});
|
||||
return acc;
|
||||
};
|
||||
})
|
||||
return acc
|
||||
}
|
||||
|
||||
const routes = get_routes(side_menu_items).concat(hide_routes);
|
||||
export { routes };
|
||||
const routes = get_routes(side_menu_items).concat(hide_routes)
|
||||
export { routes }
|
||||
|
||||
@@ -16,36 +16,36 @@ import {
|
||||
SelectValue,
|
||||
Switch as HopeSwitch,
|
||||
Textarea,
|
||||
} from "@hope-ui/solid";
|
||||
import { For, Match, Show, Switch } from "solid-js";
|
||||
import { useT } from "~/hooks";
|
||||
import { DriverItem, Type } from "~/types";
|
||||
} from "@hope-ui/solid"
|
||||
import { For, Match, Show, Switch } from "solid-js"
|
||||
import { useT } from "~/hooks"
|
||||
import { DriverItem, Type } from "~/types"
|
||||
|
||||
export type ItemProps = DriverItem & {
|
||||
readonly?: boolean;
|
||||
full_name_path?: string;
|
||||
options_prefix?: string;
|
||||
driver?: string;
|
||||
readonly?: boolean
|
||||
full_name_path?: string
|
||||
options_prefix?: string
|
||||
driver?: string
|
||||
} & (
|
||||
| {
|
||||
type: Type.Bool;
|
||||
onChange?: (value: boolean) => void;
|
||||
value: boolean;
|
||||
type: Type.Bool
|
||||
onChange?: (value: boolean) => void
|
||||
value: boolean
|
||||
}
|
||||
| {
|
||||
type: Type.Number;
|
||||
onChange?: (value: number) => void;
|
||||
value: number;
|
||||
type: Type.Number
|
||||
onChange?: (value: number) => void
|
||||
value: number
|
||||
}
|
||||
| {
|
||||
type: Type.String | Type.Text | Type.Select;
|
||||
onChange?: (value: string) => void;
|
||||
value: string;
|
||||
type: Type.String | Type.Text | Type.Select
|
||||
onChange?: (value: string) => void
|
||||
value: string
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
const Item = (props: ItemProps) => {
|
||||
const t = useT();
|
||||
const t = useT()
|
||||
return (
|
||||
<FormControl
|
||||
w="$full"
|
||||
@@ -159,7 +159,7 @@ const Item = (props: ItemProps) => {
|
||||
</FormHelperText>
|
||||
</Show>
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export { Item };
|
||||
export { Item }
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import { Button, Grid, HStack, VStack } from "@hope-ui/solid"
|
||||
import { createSignal, For } from "solid-js"
|
||||
import {
|
||||
useFetch,
|
||||
useManageTitle,
|
||||
useRouter,
|
||||
useT,
|
||||
} from "~/hooks"
|
||||
import { useFetch, useManageTitle, useRouter, useT } from "~/hooks"
|
||||
import { handleResp, r } from "~/utils"
|
||||
import { PageResp, Storage } from "~/types"
|
||||
import { StorageC } from "./Storage"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { VStack } from "@hope-ui/solid";
|
||||
import { useManageTitle } from "~/hooks";
|
||||
import { TypeTasks } from "./Tasks";
|
||||
import { VStack } from "@hope-ui/solid"
|
||||
import { useManageTitle } from "~/hooks"
|
||||
import { TypeTasks } from "./Tasks"
|
||||
|
||||
const Aria2 = () => {
|
||||
useManageTitle("manage.sidemenu.aria2");
|
||||
useManageTitle("manage.sidemenu.aria2")
|
||||
return (
|
||||
<VStack w="$full" alignItems="start" spacing="$4">
|
||||
<TypeTasks type="down" />
|
||||
<TypeTasks type="transfer" />
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Aria2;
|
||||
export default Aria2
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useManageTitle } from "~/hooks";
|
||||
import { TypeTasks } from "./Tasks";
|
||||
import { useManageTitle } from "~/hooks"
|
||||
import { TypeTasks } from "./Tasks"
|
||||
|
||||
const Copy = () => {
|
||||
useManageTitle("manage.sidemenu.copy");
|
||||
return <TypeTasks type="copy" />;
|
||||
};
|
||||
useManageTitle("manage.sidemenu.copy")
|
||||
return <TypeTasks type="copy" />
|
||||
}
|
||||
|
||||
export default Copy;
|
||||
export default Copy
|
||||
|
||||
@@ -11,13 +11,7 @@ import {
|
||||
import { MaybeLoading, FolderChooseInput } from "~/components"
|
||||
import { useFetch, useRouter, useT } from "~/hooks"
|
||||
import { handleResp, notify, r } from "~/utils"
|
||||
import {
|
||||
PEmptyResp,
|
||||
PResp,
|
||||
User,
|
||||
UserMethods,
|
||||
UserPermissions,
|
||||
} from "~/types"
|
||||
import { PEmptyResp, PResp, User, UserMethods, UserPermissions } from "~/types"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { For } from "solid-js"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Box, VStack } from "@hope-ui/solid";
|
||||
import Upload from "~/pages/home/uploads/Upload";
|
||||
import { Box, VStack } from "@hope-ui/solid"
|
||||
import Upload from "~/pages/home/uploads/Upload"
|
||||
|
||||
const Index = () => {
|
||||
return (
|
||||
@@ -8,7 +8,7 @@ const Index = () => {
|
||||
<Upload />
|
||||
</Box>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default Index;
|
||||
export default Index
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
export const keyPressed: Record<string, boolean> = {};
|
||||
export const keyPressed: Record<string, boolean> = {}
|
||||
document.addEventListener("keydown", (e) => {
|
||||
keyPressed[e.key] = true;
|
||||
});
|
||||
keyPressed[e.key] = true
|
||||
})
|
||||
document.addEventListener("keyup", (e) => {
|
||||
// keyPressed[e.key] = false;
|
||||
delete keyPressed[e.key];
|
||||
});
|
||||
delete keyPressed[e.key]
|
||||
})
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { createLocalStorage } from "@solid-primitives/storage";
|
||||
import { createLocalStorage } from "@solid-primitives/storage"
|
||||
|
||||
const [local, setLocal, { remove, clear, toJSON }] = createLocalStorage();
|
||||
const [local, setLocal, { remove, clear, toJSON }] = createLocalStorage()
|
||||
export function isValidKey(
|
||||
key: string | number | symbol,
|
||||
object: object
|
||||
): key is keyof typeof object {
|
||||
return key in object;
|
||||
return key in object
|
||||
}
|
||||
|
||||
export const initialLocalSettings = {
|
||||
aria2_rpc_url: "http://localhost:6800/jsonrpc",
|
||||
aria2_rpc_secret: "",
|
||||
// aria2_dir: "alist",
|
||||
};
|
||||
}
|
||||
for (const key in initialLocalSettings) {
|
||||
if (!local[key] && isValidKey(key, initialLocalSettings)) {
|
||||
setLocal(key, initialLocalSettings[key]);
|
||||
setLocal(key, initialLocalSettings[key])
|
||||
}
|
||||
}
|
||||
|
||||
export { local, setLocal, remove, clear, toJSON };
|
||||
export { local, setLocal, remove, clear, toJSON }
|
||||
|
||||
150
src/store/obj.ts
150
src/store/obj.ts
@@ -1,9 +1,9 @@
|
||||
import { cookieStorage, createStorageSignal } from "@solid-primitives/storage";
|
||||
import { createSignal } from "solid-js";
|
||||
import { createStore, produce } from "solid-js/store";
|
||||
import { Obj, StoreObj } from "~/types";
|
||||
import { log } from "~/utils";
|
||||
import { keyPressed } from "./key-event";
|
||||
import { cookieStorage, createStorageSignal } from "@solid-primitives/storage"
|
||||
import { createSignal } from "solid-js"
|
||||
import { createStore, produce } from "solid-js/store"
|
||||
import { Obj, StoreObj } from "~/types"
|
||||
import { log } from "~/utils"
|
||||
import { keyPressed } from "./key-event"
|
||||
|
||||
export enum State {
|
||||
Initial, // Initial state
|
||||
@@ -16,20 +16,20 @@ export enum State {
|
||||
}
|
||||
|
||||
const [objStore, setObjStore] = createStore<{
|
||||
obj: Obj;
|
||||
raw_url: string;
|
||||
related: Obj[];
|
||||
obj: Obj
|
||||
raw_url: string
|
||||
related: Obj[]
|
||||
|
||||
objs: StoreObj[];
|
||||
total: number;
|
||||
write?: boolean;
|
||||
objs: StoreObj[]
|
||||
total: number
|
||||
write?: boolean
|
||||
|
||||
readme: string;
|
||||
provider: string;
|
||||
readme: string
|
||||
provider: string
|
||||
// pageIndex: number;
|
||||
// pageSize: number;
|
||||
state: State;
|
||||
err: string;
|
||||
state: State
|
||||
err: string
|
||||
}>({
|
||||
obj: {} as Obj,
|
||||
raw_url: "",
|
||||
@@ -44,30 +44,30 @@ const [objStore, setObjStore] = createStore<{
|
||||
// pageSize: 50,
|
||||
state: State.Initial,
|
||||
err: "",
|
||||
});
|
||||
})
|
||||
|
||||
const [selectedNum, setSelectedNum] = createSignal(0);
|
||||
const [selectedNum, setSelectedNum] = createSignal(0)
|
||||
|
||||
const setObjs = (objs: Obj[]) => {
|
||||
setSelectedNum(0);
|
||||
lastChecked = { index: -1, selected: false };
|
||||
setObjStore("objs", objs);
|
||||
setObjStore("obj", "is_dir", true);
|
||||
};
|
||||
setSelectedNum(0)
|
||||
lastChecked = { index: -1, selected: false }
|
||||
setObjStore("objs", objs)
|
||||
setObjStore("obj", "is_dir", true)
|
||||
}
|
||||
|
||||
export const ObjStore = {
|
||||
setObj: (obj: Obj) => {
|
||||
setObjStore("obj", obj);
|
||||
setObjStore("obj", obj)
|
||||
},
|
||||
setRawUrl: (raw_url: string) => {
|
||||
setObjStore("raw_url", raw_url);
|
||||
setObjStore("raw_url", raw_url)
|
||||
},
|
||||
setProvider: (provider: string) => {
|
||||
setObjStore("provider", provider);
|
||||
setObjStore("provider", provider)
|
||||
},
|
||||
setObjs: setObjs,
|
||||
setTotal: (total: number) => {
|
||||
setObjStore("total", total);
|
||||
setObjStore("total", total)
|
||||
},
|
||||
setReadme: (readme: string) => setObjStore("readme", readme),
|
||||
setRelated: (related: Obj[]) => setObjStore("related", related),
|
||||
@@ -84,35 +84,35 @@ export const ObjStore = {
|
||||
// },
|
||||
setState: (state: State) => setObjStore("state", state),
|
||||
setErr: (err: string) => setObjStore("err", err),
|
||||
};
|
||||
}
|
||||
|
||||
export type OrderBy = "name" | "size" | "modified";
|
||||
export type OrderBy = "name" | "size" | "modified"
|
||||
|
||||
export const sortObjs = (orderBy: OrderBy, reverse?: boolean) => {
|
||||
log("sort:", orderBy, reverse);
|
||||
log("sort:", orderBy, reverse)
|
||||
setObjStore(
|
||||
"objs",
|
||||
produce((objs) =>
|
||||
objs.sort((a, b) => {
|
||||
if (a[orderBy] < b[orderBy]) return reverse ? 1 : -1;
|
||||
if (a[orderBy] > b[orderBy]) return reverse ? -1 : 1;
|
||||
return 0;
|
||||
if (a[orderBy] < b[orderBy]) return reverse ? 1 : -1
|
||||
if (a[orderBy] > b[orderBy]) return reverse ? -1 : 1
|
||||
return 0
|
||||
})
|
||||
)
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export const appendObjs = (objs: Obj[]) => {
|
||||
setObjStore(
|
||||
"objs",
|
||||
produce((prev) => prev.push(...objs))
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
let lastChecked = {
|
||||
index: -1,
|
||||
selected: false,
|
||||
};
|
||||
}
|
||||
|
||||
export const selectIndex = (index: number, checked: boolean, one?: boolean) => {
|
||||
if (
|
||||
@@ -120,80 +120,80 @@ export const selectIndex = (index: number, checked: boolean, one?: boolean) => {
|
||||
lastChecked.index !== -1 &&
|
||||
lastChecked.selected === checked
|
||||
) {
|
||||
const start = Math.min(lastChecked.index, index);
|
||||
const end = Math.max(lastChecked.index, index);
|
||||
const start = Math.min(lastChecked.index, index)
|
||||
const end = Math.max(lastChecked.index, index)
|
||||
const curCheckedNum = objStore.objs
|
||||
.slice(start, end + 1)
|
||||
.filter((o) => o.selected).length;
|
||||
.filter((o) => o.selected).length
|
||||
|
||||
setObjStore("objs", { from: start, to: end }, () => ({
|
||||
selected: checked,
|
||||
}));
|
||||
}))
|
||||
// update selected num
|
||||
const newSelectedNum =
|
||||
selectedNum() - curCheckedNum + (checked ? end - start + 1 : 0);
|
||||
setSelectedNum(newSelectedNum);
|
||||
selectedNum() - curCheckedNum + (checked ? end - start + 1 : 0)
|
||||
setSelectedNum(newSelectedNum)
|
||||
} else {
|
||||
setObjStore(
|
||||
"objs",
|
||||
index,
|
||||
produce((obj) => {
|
||||
if (obj.selected !== checked) {
|
||||
setSelectedNum(checked ? selectedNum() + 1 : selectedNum() - 1);
|
||||
setSelectedNum(checked ? selectedNum() + 1 : selectedNum() - 1)
|
||||
}
|
||||
obj.selected = checked;
|
||||
obj.selected = checked
|
||||
})
|
||||
);
|
||||
)
|
||||
}
|
||||
lastChecked = { index, selected: checked };
|
||||
one && setSelectedNum(checked ? 1 : 0);
|
||||
};
|
||||
lastChecked = { index, selected: checked }
|
||||
one && setSelectedNum(checked ? 1 : 0)
|
||||
}
|
||||
|
||||
export const selectAll = (checked: boolean) => {
|
||||
setSelectedNum(checked ? objStore.objs.length : 0);
|
||||
setObjStore("objs", {}, (obj) => ({ selected: checked }));
|
||||
};
|
||||
setSelectedNum(checked ? objStore.objs.length : 0)
|
||||
setObjStore("objs", {}, (obj) => ({ selected: checked }))
|
||||
}
|
||||
|
||||
export const selectedObjs = () => {
|
||||
return objStore.objs.filter((obj) => obj.selected);
|
||||
};
|
||||
return objStore.objs.filter((obj) => obj.selected)
|
||||
}
|
||||
|
||||
export const allChecked = () => {
|
||||
return objStore.objs.length === selectedNum();
|
||||
};
|
||||
return objStore.objs.length === selectedNum()
|
||||
}
|
||||
|
||||
export const oneChecked = () => {
|
||||
return selectedNum() === 1;
|
||||
};
|
||||
return selectedNum() === 1
|
||||
}
|
||||
|
||||
export const haveSelected = () => {
|
||||
return selectedNum() > 0;
|
||||
};
|
||||
return selectedNum() > 0
|
||||
}
|
||||
|
||||
export const isIndeterminate = () => {
|
||||
return selectedNum() > 0 && selectedNum() < objStore.objs.length;
|
||||
};
|
||||
return selectedNum() > 0 && selectedNum() < objStore.objs.length
|
||||
}
|
||||
|
||||
export type Layout = "list" | "grid";
|
||||
const [layout, setLayout] = createStorageSignal<Layout>("layout", "list");
|
||||
export type Layout = "list" | "grid"
|
||||
const [layout, setLayout] = createStorageSignal<Layout>("layout", "list")
|
||||
|
||||
const [_checkboxOpen, setCheckboxOpen] = createStorageSignal<string>(
|
||||
"checkbox-open",
|
||||
"false"
|
||||
);
|
||||
export const checkboxOpen = () => _checkboxOpen() === "true";
|
||||
)
|
||||
export const checkboxOpen = () => _checkboxOpen() === "true"
|
||||
|
||||
export const toggleCheckbox = () => {
|
||||
setCheckboxOpen(checkboxOpen() ? "false" : "true");
|
||||
};
|
||||
setCheckboxOpen(checkboxOpen() ? "false" : "true")
|
||||
}
|
||||
|
||||
export { objStore, layout, setLayout };
|
||||
export { objStore, layout, setLayout }
|
||||
// browser password
|
||||
const [_password, _setPassword] = createSignal<string>(
|
||||
cookieStorage.getItem("browser-password") || ""
|
||||
);
|
||||
export { _password as password };
|
||||
)
|
||||
export { _password as password }
|
||||
export const setPassword = (password: string) => {
|
||||
_setPassword(password);
|
||||
cookieStorage.setItem("browser-password", password);
|
||||
};
|
||||
_setPassword(password)
|
||||
cookieStorage.setItem("browser-password", password)
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import { Type } from ".";
|
||||
import { Type } from "."
|
||||
|
||||
export interface DriverItem {
|
||||
name: string;
|
||||
type: Type;
|
||||
default: string;
|
||||
options: string;
|
||||
required?: boolean;
|
||||
help?: string;
|
||||
name: string
|
||||
type: Type
|
||||
default: string
|
||||
options: string
|
||||
required?: boolean
|
||||
help?: string
|
||||
}
|
||||
|
||||
export interface DriverConfig {
|
||||
name: string;
|
||||
local_sort: boolean;
|
||||
only_local: boolean;
|
||||
only_proxy: boolean;
|
||||
no_cache: boolean;
|
||||
no_upload: boolean;
|
||||
need_ms: boolean;
|
||||
default_root: string;
|
||||
name: string
|
||||
local_sort: boolean
|
||||
only_local: boolean
|
||||
only_proxy: boolean
|
||||
no_cache: boolean
|
||||
no_upload: boolean
|
||||
need_ms: boolean
|
||||
default_root: string
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
export * from "./obj";
|
||||
export * from "./resp";
|
||||
export * from "./setting";
|
||||
export * from "./storage";
|
||||
export * from "./user";
|
||||
export * from "./driver_item";
|
||||
export * from "./item_type";
|
||||
export * from "./meta";
|
||||
export * from "./task";
|
||||
export * from "./obj"
|
||||
export * from "./resp"
|
||||
export * from "./setting"
|
||||
export * from "./storage"
|
||||
export * from "./user"
|
||||
export * from "./driver_item"
|
||||
export * from "./item_type"
|
||||
export * from "./meta"
|
||||
export * from "./task"
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
export interface Meta {
|
||||
id: number;
|
||||
path: string;
|
||||
password: string;
|
||||
p_sub: boolean;
|
||||
write: boolean;
|
||||
w_sub: boolean;
|
||||
hide: string;
|
||||
h_sub: boolean;
|
||||
readme: string;
|
||||
r_sub: boolean;
|
||||
id: number
|
||||
path: string
|
||||
password: string
|
||||
p_sub: boolean
|
||||
write: boolean
|
||||
w_sub: boolean
|
||||
hide: string
|
||||
h_sub: boolean
|
||||
readme: string
|
||||
r_sub: boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -9,16 +9,16 @@ export enum ObjType {
|
||||
}
|
||||
|
||||
export interface Obj {
|
||||
name: string;
|
||||
size: number;
|
||||
is_dir: boolean;
|
||||
modified: string;
|
||||
sign?: string;
|
||||
thumb: string;
|
||||
type: ObjType;
|
||||
name: string
|
||||
size: number
|
||||
is_dir: boolean
|
||||
modified: string
|
||||
sign?: string
|
||||
thumb: string
|
||||
type: ObjType
|
||||
path: string
|
||||
}
|
||||
|
||||
export type StoreObj = Obj & {
|
||||
selected?: boolean;
|
||||
};
|
||||
selected?: boolean
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Type } from ".";
|
||||
import { Type } from "."
|
||||
|
||||
export enum Group {
|
||||
SITE,
|
||||
@@ -16,11 +16,11 @@ export enum Flag {
|
||||
}
|
||||
|
||||
export interface SettingItem {
|
||||
key: string;
|
||||
value: string;
|
||||
type: Type;
|
||||
help: string;
|
||||
options?: string;
|
||||
group: Group;
|
||||
flag: Flag;
|
||||
key: string
|
||||
value: string
|
||||
type: Type
|
||||
help: string
|
||||
options?: string
|
||||
group: Group
|
||||
flag: Flag
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user