wip: change local dev

This commit is contained in:
2025-03-20 05:47:13 +00:00
parent 271456347a
commit 8d3c805985
13 changed files with 407 additions and 130 deletions

View File

@@ -0,0 +1,2 @@
import { handlers } from "@/auth"
export const { GET, POST } = handlers

View File

@@ -1,26 +1,2 @@
@import "tailwindcss";
:root {
--background: #ffffff;
--foreground: #171717;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
}
@plugin "daisyui";

View File

@@ -1,103 +1,21 @@
import Image from "next/image";
import DraggablePanel from "@/components/DraggablePanel";
import DraggableWidget from "@/components/DraggableWidget";
import Logo from "@/components/Logo";
export default function Home() {
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={180}
height={38}
priority
/>
<ol className="list-inside list-decimal text-sm/6 text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
<li className="mb-2 tracking-[-.01em]">
Get started by editing{" "}
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-[family-name:var(--font-geist-mono)] font-semibold">
app/page.tsx
</code>
.
</li>
<li className="tracking-[-.01em]">
Save and see your changes instantly.
</li>
</ol>
<div className="flex gap-4 items-center flex-col sm:flex-row">
<a
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:w-auto"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={20}
height={20}
/>
Deploy now
</a>
<a
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-full sm:w-auto md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Read our docs
</a>
</div>
</main>
<footer className="row-start-3 flex gap-[24px] flex-wrap items-center justify-center">
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/file.svg"
alt="File icon"
width={16}
height={16}
/>
Learn
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/window.svg"
alt="Window icon"
width={16}
height={16}
/>
Examples
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/globe.svg"
alt="Globe icon"
width={16}
height={16}
/>
Go to nextjs.org
</a>
</footer>
<div className="w-screen h-screen p-4">
<DraggablePanel draggable={true}>
<DraggableWidget draggable={false} x={0} y={0} w={10} h={10}>
<Logo />
</DraggableWidget>
<DraggableWidget draggable={false} x={10} y={0} w={10} h={10}>
<Logo />
</DraggableWidget>
<DraggableWidget draggable={false} x={0} y={10} w={10} h={10}>
<Logo />
</DraggableWidget>
</DraggablePanel>
</div>
);
}

0
app/settings/page.tsx Normal file
View File

42
app/signin/page.tsx Normal file
View File

@@ -0,0 +1,42 @@
import "@/app/globals.css";
import Logo from "@/components/Logo";
export default function LoginPage() {
return (
<div className="min-h-screen bg-gray-50 flex flex-col items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-md w-full space-y-8">
{/* Logo Section */}
<div className="text-center">
<Logo />
<h2 className="mt-6 text-center text-3xl font-bold text-gray-900">
</h2>
</div>
{/* Login Form */}
<form className="mt-8 space-y-6" action="#" method="POST">
{/* Email Input */}
<div>
<input type="text" placeholder="帐号" className="input w-full" />
</div>
{/* Password Input */}
<div>
<input type="password" placeholder="密码" className="input w-full" />
</div>
{/* Remember Me & Forgot Password */}
<div className="flex items-center justify-between">
<label className="fieldset-label">
<input type="checkbox" defaultChecked className="checkbox" />
</label>
</div>
{/* Submit Button */}
<button className="btn w-full"></button>
</form>
</div>
</div>
)
}

20
auth.ts Normal file
View File

@@ -0,0 +1,20 @@
import NextAuth, { CredentialsSignin } from "next-auth"
import Credentials from "next-auth/providers/credentials"
class InvalidLoginError extends CredentialsSignin {
code = "Invalid identifier or password"
}
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
Credentials({
credentials: {
username: { label: "Username" },
password: { label: "Password", type: "password" },
},
async authorize(credentials) {
throw new InvalidLoginError()
},
}),
],
})

View File

@@ -0,0 +1,32 @@
"use client";
import { ReactElement } from 'react';
import classnames from 'classnames';
export default function DraggablePanel(props: DraggablePanelType) {
const { draggable, wdith = 'full', height = 'full', children } = props;
const draggablePanelClass = classnames(
'p-8 grid gap-[16px]',
`h-${height} w-${wdith}`,
{
'h-full': height === 'full' || height === '100%',
'w-full': wdith === 'full' || wdith === '100%',
'base-200': draggable, // 当 active 为 true 时添加
'base-100': !draggable, // 当 disabled 为 true 时添加
});
return (
<div className={draggablePanelClass}>
{
children
}
</div>
);
}
export type DraggablePanelType = {
draggable: boolean;
wdith?: number | string;
height?: number | string;
children: any;
// grid: boolean;
}

