import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbSeparator,
VStack,
Text,
Divider,
HStack,
Icon,
useColorMode,
} from "@hope-ui/solid"
import { Motion } from "@motionone/solid"
import {
batch,
createEffect,
createMemo,
createSignal,
For,
Match,
Show,
Switch,
} from "solid-js"
import { getMainColor, local, me, OrderBy, password } from "~/store"
import { Obj, ObjTree, UserMethods, UserPermissions } from "~/types"
import { useFetch, useRouter, useT, useUtil } from "~/hooks"
import { ListTitle } from "~/pages/home/folder/List"
import { cols } from "~/pages/home/folder/ListItem"
import { Error, MaybeLoading } from "~/components"
import {
bus,
encodePath,
formatDate,
fsArchiveList,
fsArchiveMeta,
getFileSize,
hoverColor,
} from "~/utils"
import naturalSort from "typescript-natural-sort"
import Password from "~/pages/home/Password"
import { useSelectWithMouse } from "~/pages/home/folder/helper"
import { getIconByObj } from "~/utils/icon"
import createMutex from "~/utils/mutex"
import { Item, Menu, useContextMenu } from "solid-contextmenu"
import { TbCopy, TbLink } from "solid-icons/tb"
import { AiOutlineCloudDownload } from "solid-icons/ai"
import { Operations } from "~/pages/home/toolbar/operations"
import "solid-contextmenu/dist/style.css"
const download = (url: string) => {
window.open(url, "_blank")
}
type ListItemProps = {
obj: Obj
index: number
jumpCallback: () => void
innerPath: string
url?: string
pass: string
}
const ListItem = (props: ListItemProps) => {
const { show } = useContextMenu({ id: 2 })
const { isMouseSupported } = useSelectWithMouse()
const filenameStyle = () => local["list_item_filename_overflow"]
return (
{
if (props.obj.is_dir) {
props.jumpCallback()
} else if (props.url) {
download(props.url)
}
}}
onContextMenu={(e: MouseEvent) => {
show(e, { props: props })
}}
>
{props.obj.name}
{getFileSize(props.obj.size)}
{formatDate(props.obj.modified)}
)
}
const operations: Operations = {
extract: { icon: TbCopy, color: "$success9" },
copy_link: { icon: TbLink, color: "$info9" },
download: { icon: AiOutlineCloudDownload, color: "$primary9" },
}
const ContextMenu = () => {
const { copy } = useUtil()
const { colorMode } = useColorMode()
return (
)
}
const ItemContent = (props: { name: string }) => {
const t = useT()
return (
{t(`home.toolbar.${props.name}`)}
)
}
type List = {
[name: string]: Obj & { children: List | null }
}
const Preview = () => {
const t = useT()
const { pathname } = useRouter()
const [metaLoading, fetchMeta] = useFetch(fsArchiveMeta)
const [listLoading, fetchList] = useFetch(fsArchiveList)
const loading = createMemo(() => {
return metaLoading() || listLoading()
})
let archive_pass = ""
let raw_url = ""
let sign = ""
let list: List | null = null
const [error, setError] = createSignal("")
const [wrongPassword, setWrongPassword] = createSignal(false)
const [requiringPassword, setRequiringPassword] = createSignal(false)
const [comment, setComment] = createSignal("")
const [innerPaths, setInnerPaths] = createSignal([])
const [orderBy, setOrderBy] = createSignal()
const [reverse, setReverse] = createSignal(false)
const [extractFolder, setExtractFolder] = createSignal<"" | "front" | "back">(
"",
)
const getObjsMutex = createMutex()
const toList = (tree: ObjTree[] | Obj[]): List => {
let l: List = {}
tree.forEach((item: any) => {
l[item.name] = {
...item,
children: item.children ? toList(item.children) : null,
}
})
return l
}
const dealWithError = (resp: { code: number; message: string }): boolean => {
if (resp.code === 200) return false
if (resp.code === 202) {
batch(() => {
if (archive_pass !== "") {
setWrongPassword(true)
}
setRequiringPassword(true)
setError("")
})
} else {
setError(resp.message)
}
return true
}
const getObjs = async (innerPath: string[]) => {
await getObjsMutex.acquire()
if (requiringPassword() && archive_pass === "") {
getObjsMutex.release()
return []
}
if (raw_url === "") {
const resp = await fetchMeta(pathname(), password(), archive_pass)
if (dealWithError(resp)) {
getObjsMutex.release()
return []
}
if (resp.data.content !== null) {
list = toList(resp.data.content)
}
raw_url = resp.data.raw_url
sign = resp.data.sign
setComment(resp.data.comment)
if (resp.data.sort !== undefined) {
let order: OrderBy | undefined = undefined
if (resp.data.sort.order_by !== "") {
order = resp.data.sort.order_by
}
let re = resp.data.sort.order_direction === "desc"
let ef = resp.data.sort.extract_folder
batch(() => {
setOrderBy(order)
setReverse(re)
setExtractFolder(ef)
})
}
if (resp.data.encrypted && archive_pass === "") {
batch(() => {
setRequiringPassword(true)
setError("")
})
getObjsMutex.release()
return []
}
}
if (list === null) {
const resp = await fetchList(pathname(), password(), archive_pass, "/")
if (dealWithError(resp)) {
getObjsMutex.release()
return []
}
list = toList(resp.data.content)
}
let l = list
for (let i = 0; i < innerPath.length; i++) {
if (l[innerPath[i]].children === null) {
const resp = await fetchList(
pathname(),
password(),
archive_pass,
"/" + innerPath.slice(0, i + 1).join("/"),
)
if (dealWithError(resp)) {
getObjsMutex.release()
return []
}
l[innerPath[i]].children = toList(resp.data.content)
}
l = l[innerPath[i]].children!
}
batch(() => {
setRequiringPassword(false)
setWrongPassword(false)
setError("")
})
getObjsMutex.release()
return Object.values(l)
}
const [objs, setObjs] = createSignal([])
createEffect(() => {
getObjs(innerPaths()).then((ret) => setObjs(ret))
})
const refresh = () => {
getObjs(innerPaths()).then((ret) => setObjs(ret))
}
refresh()
const sortedObjs = () => {
let ret = objs()
if (orderBy()) {
ret = ret.sort((a, b) => {
return (reverse() ? -1 : 1) * naturalSort(a[orderBy()!], b[orderBy()!])
})
}
let ef = extractFolder()
if (ef !== "") {
let dir: Obj[] = []
let file: Obj[] = []
ret.forEach((o) => (o.is_dir ? dir : file).push(o))
ret = ef === "front" ? dir.concat(file) : file.concat(dir)
}
return ret
}
const sortObjs = (orderBy: OrderBy, reverse?: boolean) => {
batch(() => {
setExtractFolder("")
setOrderBy(orderBy)
if (reverse !== undefined) {
setReverse(reverse)
}
})
}
return (
setInnerPaths([])}
>
.
{(name, i) => (
setInnerPaths(innerPaths().slice(0, i() + 1))}
>
{name}
)}
archive_pass}
setPassword={(s) => (archive_pass = s)}
enterCallback={() => refresh()}
>
{t("home.toolbar.archive.incorrect_password")}
{(obj, i) => {
let url = undefined
let innerPath =
(innerPaths().length > 0
? "/" + innerPaths().join("/")
: "") +
"/" +
obj.name
if (!obj.is_dir) {
url = raw_url + "?inner=" + encodePath(innerPath, true)
if (archive_pass !== "") {
url = url + "&pass=" + encodeURIComponent(archive_pass)
}
if (sign !== "") {
url = url + "&sign=" + sign
}
}
return (
setInnerPaths(innerPaths().concat(obj.name))
}
innerPath={innerPath}
url={url}
pass={archive_pass}
/>
)
}}
{comment()}
)
}
export default Preview