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