View File

@@ -0,0 +1,109 @@
"use client";
import { CSSProperties, ReactElement, useEffect, useRef, useState } from "react";
import classnames from 'classnames';
import _ from 'lodash';
export default function DraggableWidget(props: DraggableWidgetType) {
const { children, x, y, w, h } = props;
const targetRef = useRef<HTMLDivElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
const [size, setSize] = useState({ width: 16, height: 16 });
const [isResize, setIsResize] = useState(false);
useEffect(() => {
const element = targetRef.current;
if (!element) return;
// 创建 ResizeObserver 实例
let timer:any;
const observer = new ResizeObserver(_.throttle((entries: any) => {
for (const entry of entries) {
const { width, height } = entry.contentRect;
setSize({
width: nearestMultipleOf16(width),
height: nearestMultipleOf16(height)
});
if (timer) {
clearTimeout(timer);
}
setIsResize(true);
timer = setTimeout(() => {
entry.target.style.width = nearestMultipleOf16(width) + 'px';
entry.target.style.height = nearestMultipleOf16(height) + 'px';
// syncSize(entry.contentRect, containerRef.current);
setIsResize(false);
}, 150)
}
}, 30));
const syncSize = (contentRect, containerNode) => {
const { x, y, height, width } = contentRect;
const area = {
rowStart: x/16 + 1,
columnStart: y/16 + 1,
rowEnd: width/16+x/16 + 1,
columnEnd: height/16+y/16 + 1
}
containerNode.style.gridArea = `${area.rowStart} / ${area.columnStart} / ${area.rowEnd} / ${area.columnEnd}`;
}
// 开始观察元素
observer.observe(element);
// 组件卸载时断开连接
return () => {
observer.disconnect();
};
}, []); // 空依赖数组确保只运行一次
const draggableWidgetClass = classnames(
'hover:bg-red-200 hover:outline-2 hover:outline-dashed hover:outline-gray-300 hover:opacity-30 resize block rounded-lg w-64 h-64 max-h-[1048px] max-w-[1888px] cursor-pointer overflow-hidden ', {
}
);
const draggableWidgetIndicatorBoxClass = classnames(
'absolute top-0 left-0 outline-2 outline-dashed outline-red-500 z-50 pointer-events-none',
{
'invisible': !isResize
}
);
return (
<div className="relative" ref={containerRef} style={{ gridArea: `${x} \ ${w+x} \ ${y} \ ${h+y}`}}>
<div className={draggableWidgetClass} ref={targetRef}>
{
children
}
</div>
<div className={draggableWidgetIndicatorBoxClass} style={{
width: size.width,
height: size.height,
}
}>{`${size.width}x${size.height}`}</div>
</div>
);
}
export type DraggableWidgetType = {
draggable: boolean;
wdith?: number | string;
height?: number | string;
children: ReactElement;
x: number;
y: number;
w: number;
h: number;
}
/**
* 计算最接近的 16 的倍数
* @param n 输入的数字
* @returns 最近的 16 的倍数
*/
function nearestMultipleOf16(n: number): number {
return Math.floor((n + 8) / 16) * 16;
}

9
components/Logo.tsx Normal file
View File

@@ -0,0 +1,9 @@
import "@/app/globals.css";
export default function Home() {
return (
<div className="w-full h-full text-5xl font-bold text-gray-900 flex items-center justify-center">
NEXUSHUB
</div>
);
}

1
middleware.ts Normal file
View File

@@ -0,0 +1 @@
export { auth as middleware } from "@/auth"

View File

@@ -9,19 +9,24 @@
"lint": "next lint"
},
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"classnames": "^2.5.1",
"lodash": "^4.17.21",
"next": "15.2.3",
"next-auth": "5.0.0-beta.25",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"next": "15.2.3"
"react-dom": "^19.0.0"
},
"devDependencies": {
"typescript": "^5",
"@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4.0.14",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@tailwindcss/postcss": "^4",
"tailwindcss": "^4",
"daisyui": "^5.0.6",
"eslint": "^9",
"eslint-config-next": "15.2.3",
"@eslint/eslintrc": "^3"
"tailwindcss": "^4.0.14",
"typescript": "^5"
}
}

160
pnpm-lock.yaml generated
View File

