@h-ai/ui 0.1.0-alpha.25 → 0.1.0-alpha.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -7
- package/auto-import.d.ts +5 -0
- package/auto-import.js +4 -0
- package/dist/components/compounds/DataTable.svelte +81 -4
- package/dist/components/compounds/DataTable.svelte.d.ts +7 -0
- package/dist/components/compounds/Modal.svelte +44 -6
- package/dist/components/compounds/Pagination.svelte +72 -119
- package/dist/components/scenes/app/SettingsLayout.svelte +111 -0
- package/dist/components/scenes/app/SettingsLayout.svelte.d.ts +41 -0
- package/dist/components/scenes/app/ThemeColorPicker.svelte +41 -0
- package/dist/components/scenes/app/index.d.ts +1 -0
- package/dist/components/scenes/app/index.js +1 -0
- package/dist/components/scenes/crud/CrudFilterBar.svelte +173 -35
- package/dist/components/scenes/crud/CrudFilterBar.svelte.d.ts +7 -1
- package/dist/components/scenes/crud/CrudPage.svelte +19 -15
- package/dist/components/scenes/error/ErrorPage.svelte +125 -0
- package/dist/components/scenes/error/ErrorPage.svelte.d.ts +42 -0
- package/dist/components/scenes/error/error-presets.d.ts +24 -0
- package/dist/components/scenes/error/error-presets.js +31 -0
- package/dist/components/scenes/error/index.d.ts +8 -0
- package/dist/components/scenes/error/index.js +8 -0
- package/dist/components/scenes/iam/AuthShell.svelte +138 -0
- package/dist/components/scenes/iam/AuthShell.svelte.d.ts +45 -0
- package/dist/components/scenes/iam/index.d.ts +1 -0
- package/dist/components/scenes/iam/index.js +2 -1
- package/dist/components/scenes/index.d.ts +1 -0
- package/dist/components/scenes/index.js +2 -0
- package/dist/messages/en-US.json +20 -1
- package/dist/messages/zh-CN.json +20 -1
- package/dist/styles/global.css +4 -1
- package/dist/types.d.ts +6 -0
- package/package.json +2 -2
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component ErrorPage
|
|
3
|
+
通用错误页场景组件
|
|
4
|
+
|
|
5
|
+
展示大号状态码 + 标题 + 描述 + 操作按钮,内置 401/403/404/500/503 预设。
|
|
6
|
+
借鉴 shadcn-admin 错误页布局,复用现有主题 token。
|
|
7
|
+
|
|
8
|
+
使用 Svelte 5 Runes ($props, $derived)
|
|
9
|
+
|
|
10
|
+
@example
|
|
11
|
+
<ErrorPage status={403} homeUrl="/admin" onback={() => history.back()} />
|
|
12
|
+
-->
|
|
13
|
+
<script lang='ts'>
|
|
14
|
+
import type { Snippet } from 'svelte'
|
|
15
|
+
import type { ErrorPreset } from './error-presets.js'
|
|
16
|
+
import { uiM } from '../../../messages.js'
|
|
17
|
+
import { cn } from '../../../utils.js'
|
|
18
|
+
import Button from '../../primitives/Button.svelte'
|
|
19
|
+
import { ERROR_PRESETS, resolveErrorPreset } from './error-presets.js'
|
|
20
|
+
|
|
21
|
+
const {
|
|
22
|
+
status = 404,
|
|
23
|
+
code,
|
|
24
|
+
title,
|
|
25
|
+
description,
|
|
26
|
+
showHome = true,
|
|
27
|
+
showBack = true,
|
|
28
|
+
homeUrl = '/',
|
|
29
|
+
onhome,
|
|
30
|
+
onback,
|
|
31
|
+
icon,
|
|
32
|
+
actions,
|
|
33
|
+
class: className = '',
|
|
34
|
+
}: {
|
|
35
|
+
/** HTTP 状态码或预设标识;未命中预设时回退到最接近的预设 */
|
|
36
|
+
status?: number | string | ErrorPreset
|
|
37
|
+
/** 自定义大号展示码(覆盖预设) */
|
|
38
|
+
code?: string
|
|
39
|
+
/** 自定义标题(覆盖预设文案) */
|
|
40
|
+
title?: string
|
|
41
|
+
/** 自定义描述(覆盖预设文案) */
|
|
42
|
+
description?: string
|
|
43
|
+
/** 是否显示「返回首页」按钮 */
|
|
44
|
+
showHome?: boolean
|
|
45
|
+
/** 是否显示「返回上一页」按钮 */
|
|
46
|
+
showBack?: boolean
|
|
47
|
+
/** 首页地址(未提供 onhome 时作为链接跳转) */
|
|
48
|
+
homeUrl?: string
|
|
49
|
+
/** 自定义「返回首页」处理(优先于 homeUrl 链接) */
|
|
50
|
+
onhome?: () => void
|
|
51
|
+
/** 自定义「返回上一页」处理(默认 history.back()) */
|
|
52
|
+
onback?: () => void
|
|
53
|
+
/** 自定义图标插槽 */
|
|
54
|
+
icon?: Snippet
|
|
55
|
+
/** 自定义操作区插槽(提供时覆盖默认按钮) */
|
|
56
|
+
actions?: Snippet
|
|
57
|
+
class?: string
|
|
58
|
+
} = $props()
|
|
59
|
+
|
|
60
|
+
const preset = $derived(ERROR_PRESETS[resolveErrorPreset(status)])
|
|
61
|
+
const displayCode = $derived(code ?? preset.code)
|
|
62
|
+
const displayTitle = $derived(title ?? uiM(preset.titleKey))
|
|
63
|
+
const displayDesc = $derived(description ?? uiM(preset.descKey))
|
|
64
|
+
|
|
65
|
+
function handleBack() {
|
|
66
|
+
if (onback) {
|
|
67
|
+
onback()
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
if (typeof history !== 'undefined') {
|
|
71
|
+
history.back()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function handleHome() {
|
|
76
|
+
onhome?.()
|
|
77
|
+
}
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<div class={cn('flex min-h-[60vh] w-full flex-col items-center justify-center px-6 py-12 text-center', className)}>
|
|
81
|
+
<!-- 图标 -->
|
|
82
|
+
<div class='mb-6 flex size-16 items-center justify-center rounded-2xl bg-base-content/5 text-base-content/40'>
|
|
83
|
+
{#if icon}
|
|
84
|
+
{@render icon()}
|
|
85
|
+
{:else}
|
|
86
|
+
<span class='{preset.icon} size-8'></span>
|
|
87
|
+
{/if}
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<!-- 大号状态码 -->
|
|
91
|
+
<p class='text-6xl font-bold tracking-tight text-base-content/85 sm:text-7xl'>{displayCode}</p>
|
|
92
|
+
|
|
93
|
+
<!-- 标题 -->
|
|
94
|
+
<h1 class='mt-4 text-xl font-semibold text-base-content sm:text-2xl'>{displayTitle}</h1>
|
|
95
|
+
|
|
96
|
+
<!-- 描述 -->
|
|
97
|
+
<p class='mt-2 max-w-md text-sm text-base-content/55'>{displayDesc}</p>
|
|
98
|
+
|
|
99
|
+
<!-- 操作区 -->
|
|
100
|
+
<div class='mt-8 flex flex-wrap items-center justify-center gap-3'>
|
|
101
|
+
{#if actions}
|
|
102
|
+
{@render actions()}
|
|
103
|
+
{:else}
|
|
104
|
+
{#if showBack}
|
|
105
|
+
<Button variant='outline' size='sm' onclick={handleBack}>
|
|
106
|
+
<span class='icon-[tabler--arrow-left] mr-1.5 size-4'></span>
|
|
107
|
+
{uiM('error_go_back')}
|
|
108
|
+
</Button>
|
|
109
|
+
{/if}
|
|
110
|
+
{#if showHome}
|
|
111
|
+
{#if onhome}
|
|
112
|
+
<Button variant='primary' size='sm' onclick={handleHome}>
|
|
113
|
+
<span class='icon-[tabler--home] mr-1.5 size-4'></span>
|
|
114
|
+
{uiM('error_back_home')}
|
|
115
|
+
</Button>
|
|
116
|
+
{:else}
|
|
117
|
+
<a href={homeUrl} class='btn btn-primary btn-sm'>
|
|
118
|
+
<span class='icon-[tabler--home] mr-1.5 size-4'></span>
|
|
119
|
+
{uiM('error_back_home')}
|
|
120
|
+
</a>
|
|
121
|
+
{/if}
|
|
122
|
+
{/if}
|
|
123
|
+
{/if}
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { ErrorPreset } from './error-presets.js';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
/** HTTP 状态码或预设标识;未命中预设时回退到最接近的预设 */
|
|
5
|
+
status?: number | string | ErrorPreset;
|
|
6
|
+
/** 自定义大号展示码(覆盖预设) */
|
|
7
|
+
code?: string;
|
|
8
|
+
/** 自定义标题(覆盖预设文案) */
|
|
9
|
+
title?: string;
|
|
10
|
+
/** 自定义描述(覆盖预设文案) */
|
|
11
|
+
description?: string;
|
|
12
|
+
/** 是否显示「返回首页」按钮 */
|
|
13
|
+
showHome?: boolean;
|
|
14
|
+
/** 是否显示「返回上一页」按钮 */
|
|
15
|
+
showBack?: boolean;
|
|
16
|
+
/** 首页地址(未提供 onhome 时作为链接跳转) */
|
|
17
|
+
homeUrl?: string;
|
|
18
|
+
/** 自定义「返回首页」处理(优先于 homeUrl 链接) */
|
|
19
|
+
onhome?: () => void;
|
|
20
|
+
/** 自定义「返回上一页」处理(默认 history.back()) */
|
|
21
|
+
onback?: () => void;
|
|
22
|
+
/** 自定义图标插槽 */
|
|
23
|
+
icon?: Snippet;
|
|
24
|
+
/** 自定义操作区插槽(提供时覆盖默认按钮) */
|
|
25
|
+
actions?: Snippet;
|
|
26
|
+
class?: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* ErrorPage
|
|
30
|
+
* 通用错误页场景组件
|
|
31
|
+
*
|
|
32
|
+
* 展示大号状态码 + 标题 + 描述 + 操作按钮,内置 401/403/404/500/503 预设。
|
|
33
|
+
* 借鉴 shadcn-admin 错误页布局,复用现有主题 token。
|
|
34
|
+
*
|
|
35
|
+
* 使用 Svelte 5 Runes ($props, $derived)
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* <ErrorPage status={403} homeUrl="/admin" onback={() => history.back()} />
|
|
39
|
+
*/
|
|
40
|
+
declare const ErrorPage: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
41
|
+
type ErrorPage = ReturnType<typeof ErrorPage>;
|
|
42
|
+
export default ErrorPage;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @h-ai/ui — 错误页预设
|
|
3
|
+
*
|
|
4
|
+
* 为 ErrorPage 提供常见 HTTP 错误的内置文案 key 与图标。
|
|
5
|
+
* @module error-presets
|
|
6
|
+
*/
|
|
7
|
+
import type { UIMessageKey } from '../../../messages.js';
|
|
8
|
+
/** 内置错误预设标识 */
|
|
9
|
+
export type ErrorPreset = '401' | '403' | '404' | '500' | '503';
|
|
10
|
+
/** 单个错误预设的展示信息 */
|
|
11
|
+
export interface ErrorPresetInfo {
|
|
12
|
+
/** HTTP 状态码(用于大号展示) */
|
|
13
|
+
code: string;
|
|
14
|
+
/** 标题文案 key */
|
|
15
|
+
titleKey: UIMessageKey;
|
|
16
|
+
/** 描述文案 key */
|
|
17
|
+
descKey: UIMessageKey;
|
|
18
|
+
/** Tabler 图标类名 */
|
|
19
|
+
icon: string;
|
|
20
|
+
}
|
|
21
|
+
/** 错误预设映射表 */
|
|
22
|
+
export declare const ERROR_PRESETS: Record<ErrorPreset, ErrorPresetInfo>;
|
|
23
|
+
/** 根据 HTTP 状态码解析到最接近的预设 */
|
|
24
|
+
export declare function resolveErrorPreset(status: number | string | undefined): ErrorPreset;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @h-ai/ui — 错误页预设
|
|
3
|
+
*
|
|
4
|
+
* 为 ErrorPage 提供常见 HTTP 错误的内置文案 key 与图标。
|
|
5
|
+
* @module error-presets
|
|
6
|
+
*/
|
|
7
|
+
/** 错误预设映射表 */
|
|
8
|
+
export const ERROR_PRESETS = {
|
|
9
|
+
401: { code: '401', titleKey: 'error_401_title', descKey: 'error_401_desc', icon: 'icon-[tabler--lock]' },
|
|
10
|
+
403: { code: '403', titleKey: 'error_403_title', descKey: 'error_403_desc', icon: 'icon-[tabler--shield-lock]' },
|
|
11
|
+
404: { code: '404', titleKey: 'error_404_title', descKey: 'error_404_desc', icon: 'icon-[tabler--map-search]' },
|
|
12
|
+
500: { code: '500', titleKey: 'error_500_title', descKey: 'error_500_desc', icon: 'icon-[tabler--server-off]' },
|
|
13
|
+
503: { code: '503', titleKey: 'error_503_title', descKey: 'error_503_desc', icon: 'icon-[tabler--tool]' },
|
|
14
|
+
};
|
|
15
|
+
/** 根据 HTTP 状态码解析到最接近的预设 */
|
|
16
|
+
export function resolveErrorPreset(status) {
|
|
17
|
+
const code = String(status ?? '');
|
|
18
|
+
if (code in ERROR_PRESETS) {
|
|
19
|
+
return code;
|
|
20
|
+
}
|
|
21
|
+
const num = Number(code);
|
|
22
|
+
if (num === 401)
|
|
23
|
+
return '401';
|
|
24
|
+
if (num === 403)
|
|
25
|
+
return '403';
|
|
26
|
+
if (num === 503)
|
|
27
|
+
return '503';
|
|
28
|
+
if (num >= 500)
|
|
29
|
+
return '500';
|
|
30
|
+
return '404';
|
|
31
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component AuthShell
|
|
3
|
+
认证页布局场景组件
|
|
4
|
+
|
|
5
|
+
借鉴 shadcn-admin sign-in / sign-in-2:支持居中卡片(card)与左右分栏(split)两种布局。
|
|
6
|
+
品牌区、标题、副标题、表单内容由使用方提供。
|
|
7
|
+
|
|
8
|
+
使用 Svelte 5 Runes ($props, $derived)
|
|
9
|
+
|
|
10
|
+
@example
|
|
11
|
+
<AuthShell variant="card" title="登录" subtitle="欢迎回来">
|
|
12
|
+
<LoginForm onsubmit={handleLogin} />
|
|
13
|
+
</AuthShell>
|
|
14
|
+
-->
|
|
15
|
+
<script lang='ts'>
|
|
16
|
+
import type { Snippet } from 'svelte'
|
|
17
|
+
import { cn } from '../../../utils.js'
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
variant = 'card',
|
|
21
|
+
title = '',
|
|
22
|
+
subtitle = '',
|
|
23
|
+
brandTitle = '',
|
|
24
|
+
brandText = '',
|
|
25
|
+
logo,
|
|
26
|
+
illustration,
|
|
27
|
+
description,
|
|
28
|
+
highlights,
|
|
29
|
+
brand,
|
|
30
|
+
footer,
|
|
31
|
+
children,
|
|
32
|
+
class: className = '',
|
|
33
|
+
}: {
|
|
34
|
+
/** 布局形态:'card'(居中卡片,默认)或 'split'(左右分栏) */
|
|
35
|
+
variant?: 'card' | 'split'
|
|
36
|
+
/** 表单区标题 */
|
|
37
|
+
title?: string
|
|
38
|
+
/** 表单区副标题 */
|
|
39
|
+
subtitle?: string
|
|
40
|
+
/** split 模式品牌区主标题 */
|
|
41
|
+
brandTitle?: string
|
|
42
|
+
/** split 模式品牌区描述文案 */
|
|
43
|
+
brandText?: string
|
|
44
|
+
/** 顶部 Logo 插槽 */
|
|
45
|
+
logo?: Snippet
|
|
46
|
+
/** split 模式品牌区插图(如大图/海报) */
|
|
47
|
+
illustration?: Snippet
|
|
48
|
+
/** split 模式品牌区描述区(覆盖 brandText) */
|
|
49
|
+
description?: Snippet
|
|
50
|
+
/** split 模式品牌区重点信息(如卖点列表) */
|
|
51
|
+
highlights?: Snippet
|
|
52
|
+
/** split 模式品牌区自定义插槽(覆盖 brandTitle/brandText) */
|
|
53
|
+
brand?: Snippet
|
|
54
|
+
/** 底部插槽(如注册/登录切换链接) */
|
|
55
|
+
footer?: Snippet
|
|
56
|
+
/** 表单内容 */
|
|
57
|
+
children?: Snippet
|
|
58
|
+
class?: string
|
|
59
|
+
} = $props()
|
|
60
|
+
|
|
61
|
+
const isSplit = $derived(variant === 'split')
|
|
62
|
+
// split 模式下品牌区已展示 Logo,表单区仅在小屏展示,避免桌面端重复
|
|
63
|
+
const logoWrapClass = $derived(isSplit ? 'mb-6 flex justify-center lg:hidden' : 'mb-6 flex justify-center')
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
{#snippet formPanel()}
|
|
67
|
+
<div class='flex w-full max-w-sm flex-col'>
|
|
68
|
+
{#if logo}
|
|
69
|
+
<div class={logoWrapClass}>{@render logo()}</div>
|
|
70
|
+
{/if}
|
|
71
|
+
{#if title}
|
|
72
|
+
<h1 class='text-center text-2xl font-semibold tracking-tight text-base-content'>{title}</h1>
|
|
73
|
+
{/if}
|
|
74
|
+
{#if subtitle}
|
|
75
|
+
<p class='mt-2 text-center text-sm text-base-content/55'>{subtitle}</p>
|
|
76
|
+
{/if}
|
|
77
|
+
<div class='mt-7'>
|
|
78
|
+
{#if children}{@render children()}{/if}
|
|
79
|
+
</div>
|
|
80
|
+
{#if footer}
|
|
81
|
+
<div class='mt-6 text-center text-sm text-base-content/60'>{@render footer()}</div>
|
|
82
|
+
{/if}
|
|
83
|
+
</div>
|
|
84
|
+
{/snippet}
|
|
85
|
+
|
|
86
|
+
{#if isSplit}
|
|
87
|
+
<div class={cn('grid min-h-screen lg:grid-cols-2', className)}>
|
|
88
|
+
<!-- 品牌区 -->
|
|
89
|
+
<div class='relative hidden overflow-hidden bg-primary p-10 text-primary-content lg:flex'>
|
|
90
|
+
<div class='pointer-events-none absolute inset-0 opacity-20' style='background-image: radial-gradient(circle at 20% 20%, currentColor 1px, transparent 1px); background-size: 28px 28px;'></div>
|
|
91
|
+
{#if brand}
|
|
92
|
+
{@render brand()}
|
|
93
|
+
{:else}
|
|
94
|
+
<div class='relative z-10 flex w-full flex-1 flex-col justify-between gap-10'>
|
|
95
|
+
<div class='space-y-6'>
|
|
96
|
+
{#if logo}
|
|
97
|
+
<div>{@render logo()}</div>
|
|
98
|
+
{/if}
|
|
99
|
+
{#if illustration}
|
|
100
|
+
<div class='overflow-hidden rounded-2xl border border-primary-content/15 bg-primary-content/5 p-2'>
|
|
101
|
+
{@render illustration()}
|
|
102
|
+
</div>
|
|
103
|
+
{/if}
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<div class='space-y-4'>
|
|
107
|
+
{#if brandTitle}
|
|
108
|
+
<h2 class='text-3xl font-semibold leading-snug'>{brandTitle}</h2>
|
|
109
|
+
{/if}
|
|
110
|
+
{#if description}
|
|
111
|
+
<div class='max-w-xl text-sm text-primary-content/85'>
|
|
112
|
+
{@render description()}
|
|
113
|
+
</div>
|
|
114
|
+
{:else if brandText}
|
|
115
|
+
<p class='max-w-xl text-sm text-primary-content/80'>{brandText}</p>
|
|
116
|
+
{/if}
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
{#if highlights}
|
|
120
|
+
<div class='max-w-xl text-sm text-primary-content/90'>
|
|
121
|
+
{@render highlights()}
|
|
122
|
+
</div>
|
|
123
|
+
{/if}
|
|
124
|
+
</div>
|
|
125
|
+
{/if}
|
|
126
|
+
</div>
|
|
127
|
+
<!-- 表单区 -->
|
|
128
|
+
<div class='flex items-center justify-center p-6 sm:p-10'>
|
|
129
|
+
{@render formPanel()}
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
{:else}
|
|
133
|
+
<div class={cn('flex min-h-screen items-center justify-center bg-base-200/40 p-6', className)}>
|
|
134
|
+
<div class='w-full max-w-md rounded-2xl border border-base-content/8 bg-base-100 p-8 shadow-sm sm:p-10'>
|
|
135
|
+
{@render formPanel()}
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
{/if}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
/** 布局形态:'card'(居中卡片,默认)或 'split'(左右分栏) */
|
|
4
|
+
variant?: 'card' | 'split';
|
|
5
|
+
/** 表单区标题 */
|
|
6
|
+
title?: string;
|
|
7
|
+
/** 表单区副标题 */
|
|
8
|
+
subtitle?: string;
|
|
9
|
+
/** split 模式品牌区主标题 */
|
|
10
|
+
brandTitle?: string;
|
|
11
|
+
/** split 模式品牌区描述文案 */
|
|
12
|
+
brandText?: string;
|
|
13
|
+
/** 顶部 Logo 插槽 */
|
|
14
|
+
logo?: Snippet;
|
|
15
|
+
/** split 模式品牌区插图(如大图/海报) */
|
|
16
|
+
illustration?: Snippet;
|
|
17
|
+
/** split 模式品牌区描述区(覆盖 brandText) */
|
|
18
|
+
description?: Snippet;
|
|
19
|
+
/** split 模式品牌区重点信息(如卖点列表) */
|
|
20
|
+
highlights?: Snippet;
|
|
21
|
+
/** split 模式品牌区自定义插槽(覆盖 brandTitle/brandText) */
|
|
22
|
+
brand?: Snippet;
|
|
23
|
+
/** 底部插槽(如注册/登录切换链接) */
|
|
24
|
+
footer?: Snippet;
|
|
25
|
+
/** 表单内容 */
|
|
26
|
+
children?: Snippet;
|
|
27
|
+
class?: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* AuthShell
|
|
31
|
+
* 认证页布局场景组件
|
|
32
|
+
*
|
|
33
|
+
* 借鉴 shadcn-admin sign-in / sign-in-2:支持居中卡片(card)与左右分栏(split)两种布局。
|
|
34
|
+
* 品牌区、标题、副标题、表单内容由使用方提供。
|
|
35
|
+
*
|
|
36
|
+
* 使用 Svelte 5 Runes ($props, $derived)
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* <AuthShell variant="card" title="登录" subtitle="欢迎回来">
|
|
40
|
+
* <LoginForm onsubmit={handleLogin} />
|
|
41
|
+
* </AuthShell>
|
|
42
|
+
*/
|
|
43
|
+
declare const AuthShell: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
44
|
+
type AuthShell = ReturnType<typeof AuthShell>;
|
|
45
|
+
export default AuthShell;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* 身份认证相关的场景化组件
|
|
5
5
|
* @module index
|
|
6
6
|
*/
|
|
7
|
+
export { default as AuthShell } from './AuthShell.svelte';
|
|
7
8
|
export { default as ChangePasswordForm } from './ChangePasswordForm.svelte';
|
|
8
9
|
export { default as ForgotPasswordForm } from './ForgotPasswordForm.svelte';
|
|
9
10
|
export { default as LoginForm } from './LoginForm.svelte';
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* 身份认证相关的场景化组件
|
|
5
5
|
* @module index
|
|
6
6
|
*/
|
|
7
|
+
// 认证表单
|
|
8
|
+
export { default as AuthShell } from './AuthShell.svelte';
|
|
7
9
|
export { default as ChangePasswordForm } from './ChangePasswordForm.svelte';
|
|
8
10
|
export { default as ForgotPasswordForm } from './ForgotPasswordForm.svelte';
|
|
9
|
-
// 认证表单
|
|
10
11
|
export { default as LoginForm } from './LoginForm.svelte';
|
|
11
12
|
export { default as PasswordInput } from './PasswordInput.svelte';
|
|
12
13
|
// 权限控制
|
|
@@ -8,6 +8,7 @@ export * from './ai/index.js';
|
|
|
8
8
|
export * from './app/index.js';
|
|
9
9
|
export * from './crud/index.js';
|
|
10
10
|
export * from './crypto/index.js';
|
|
11
|
+
export * from './error/index.js';
|
|
11
12
|
export * from './iam/index.js';
|
|
12
13
|
export * from './storage/index.js';
|
|
13
14
|
export * from './types.js';
|
package/dist/messages/en-US.json
CHANGED
|
@@ -160,6 +160,8 @@
|
|
|
160
160
|
"pagination_jump_to": "Go to",
|
|
161
161
|
"pagination_page": "page",
|
|
162
162
|
"pagination_page_size": "{size} / page",
|
|
163
|
+
"pagination_rows_per_page": "Rows per page",
|
|
164
|
+
"pagination_page_info": "Page {page} of {total}",
|
|
163
165
|
"severity_critical": "Critical",
|
|
164
166
|
"severity_high": "High",
|
|
165
167
|
"severity_medium": "Medium",
|
|
@@ -275,7 +277,24 @@
|
|
|
275
277
|
"crud_delete_failed": "Delete failed",
|
|
276
278
|
"crud_network_error": "Network error, please try again later",
|
|
277
279
|
"crud_filter_all": "All",
|
|
280
|
+
"crud_filter_yes": "Yes",
|
|
281
|
+
"crud_filter_no": "No",
|
|
282
|
+
"crud_filter_from": "From",
|
|
283
|
+
"crud_filter_to": "To",
|
|
284
|
+
"crud_reset": "Reset",
|
|
278
285
|
"crud_total": "{count} items total",
|
|
279
286
|
"crud_detail_empty": "-",
|
|
280
|
-
"crud_field_required": "This field is required"
|
|
287
|
+
"crud_field_required": "This field is required",
|
|
288
|
+
"error_go_back": "Go Back",
|
|
289
|
+
"error_back_home": "Back to Home",
|
|
290
|
+
"error_401_title": "Unauthorized",
|
|
291
|
+
"error_401_desc": "You need to sign in to access this page. Please log in and try again.",
|
|
292
|
+
"error_403_title": "Access Forbidden",
|
|
293
|
+
"error_403_desc": "You don't have permission to access this resource. Contact your administrator if you need help.",
|
|
294
|
+
"error_404_title": "Page Not Found",
|
|
295
|
+
"error_404_desc": "The page you are looking for doesn't exist or has been moved. Please check the URL.",
|
|
296
|
+
"error_500_title": "Internal Server Error",
|
|
297
|
+
"error_500_desc": "Something went wrong on our end. We're working on it, please try again later.",
|
|
298
|
+
"error_503_title": "Under Maintenance",
|
|
299
|
+
"error_503_desc": "The system is currently undergoing maintenance. Please check back soon."
|
|
281
300
|
}
|
package/dist/messages/zh-CN.json
CHANGED
|
@@ -160,6 +160,8 @@
|
|
|
160
160
|
"pagination_jump_to": "跳转到",
|
|
161
161
|
"pagination_page": "页",
|
|
162
162
|
"pagination_page_size": "{size} 条/页",
|
|
163
|
+
"pagination_rows_per_page": "每页",
|
|
164
|
+
"pagination_page_info": "第 {page} / {total} 页",
|
|
163
165
|
"severity_critical": "严重",
|
|
164
166
|
"severity_high": "高",
|
|
165
167
|
"severity_medium": "中",
|
|
@@ -275,7 +277,24 @@
|
|
|
275
277
|
"crud_delete_failed": "删除失败",
|
|
276
278
|
"crud_network_error": "网络错误,请稍后重试",
|
|
277
279
|
"crud_filter_all": "全部",
|
|
280
|
+
"crud_filter_yes": "是",
|
|
281
|
+
"crud_filter_no": "否",
|
|
282
|
+
"crud_filter_from": "开始日期",
|
|
283
|
+
"crud_filter_to": "结束日期",
|
|
284
|
+
"crud_reset": "重置",
|
|
278
285
|
"crud_total": "共 {count} 条",
|
|
279
286
|
"crud_detail_empty": "-",
|
|
280
|
-
"crud_field_required": "此字段为必填项"
|
|
287
|
+
"crud_field_required": "此字段为必填项",
|
|
288
|
+
"error_go_back": "返回上一页",
|
|
289
|
+
"error_back_home": "返回首页",
|
|
290
|
+
"error_401_title": "未授权访问",
|
|
291
|
+
"error_401_desc": "您需要登录后才能访问此页面。请登录后重试。",
|
|
292
|
+
"error_403_title": "禁止访问",
|
|
293
|
+
"error_403_desc": "您没有权限访问此资源。如需帮助请联系管理员。",
|
|
294
|
+
"error_404_title": "页面不存在",
|
|
295
|
+
"error_404_desc": "您访问的页面不存在或已被移除。请检查地址是否正确。",
|
|
296
|
+
"error_500_title": "服务器错误",
|
|
297
|
+
"error_500_desc": "服务器出现了一些问题。我们正在处理,请稍后重试。",
|
|
298
|
+
"error_503_title": "服务维护中",
|
|
299
|
+
"error_503_desc": "系统正在维护升级,请稍后再访问。"
|
|
281
300
|
}
|
package/dist/styles/global.css
CHANGED
|
@@ -57,7 +57,10 @@ input::-webkit-credentials-auto-fill-button {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/* ─── Focus ring ─── */
|
|
60
|
-
|
|
60
|
+
/* 全局 focus-visible 仅用于非表单交互元素(按钮、链接等)
|
|
61
|
+
表单组件 (.select, .radio, .checkbox, .toggle, .textarea, input, textarea)
|
|
62
|
+
由 DaisyUI 或组件自身处理焦点样式 */
|
|
63
|
+
:focus-visible:not(input, select, textarea, .select, .radio, .checkbox, .toggle, .textarea) {
|
|
61
64
|
outline: 2px solid oklch(0.6 0.15 250);
|
|
62
65
|
outline-offset: 2px;
|
|
63
66
|
border-radius: 4px;
|
package/dist/types.d.ts
CHANGED
|
@@ -438,6 +438,8 @@ export interface ModalProps {
|
|
|
438
438
|
title?: string;
|
|
439
439
|
/** 尺寸 */
|
|
440
440
|
size?: Size | 'full';
|
|
441
|
+
/** 面板圆角(任意合法 CSS border-radius 值,默认 1rem) */
|
|
442
|
+
radius?: string;
|
|
441
443
|
/** 是否可通过点击遮罩关闭 */
|
|
442
444
|
closeOnBackdrop?: boolean;
|
|
443
445
|
/** 是否可通过 ESC 键关闭 */
|
|
@@ -601,6 +603,10 @@ export interface PaginationProps {
|
|
|
601
603
|
page?: string;
|
|
602
604
|
/** 每页条数文案,{size} 会被替换为实际数字 */
|
|
603
605
|
pageSize?: string;
|
|
606
|
+
/** 每页条数前缀文案(如「每页」/「Rows per page」) */
|
|
607
|
+
rowsPerPage?: string;
|
|
608
|
+
/** 页码信息文案,{page} / {total} 会被替换(如「第 {page} / {total} 页」) */
|
|
609
|
+
pageInfo?: string;
|
|
604
610
|
};
|
|
605
611
|
/** 自定义类名 */
|
|
606
612
|
class?: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-ai/ui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
4
|
+
"version": "0.1.0-alpha.26",
|
|
5
5
|
"description": "Hai Framework UI component library for Svelte 5 Runes.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"svelte": "./dist/index.js",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"mermaid": "^11.12.0",
|
|
46
46
|
"shiki": "^4.0.2",
|
|
47
47
|
"tailwind-merge": "^3.5.0",
|
|
48
|
-
"@h-ai/core": "0.1.0-alpha.
|
|
48
|
+
"@h-ai/core": "0.1.0-alpha.26"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@sveltejs/package": "^2.5.7",
|