Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ import { useLoading, useRouter, useT } from "~/hooks"
import { setSettings } from "~/store"
import { setArchiveExtensions } from "~/store/archive"
import { Resp } from "~/types"
import { base_path, bus, handleRespWithoutAuthAndNotify, r } from "~/utils"
import {
base_path,
bus,
handleRespWithoutAuthAndNotify,
initPluginEngine,
r,
} from "~/utils"
import { MustUser, UserOrGuest } from "./MustUser"
import "./index.css"
import { globalStyles } from "./theme"
Expand All @@ -28,6 +34,7 @@ const Test = lazy(() => import("~/pages/test"))
const App: Component = () => {
const t = useT()
globalStyles()
initPluginEngine()
const isRouting = useIsRouting()
const { to, pathname } = useRouter()
const onTo = (path: string) => {
Expand Down
11 changes: 11 additions & 0 deletions src/components/Base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ import {
import { AiOutlineFullscreen, AiOutlineFullscreenExit } from "solid-icons/ai"
import { BsFullscreen, BsFullscreenExit } from "solid-icons/bs"
import { useT } from "~/hooks"
import { Face404 } from "./Face404"

export const Error = (props: {
msg: string
disableColor?: boolean
h?: string
actions?: JSXElement
show404Face?: boolean
}) => {
const merged = mergeProps(
{
Expand All @@ -52,7 +54,16 @@ export const Error = (props: {
px="$4"
py="$6"
bgColor={useColorModeValue("white", "$neutral3")()}
css={{
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "$4",
}}
>
<Show when={props.show404Face}>
<Face404 />
</Show>
<Heading
css={{
wordBreak: "break-all",
Expand Down
169 changes: 169 additions & 0 deletions src/components/Face404.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import { useColorModeValue } from "@hope-ui/solid"

/**
* 404 face animation (classic 404 face animation)
* - Eyes move up + pupils rotate + blink + mouth appears + nose moves down
* - Color follows light/dark mode (light: #292d33; dark: #d6d9de)
* Only shown on the share expired/cancelled error page.
*/
const face404Style = `
.face404__eyes,
.face404__eye-lid,
.face404__mouth-left,
.face404__mouth-right,
.face404__nose,
.face404__pupil {
animation: face404-eyes 1s 0.3s cubic-bezier(0.65, 0, 0.35, 1) forwards;
}
.face404__eye-lid,
.face404__pupil {
animation-duration: 4s;
animation-delay: 1.3s;
animation-iteration-count: infinite;
}
.face404__eye-lid {
animation-name: face404-eye-lid;
}
.face404__mouth-left,
.face404__mouth-right {
animation-timing-function: cubic-bezier(0.33, 1, 0.68, 1);
}
.face404__mouth-left {
animation-name: face404-mouth-left;
}
.face404__mouth-right {
animation-name: face404-mouth-right;
}
.face404__nose {
animation-name: face404-nose;
}
.face404__pupil {
animation-name: face404-pupil;
}
@keyframes face404-eye-lid {
from, 40%, 45%, to {
transform: translateY(0);
}
42.5% {
transform: translateY(17.5px);
}
}
@keyframes face404-eyes {
from {
transform: translateY(112.5px);
}
to {
transform: translateY(15px);
}
}
@keyframes face404-pupil {
from, 37.5%, 40%, 45%, 87.5%, to {
stroke-dashoffset: 0;
transform: translate(0, 0);
}
12.5%, 25%, 62.5%, 75% {
stroke-dashoffset: 0;
transform: translate(-35px, 0);
}
42.5% {
stroke-dashoffset: 35;
transform: translate(0, 17.5px);
}
}
@keyframes face404-mouth-left {
from, 50% {
stroke-dashoffset: -102;
}
to {
stroke-dashoffset: 0;
}
}
@keyframes face404-mouth-right {
from, 50% {
stroke-dashoffset: 102;
}
to {
stroke-dashoffset: 0;
}
}
@keyframes face404-nose {
from {
transform: translate(0, 0);
}
to {
transform: translate(0, 22.5px);
}
}
`

if (typeof document !== "undefined" && !document.getElementById("face404-style")) {
const styleEl = document.createElement("style")
styleEl.id = "face404-style"
styleEl.textContent = face404Style
document.head.appendChild(styleEl)
}

export const Face404 = () => {
const color = useColorModeValue("#292d33", "#d6d9de")()
return (
<svg
class="face404"
viewBox="0 0 320 380"
width="180px"
height="auto"
aria-hidden="true"
style={{
display: "block",
color: color,
}}
>
<g
fill="none"
stroke="currentcolor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="25"
>
<g class="face404__eyes" transform="translate(0, 112.5)">
<g transform="translate(15, 0)">
<polyline class="face404__eye-lid" points="37,0 0,120 75,120" />
<polyline
class="face404__pupil"
points="55,120 55,155"
stroke-dasharray="35 35"
/>
</g>
<g transform="translate(230, 0)">
<polyline class="face404__eye-lid" points="37,0 0,120 75,120" />
<polyline
class="face404__pupil"
points="55,120 55,155"
stroke-dasharray="35 35"
/>
</g>
</g>
<rect
class="face404__nose"
rx="4"
ry="4"
x="132.5"
y="112.5"
width="55"
height="155"
/>
<g stroke-dasharray="102 102" transform="translate(65, 334)">
<path
class="face404__mouth-left"
d="M 0 30 C 0 30 40 0 95 0"
stroke-dashoffset="-102"
/>
<path
class="face404__mouth-right"
d="M 95 0 C 150 0 190 30 190 30"
stroke-dashoffset="102"
/>
</g>
</g>
</svg>
)
}
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from "./ImageWithError"
export * from "./Markdown"
export * from "./ModalInput"
export * from "./ModalTwoInput"
export * from "./Face404"
export * from "./Base"
export * from "./Paginator"
export * from "./icons"
Expand Down
2 changes: 2 additions & 0 deletions src/lang/en/entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import indexes from "./indexes.json"
import login from "./login.json"
import manage from "./manage.json"
import metas from "./metas.json"
import plugins from "./plugins.json"
import settings_other from "./settings_other.json"
import settings from "./settings.json"
import shares from "./shares.json"
Expand All @@ -24,6 +25,7 @@ export const dict = {
login,
manage,
metas,
plugins,
settings_other,
settings,
shares,
Expand Down
3 changes: 2 additions & 1 deletion src/lang/en/manage.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"ldap": "LDAP",
"s3": "S3",
"ftp": "FTP",
"traffic": "Traffic"
"traffic": "Traffic",
"plugins": "Plugins"
},
"title": "OpenList Management",
"not_admin": "You are not an admin user, please login with an admin account.",
Expand Down
69 changes: 69 additions & 0 deletions src/lang/en/plugins.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"title": "Plugins",
"name": "Plugin Name",
"type": "Type",
"version": "Version",
"author": "Author",
"status_col": "Status",
"empty_desc": "No description provided",
"subtitle": "Manage and configure OpenList extensions with ZIP file upload and third-party URL installation",
"search_placeholder": "Search plugins by name, ID, description, or permissions...",
"filter_type": "Filter by type",
"types": {
"all": "All Types",
"ui": "UI & Widgets",
"preview": "Previewers",
"tool": "Tools",
"theme": "Themes & Effects",
"integration": "Integrations",
"system": "System Core"
},
"status": {
"enabled": "Enabled",
"disabled": "Disabled",
"builtin": "Built-in",
"custom": "Custom",
"high_privilege": "High Privilege"
},
"actions": {
"install": "Install Plugin",
"reinstall": "Reinstall",
"uninstall": "Uninstall",
"config": "Settings",
"view_details": "Details",
"enable": "Enable",
"disable": "Disable",
"export": "Export Config",
"import": "Import Config",
"refresh": "Refresh",
"save": "Save Settings",
"cancel": "Cancel",
"install_url": "Install via URL"
},
"install_modal": {
"install_type": "Installation Source",
"zip_tab": "Upload ZIP Package",
"url_tab": "Install via URL",
"zip_file_label": "Plugin ZIP Package",
"zip_drop_title": "Click to select or drag & drop plugin ZIP file here",
"zip_drop_help": "Supports open-source plugin archives containing plugin.json / manifest.json",
"url_label": "Plugin Manifest URL",
"url_placeholder": "e.g.: https://raw.githubusercontent.com/.../plugin.json",
"url_help": "Supports open-source plugin JSON manifest links (GitHub Raw, jsDelivr, unpkg, etc.)",
"high_privilege_label": "Grant System High Privilege (Root / Admin Privileges)",
"high_privilege_help": "Allows direct access to low-level filesystem APIs, storage driver reloading, full site settings read/write, and raw HTTP requests",
"fetch_and_install": "Fetch and Install"
},
"config_modal": {
"title": "Plugin Configuration",
"no_config": "No configuration parameters required for this plugin.",
"save_success": "Plugin configuration saved successfully"
},
"delete_confirm": "Are you sure you want to uninstall and remove this plugin? This cannot be undone.",
"import_modal": {
"title": "Import Plugins Backup",
"paste_json": "Paste plugins JSON data here",
"import_success": "Plugins imported successfully"
},
"empty_installed": "No plugins installed yet. Click 'Install Plugin' to upload a ZIP package or install from URL."
}
1 change: 1 addition & 0 deletions src/lang/en/shares.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"back": "Folders at Bottom"
},
"input_password": "Please enter Share Code",
"share_gone": "This share has expired or been cancelled",
"copy_msg": "Copy link",
"no_permission_tip": "To create a share, you need \"Share\" permission."
}
1 change: 1 addition & 0 deletions src/pages/home/Obj.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export const Obj = () => {
<Error
msg={objStore.err}
disableColor
show404Face={isShare() && objStore.err === t("shares.share_gone")}
actions={
shouldShowStorageButton() ? storageErrorActions() : undefined
}
Expand Down
Loading