@@ -8,9 +8,21 @@ importers:
.:
dependencies:
'@dnd-kit/core':
specifier: ^6.3.1
version: 6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
classnames:
specifier: ^2.5.1
version: 2.5.1
lodash:
specifier: ^4.17.21
version: 4.17.21
next:
specifier: 15.2.3
version: 15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
next-auth:
specifier: 5.0.0-beta.25
version: 5.0.0-beta.25(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)
react:
specifier: ^19.0.0
version: 19.0.0
@@ -22,7 +34,7 @@ importers:
specifier: ^3
version: 3.3.0
'@tailwindcss/postcss':
specifier: ^4
specifier: ^4.0.14
version: 4.0.14
'@types/node':
specifier: ^20
@@ -33,6 +45,9 @@ importers:
'@types/react-dom':
specifier: ^19
version: 19.0.4(@types/react@19.0.11)
daisyui:
specifier: ^5.0.6
version: 5.0.6
eslint:
specifier: ^9
version: 9.22.0(jiti@2.4.2)
@@ -40,7 +55,7 @@ importers:
specifier: 15.2.3
version: 15.2.3(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
tailwindcss:
specifier: ^4
specifier: ^4.0.14
version: 4.0.14
typescript:
specifier: ^5
@@ -52,6 +67,36 @@ packages:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
'@auth/core@0.37.2':
resolution: {integrity: sha512-kUvzyvkcd6h1vpeMAojK2y7+PAV5H+0Cc9+ZlKYDFhDY31AlvsB+GW5vNO4qE3Y07KeQgvNO9U0QUx/fN62kBw==}
peerDependencies:
'@simplewebauthn/browser': ^9.0.1
'@simplewebauthn/server': ^9.0.2
nodemailer: ^6.8.0
peerDependenciesMeta:
'@simplewebauthn/browser':
optional: true
'@simplewebauthn/server':
optional: true
nodemailer:
optional: true
'@dnd-kit/accessibility@3.1.1':
resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==}
peerDependencies:
react: '>=16.8.0'
'@dnd-kit/core@6.3.1':
resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==}
peerDependencies:
react: '>=16.8.0'
react-dom: '>=16.8.0'
'@dnd-kit/utilities@3.2.2':
resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==}
peerDependencies:
react: '>=16.8.0'
'@emnapi/core@1.3.1':
resolution: {integrity: sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==}
@@ -297,6 +342,9 @@ packages:
resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
engines: {node: '>=12.4.0'}
'@panva/hkdf@1.2.1':
resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==}
'@rtsao/scc@1.1.0':
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
@@ -388,6 +436,9 @@ packages:
'@tybys/wasm-util@0.9.0':
resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==}
'@types/cookie@0.6.0':
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
'@types/estree@1.0.6':
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
@@ -625,6 +676,9 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
classnames@2.5.1:
resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
@@ -645,6 +699,10 @@ packages:
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
cookie@0.7.1:
resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}
engines: {node: '>= 0.6'}
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
@@ -652,6 +710,9 @@ packages:
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
daisyui@5.0.6:
resolution: {integrity: sha512-/e/9Gw/2y9oawBJlWkJMSEhRXdmfOLvcPl+6q/x2rPEdIVOtebs1t3ex2vwySl9vCRs1GGNBKCiL+P60Ps/wUw==}
damerau-levenshtein@1.0.8:
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
@@ -1127,6 +1188,9 @@ packages:
resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
hasBin: true
jose@5.10.0:
resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==}
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -1236,6 +1300,9 @@ packages:
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
@@ -1273,6 +1340,22 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
next-auth@5.0.0-beta.25:
resolution: {integrity: sha512-2dJJw1sHQl2qxCrRk+KTQbeH+izFbGFPuJj5eGgBZFYyiYYtvlrBeUw1E/OJJxTRjuxbSYGnCTkUIRsIIW0bog==}
peerDependencies:
'@simplewebauthn/browser': ^9.0.1
'@simplewebauthn/server': ^9.0.2
next: ^14.0.0-0 || ^15.0.0-0
nodemailer: ^6.6.5
react: ^18.2.0 || ^19.0.0-0
peerDependenciesMeta:
'@simplewebauthn/browser':
optional: true
'@simplewebauthn/server':
optional: true
nodemailer:
optional: true
next@15.2.3:
resolution: {integrity: sha512-x6eDkZxk2rPpu46E1ZVUWIBhYCLszmUY6fvHBFcbzJ9dD+qRX6vcHusaqqDlnY+VngKzKbAiG2iRCkPbmi8f7w==}
engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
@@ -1294,6 +1377,9 @@ packages:
sass:
optional: true
oauth4webapi@3.3.1:
resolution: {integrity: sha512-ZwX7UqYrP3Lr+Glhca3a1/nF2jqf7VVyJfhGuW5JtrfDUxt0u+IoBPzFjZ2dd7PJGkdM6CFPVVYzuDYKHv101A==}
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@@ -1380,10 +1466,21 @@ packages:
resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
engines: {node: ^10 || ^12 || >=14}
preact-render-to-string@5.2.3:
resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==}
peerDependencies:
preact: '>=10'
preact@10.11.3:
resolution: {integrity: sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==}
prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
pretty-format@3.8.0:
resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==}
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
@@ -1665,6 +1762,34 @@ snapshots:
'@alloc/quick-lru@5.2.0': {}
'@auth/core@0.37.2':
dependencies:
'@panva/hkdf': 1.2.1
'@types/cookie': 0.6.0
cookie: 0.7.1
jose: 5.10.0
oauth4webapi: 3.3.1
preact: 10.11.3
preact-render-to-string: 5.2.3(preact@10.11.3)
'@dnd-kit/accessibility@3.1.1(react@19.0.0)':
dependencies:
react: 19.0.0
tslib: 2.8.1
'@dnd-kit/core@6.3.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@dnd-kit/accessibility': 3.1.1(react@19.0.0)
'@dnd-kit/utilities': 3.2.2(react@19.0.0)
react: 19.0.0
react-dom: 19.0.0(react@19.0.0)
tslib: 2.8.1
'@dnd-kit/utilities@3.2.2(react@19.0.0)':
dependencies:
react: 19.0.0
tslib: 2.8.1
'@emnapi/core@1.3.1':
dependencies:
'@emnapi/wasi-threads': 1.0.1
@@ -1864,6 +1989,8 @@ snapshots:
'@nolyfill/is-core-module@1.0.39': {}
'@panva/hkdf@1.2.1': {}
'@rtsao/scc@1.1.0': {}
'@rushstack/eslint-patch@1.11.0': {}
@@ -1941,6 +2068,8 @@ snapshots:
tslib: 2.8.1
optional: true
'@types/cookie@0.6.0': {}
'@types/estree@1.0.6': {}
'@types/json-schema@7.0.15': {}
@@ -2214,6 +2343,8 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
classnames@2.5.1: {}
client-only@0.0.1: {}
color-convert@2.0.1:
@@ -2236,6 +2367,8 @@ snapshots:
concat-map@0.0.1: {}
cookie@0.7.1: {}
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
@@ -2244,6 +2377,8 @@ snapshots:
csstype@3.1.3: {}
daisyui@5.0.6: {}
damerau-levenshtein@1.0.8: {}
data-view-buffer@1.0.2:
@@ -2882,6 +3017,8 @@ snapshots:
jiti@2.4.2: {}
jose@5.10.0: {}
js-tokens@4.0.0: {}
js-yaml@4.1.0:
@@ -2971,6 +3108,8 @@ snapshots:
lodash.merge@4.6.2: {}
lodash@4.17.21: {}
loose-envify@1.4.0:
dependencies:
js-tokens: 4.0.0
@@ -3000,6 +3139,12 @@ snapshots:
natural-compare@1.4.0: {}
next-auth@5.0.0-beta.25(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0):
dependencies:
'@auth/core': 0.37.2
next: 15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react: 19.0.0
next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
'@next/env': 15.2.3
@@ -3025,6 +3170,8 @@ snapshots:
- '@babel/core'
- babel-plugin-macros
oauth4webapi@3.3.1: {}
object-assign@4.1.1: {}
object-inspect@1.13.4: {}
@@ -3120,8 +3267,17 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
preact-render-to-string@5.2.3(preact@10.11.3):
dependencies:
preact: 10.11.3
pretty-format: 3.8.0
preact@10.11.3: {}
prelude-ls@1.2.1: {}
pretty-format@3.8.0: {}
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0

7
types/plugin.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
export interface CardPlugin {
id: string; // 唯一标识
displayName: string; // 显示名称
component: React.ComponentType<{ config?: any }>; // 卡片组件
configSchema?: any; // 配置的JSON Schema用于后台配置界面
}