create-halo-plugin-template 1.0.0 → 1.0.1

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.
Files changed (108) hide show
  1. package/.editorconfig +520 -0
  2. package/.github/workflows/cd.yaml +20 -0
  3. package/.github/workflows/ci.yaml +32 -0
  4. package/.github/workflows/publish-npm.yaml +46 -0
  5. package/.gitignore +84 -0
  6. package/LICENSE +674 -0
  7. package/README.md +191 -0
  8. package/build.gradle +103 -0
  9. package/docs/first-npm-release-checklist.md +58 -0
  10. package/docs/publish-template.md +148 -0
  11. package/docs/rsbuild-switch.md +90 -0
  12. package/docs/template-pruning.md +43 -0
  13. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  14. package/gradle/wrapper/gradle-wrapper.properties +7 -0
  15. package/gradle.properties +1 -0
  16. package/gradlew +248 -0
  17. package/gradlew.bat +93 -0
  18. package/package.json +67 -7
  19. package/scripts/create-project.mjs +399 -0
  20. package/scripts/init-template.mjs +281 -0
  21. package/scripts/publish-check.mjs +97 -0
  22. package/scripts/release.mjs +278 -0
  23. package/scripts/verify-template.mjs +407 -0
  24. package/settings.gradle +7 -0
  25. package/src/main/java/run/halo/plugintemplate/PluginTemplatePlugin.java +43 -0
  26. package/src/main/java/run/halo/plugintemplate/config/PluginTemplateConfig.java +14 -0
  27. package/src/main/java/run/halo/plugintemplate/dto/PluginTemplateChecklistItem.java +30 -0
  28. package/src/main/java/run/halo/plugintemplate/dto/PluginTemplateFeatureItem.java +30 -0
  29. package/src/main/java/run/halo/plugintemplate/dto/PluginTemplateOverview.java +73 -0
  30. package/src/main/java/run/halo/plugintemplate/dto/PluginTemplateStatItem.java +30 -0
  31. package/src/main/java/run/halo/plugintemplate/endpoint/PluginTemplateConsoleEndpoint.java +33 -0
  32. package/src/main/java/run/halo/plugintemplate/endpoint/PluginTemplatePublicEndpoint.java +26 -0
  33. package/src/main/java/run/halo/plugintemplate/endpoint/PluginTemplateUcEndpoint.java +33 -0
  34. package/src/main/java/run/halo/plugintemplate/endpoint/routes/PluginTemplateOverviewRoutes.java +60 -0
  35. package/src/main/java/run/halo/plugintemplate/model/PluginTemplateAudience.java +23 -0
  36. package/src/main/java/run/halo/plugintemplate/query/PluginTemplateOverviewQuery.java +26 -0
  37. package/src/main/java/run/halo/plugintemplate/reconcile/PluginTemplateSettingsReconciler.java +17 -0
  38. package/src/main/java/run/halo/plugintemplate/scheme/PluginTemplateRecord.java +43 -0
  39. package/src/main/java/run/halo/plugintemplate/service/PluginTemplateOverviewService.java +10 -0
  40. package/src/main/java/run/halo/plugintemplate/service/impl/PluginTemplateOverviewServiceImpl.java +74 -0
  41. package/src/main/java/run/halo/plugintemplate/setting/PluginTemplateGeneralSetting.java +25 -0
  42. package/src/main/java/run/halo/plugintemplate/setting/PluginTemplateSettingKeys.java +24 -0
  43. package/src/main/java/run/halo/plugintemplate/setting/PluginTemplateUiSetting.java +13 -0
  44. package/src/main/java/run/halo/plugintemplate/utils/PluginTemplateSeeds.java +197 -0
  45. package/src/main/resources/extensions/roleTemplate-console.yaml +39 -0
  46. package/src/main/resources/extensions/roleTemplate-uc.yaml +19 -0
  47. package/src/main/resources/extensions/settings.yaml +47 -0
  48. package/src/main/resources/logo.png +0 -0
  49. package/src/main/resources/plugin.yaml +24 -0
  50. package/src/test/java/run/halo/plugintemplate/PluginTemplatePluginTest.java +34 -0
  51. package/src/test/java/run/halo/plugintemplate/service/impl/PluginTemplateOverviewServiceImplTest.java +97 -0
  52. package/ui/build.gradle +41 -0
  53. package/ui/env.d.ts +2 -0
  54. package/ui/eslint.config.ts +30 -0
  55. package/ui/package.json +57 -0
  56. package/ui/pnpm-lock.yaml +5250 -0
  57. package/ui/src/api/__tests__/normalizers.spec.ts +65 -0
  58. package/ui/src/api/generated/.openapi-generator/FILES +23 -0
  59. package/ui/src/api/generated/.openapi-generator/VERSION +1 -0
  60. package/ui/src/api/generated/.openapi-generator-ignore +23 -0
  61. package/ui/src/api/generated/api/plugin-template-console-api.ts +128 -0
  62. package/ui/src/api/generated/api/plugin-template-uc-api.ts +128 -0
  63. package/ui/src/api/generated/api.ts +19 -0
  64. package/ui/src/api/generated/base.ts +86 -0
  65. package/ui/src/api/generated/common.ts +150 -0
  66. package/ui/src/api/generated/configuration.ts +110 -0
  67. package/ui/src/api/generated/git_push.sh +57 -0
  68. package/ui/src/api/generated/index.ts +18 -0
  69. package/ui/src/api/generated/models/add-operation.ts +49 -0
  70. package/ui/src/api/generated/models/copy-operation.ts +49 -0
  71. package/ui/src/api/generated/models/index.ts +11 -0
  72. package/ui/src/api/generated/models/json-patch-inner.ts +41 -0
  73. package/ui/src/api/generated/models/move-operation.ts +49 -0
  74. package/ui/src/api/generated/models/plugin-template-checklist-item.ts +54 -0
  75. package/ui/src/api/generated/models/plugin-template-feature-item.ts +54 -0
  76. package/ui/src/api/generated/models/plugin-template-overview.ts +147 -0
  77. package/ui/src/api/generated/models/plugin-template-stat-item.ts +54 -0
  78. package/ui/src/api/generated/models/remove-operation.ts +43 -0
  79. package/ui/src/api/generated/models/replace-operation.ts +49 -0
  80. package/ui/src/api/generated/models/test-operation.ts +49 -0
  81. package/ui/src/api/index.ts +42 -0
  82. package/ui/src/api/normalizers.ts +65 -0
  83. package/ui/src/assets/element.scss +24 -0
  84. package/ui/src/assets/index.css +361 -0
  85. package/ui/src/assets/logo.svg +1 -0
  86. package/ui/src/components/PluginTemplateAttachmentTab.vue +69 -0
  87. package/ui/src/components/PluginTemplateCommonTable.vue +69 -0
  88. package/ui/src/components/PluginTemplateDashboardWidget.vue +62 -0
  89. package/ui/src/components/PluginTemplateOverviewPage.vue +254 -0
  90. package/ui/src/components/ui/PluginUiProvider.vue +40 -0
  91. package/ui/src/components/ui/UiMetricCard.vue +21 -0
  92. package/ui/src/components/ui/UiSectionCard.vue +25 -0
  93. package/ui/src/components/ui/UiStatusPill.vue +18 -0
  94. package/ui/src/composables/useTemplateOverview.ts +38 -0
  95. package/ui/src/index.ts +88 -0
  96. package/ui/src/lib/__tests__/plugin-ui.spec.ts +19 -0
  97. package/ui/src/lib/plugin-ui.ts +19 -0
  98. package/ui/src/lib/template.spec.ts +24 -0
  99. package/ui/src/lib/template.ts +52 -0
  100. package/ui/src/lib/theme.ts +31 -0
  101. package/ui/src/types/index.ts +59 -0
  102. package/ui/src/views/console/ConsoleDashboardView.vue +7 -0
  103. package/ui/src/views/uc/UcDashboardView.vue +7 -0
  104. package/ui/tsconfig.app.json +12 -0
  105. package/ui/tsconfig.json +14 -0
  106. package/ui/tsconfig.node.json +15 -0
  107. package/ui/tsconfig.vitest.json +11 -0
  108. package/ui/vite.config.ts +25 -0
@@ -0,0 +1,43 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /**
4
+ * Halo
5
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
6
+ *
7
+ * The version of the OpenAPI document: 2.23.2
8
+ *
9
+ *
10
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11
+ * https://openapi-generator.tech
12
+ * Do not edit the class manually.
13
+ */
14
+
15
+
16
+
17
+ /**
18
+ *
19
+ * @export
20
+ * @interface RemoveOperation
21
+ */
22
+ export interface RemoveOperation {
23
+ /**
24
+ *
25
+ * @type {string}
26
+ * @memberof RemoveOperation
27
+ */
28
+ 'op': RemoveOperationOpEnum;
29
+ /**
30
+ * A JSON Pointer path pointing to the location to move/copy from.
31
+ * @type {string}
32
+ * @memberof RemoveOperation
33
+ */
34
+ 'path': string;
35
+ }
36
+
37
+ export const RemoveOperationOpEnum = {
38
+ Remove: 'remove'
39
+ } as const;
40
+
41
+ export type RemoveOperationOpEnum = typeof RemoveOperationOpEnum[keyof typeof RemoveOperationOpEnum];
42
+
43
+
@@ -0,0 +1,49 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /**
4
+ * Halo
5
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
6
+ *
7
+ * The version of the OpenAPI document: 2.23.2
8
+ *
9
+ *
10
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11
+ * https://openapi-generator.tech
12
+ * Do not edit the class manually.
13
+ */
14
+
15
+
16
+
17
+ /**
18
+ *
19
+ * @export
20
+ * @interface ReplaceOperation
21
+ */
22
+ export interface ReplaceOperation {
23
+ /**
24
+ *
25
+ * @type {string}
26
+ * @memberof ReplaceOperation
27
+ */
28
+ 'op': ReplaceOperationOpEnum;
29
+ /**
30
+ * A JSON Pointer path pointing to the location to move/copy from.
31
+ * @type {string}
32
+ * @memberof ReplaceOperation
33
+ */
34
+ 'path': string;
35
+ /**
36
+ * Value can be any JSON value
37
+ * @type {any}
38
+ * @memberof ReplaceOperation
39
+ */
40
+ 'value': any;
41
+ }
42
+
43
+ export const ReplaceOperationOpEnum = {
44
+ Replace: 'replace'
45
+ } as const;
46
+
47
+ export type ReplaceOperationOpEnum = typeof ReplaceOperationOpEnum[keyof typeof ReplaceOperationOpEnum];
48
+
49
+
@@ -0,0 +1,49 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /**
4
+ * Halo
5
+ * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
6
+ *
7
+ * The version of the OpenAPI document: 2.23.2
8
+ *
9
+ *
10
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11
+ * https://openapi-generator.tech
12
+ * Do not edit the class manually.
13
+ */
14
+
15
+
16
+
17
+ /**
18
+ *
19
+ * @export
20
+ * @interface TestOperation
21
+ */
22
+ export interface TestOperation {
23
+ /**
24
+ *
25
+ * @type {string}
26
+ * @memberof TestOperation
27
+ */
28
+ 'op': TestOperationOpEnum;
29
+ /**
30
+ * A JSON Pointer path pointing to the location to move/copy from.
31
+ * @type {string}
32
+ * @memberof TestOperation
33
+ */
34
+ 'path': string;
35
+ /**
36
+ * Value can be any JSON value
37
+ * @type {any}
38
+ * @memberof TestOperation
39
+ */
40
+ 'value': any;
41
+ }
42
+
43
+ export const TestOperationOpEnum = {
44
+ Test: 'test'
45
+ } as const;
46
+
47
+ export type TestOperationOpEnum = typeof TestOperationOpEnum[keyof typeof TestOperationOpEnum];
48
+
49
+
@@ -0,0 +1,42 @@
1
+ import { axiosInstance } from '@halo-dev/api-client'
2
+ import {
3
+ Configuration,
4
+ PluginTemplateConsoleApi,
5
+ PluginTemplateUcApi,
6
+ } from '@/api/generated'
7
+ import { normalizeOverview } from '@/api/normalizers'
8
+ import type { PluginTemplateOverview } from '@/types'
9
+
10
+ // Keep this file as the only API import surface for UI code.
11
+ // Generated clients stay behind this wrapper so views and components never import them directly.
12
+
13
+ const generatedClientConfiguration = new Configuration({
14
+ basePath: '',
15
+ })
16
+
17
+ const consoleApi = new PluginTemplateConsoleApi(
18
+ generatedClientConfiguration,
19
+ '',
20
+ axiosInstance,
21
+ )
22
+ const ucApi = new PluginTemplateUcApi(
23
+ generatedClientConfiguration,
24
+ '',
25
+ axiosInstance,
26
+ )
27
+
28
+ export const templateConsoleApi = {
29
+ getOverview: async (): Promise<PluginTemplateOverview> => {
30
+ const response = await consoleApi.pluginTemplateOverviewForConsole()
31
+ return normalizeOverview(response.data)
32
+ },
33
+ }
34
+
35
+ export const templateUcApi = {
36
+ getOverview: async (): Promise<PluginTemplateOverview> => {
37
+ const response = await ucApi.pluginTemplateOverviewForUc()
38
+ return normalizeOverview(response.data)
39
+ },
40
+ }
41
+
42
+ export type { PluginTemplateOverview }
@@ -0,0 +1,65 @@
1
+ import type {
2
+ PluginTemplateChecklistItem as RawPluginTemplateChecklistItem,
3
+ PluginTemplateFeatureItem as RawPluginTemplateFeatureItem,
4
+ PluginTemplateOverview as RawPluginTemplateOverview,
5
+ PluginTemplateStatItem as RawPluginTemplateStatItem,
6
+ } from '@/api/generated'
7
+ import type { PluginTemplateOverview } from '@/types'
8
+
9
+ export type RawTemplateOverview = RawPluginTemplateOverview & {
10
+ enableConsoleDashboard?: boolean
11
+ enableUcDashboard?: boolean
12
+ enableAttachmentProvider?: boolean
13
+ accentColor?: string
14
+ density?: string
15
+ supportLink?: string
16
+ }
17
+
18
+ export const normalizeStats = (stats?: RawPluginTemplateStatItem[]) =>
19
+ (stats ?? []).map((item, index) => ({
20
+ key: item.key || `stat-${index}`,
21
+ label: item.label || '未命名指标',
22
+ value: item.value || '—',
23
+ helper: item.helper || '',
24
+ tone: item.tone || 'info',
25
+ }))
26
+
27
+ export const normalizeFeatures = (features?: RawPluginTemplateFeatureItem[]) =>
28
+ (features ?? []).map((item, index) => ({
29
+ key: item.key || `feature-${index}`,
30
+ title: item.title || '未命名能力',
31
+ area: item.area || 'General',
32
+ description: item.description || '',
33
+ enabled: Boolean(item.enabled),
34
+ }))
35
+
36
+ export const normalizeChecklist = (checklist?: RawPluginTemplateChecklistItem[]) =>
37
+ (checklist ?? []).map((item, index) => ({
38
+ key: item.key || `checklist-${index}`,
39
+ title: item.title || '未命名检查项',
40
+ description: item.description || '',
41
+ audience: item.audience || 'all',
42
+ status: item.status || 'todo',
43
+ }))
44
+
45
+ export const normalizeOverview = (overview: RawTemplateOverview): PluginTemplateOverview => ({
46
+ pluginName: overview.pluginName || 'halo-plugin-template',
47
+ displayName: overview.displayName || 'Halo Plugin Template',
48
+ audience: overview.audience || 'console',
49
+ audienceLabel: overview.audienceLabel || 'Console',
50
+ consolePath: overview.consolePath || '/halo-plugin-template',
51
+ ucPath: overview.ucPath || '/halo-plugin-template',
52
+ settingName: overview.settingName || 'halo-plugin-template-settings',
53
+ configMapName: overview.configMapName || 'halo-plugin-template-configmap',
54
+ generatedClientPath: overview.generatedClientPath || 'ui/src/api/generated',
55
+ generatedAt: overview.generatedAt || '',
56
+ enableConsoleDashboard: overview.enableConsoleDashboard ?? true,
57
+ enableUcDashboard: overview.enableUcDashboard ?? true,
58
+ enableAttachmentProvider: overview.enableAttachmentProvider ?? true,
59
+ accentColor: overview.accentColor || '#2457F5',
60
+ density: overview.density || 'balanced',
61
+ supportLink: overview.supportLink || 'https://docs.halo.run/developer-guide/plugin/introduction',
62
+ stats: normalizeStats(overview.stats),
63
+ features: normalizeFeatures(overview.features),
64
+ checklist: normalizeChecklist(overview.checklist),
65
+ })
@@ -0,0 +1,24 @@
1
+ .halo-plugin-template-admin-shell {
2
+ --el-color-primary: var(--halo-plugin-template-color-primary);
3
+ --el-color-success: var(--halo-plugin-template-color-accent);
4
+ --el-color-warning: var(--halo-plugin-template-color-warning);
5
+ --el-color-danger: var(--halo-plugin-template-color-danger);
6
+ --el-border-radius-base: 14px;
7
+ --el-border-color: rgba(148, 163, 184, 0.16);
8
+ --el-fill-color-blank: transparent;
9
+ --el-bg-color: rgba(255, 255, 255, 0.92);
10
+ --el-bg-color-page: transparent;
11
+ --el-text-color-primary: var(--halo-plugin-template-text-primary);
12
+ --el-text-color-regular: var(--halo-plugin-template-text-secondary);
13
+ --el-text-color-placeholder: var(--halo-plugin-template-text-muted);
14
+ --el-table-border-color: rgba(148, 163, 184, 0.12);
15
+ --el-table-header-bg-color: rgba(248, 250, 252, 0.86);
16
+ --el-table-row-hover-bg-color: rgba(36, 87, 245, 0.06);
17
+ }
18
+
19
+ .halo-plugin-template-admin-shell.dark {
20
+ --el-bg-color: rgba(15, 23, 42, 0.88);
21
+ --el-fill-color-blank: rgba(15, 23, 42, 0.72);
22
+ --el-table-header-bg-color: rgba(30, 41, 59, 0.88);
23
+ --el-table-tr-bg-color: transparent;
24
+ }
@@ -0,0 +1,361 @@
1
+ :root {
2
+ --halo-plugin-template-color-primary: #2457f5;
3
+ --halo-plugin-template-color-accent: #13b77a;
4
+ --halo-plugin-template-color-warning: #ff8f1f;
5
+ --halo-plugin-template-color-danger: #e14d5f;
6
+ --halo-plugin-template-surface: rgba(255, 255, 255, 0.92);
7
+ --halo-plugin-template-surface-secondary: rgba(248, 250, 252, 0.88);
8
+ --halo-plugin-template-surface-border: rgba(15, 23, 42, 0.08);
9
+ --halo-plugin-template-text-primary: #0f172a;
10
+ --halo-plugin-template-text-secondary: #475569;
11
+ --halo-plugin-template-text-muted: #64748b;
12
+ --halo-plugin-template-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
13
+ --halo-plugin-template-shadow-soft: 0 10px 30px rgba(15, 23, 42, 0.06);
14
+ --halo-plugin-template-radius-xl: 28px;
15
+ --halo-plugin-template-radius-lg: 20px;
16
+ --halo-plugin-template-radius-md: 14px;
17
+ }
18
+
19
+ .halo-plugin-template-admin-shell {
20
+ min-height: 100%;
21
+ color: var(--halo-plugin-template-text-primary);
22
+ }
23
+
24
+ .halo-plugin-template-admin-shell.dark {
25
+ --halo-plugin-template-surface: rgba(15, 23, 42, 0.82);
26
+ --halo-plugin-template-surface-secondary: rgba(15, 23, 42, 0.72);
27
+ --halo-plugin-template-surface-border: rgba(148, 163, 184, 0.18);
28
+ --halo-plugin-template-text-primary: #e2e8f0;
29
+ --halo-plugin-template-text-secondary: #cbd5e1;
30
+ --halo-plugin-template-text-muted: #94a3b8;
31
+ --halo-plugin-template-shadow: 0 18px 46px rgba(2, 6, 23, 0.28);
32
+ --halo-plugin-template-shadow-soft: 0 10px 30px rgba(2, 6, 23, 0.24);
33
+ }
34
+
35
+ .halo-plugin-template-admin-page {
36
+ width: min(1240px, 100%);
37
+ margin: 0 auto;
38
+ padding: 24px 24px 56px;
39
+ display: flex;
40
+ flex-direction: column;
41
+ gap: 24px;
42
+ }
43
+
44
+ .halo-plugin-template-admin-hero {
45
+ position: relative;
46
+ overflow: hidden;
47
+ padding: 28px;
48
+ border-radius: var(--halo-plugin-template-radius-xl);
49
+ background:
50
+ radial-gradient(circle at top left, rgba(36, 87, 245, 0.16), transparent 42%),
51
+ radial-gradient(circle at bottom right, rgba(19, 183, 122, 0.18), transparent 38%),
52
+ linear-gradient(135deg, rgba(255, 255, 255, 0.94), rgba(248, 250, 252, 0.92));
53
+ border: 1px solid var(--halo-plugin-template-surface-border);
54
+ box-shadow: var(--halo-plugin-template-shadow);
55
+ display: grid;
56
+ grid-template-columns: minmax(0, 1fr) auto;
57
+ gap: 24px;
58
+ }
59
+
60
+ .halo-plugin-template-admin-shell.dark .halo-plugin-template-admin-hero {
61
+ background:
62
+ radial-gradient(circle at top left, rgba(36, 87, 245, 0.2), transparent 42%),
63
+ radial-gradient(circle at bottom right, rgba(19, 183, 122, 0.2), transparent 38%),
64
+ linear-gradient(135deg, rgba(15, 23, 42, 0.9), rgba(15, 23, 42, 0.82));
65
+ }
66
+
67
+ .halo-plugin-template-admin-eyebrow {
68
+ margin: 0 0 8px;
69
+ font-size: 12px;
70
+ letter-spacing: 0.12em;
71
+ text-transform: uppercase;
72
+ color: var(--halo-plugin-template-text-muted);
73
+ }
74
+
75
+ .halo-plugin-template-admin-title {
76
+ margin: 0;
77
+ font-size: clamp(28px, 3vw, 40px);
78
+ line-height: 1.08;
79
+ font-weight: 700;
80
+ }
81
+
82
+ .halo-plugin-template-admin-description {
83
+ margin: 12px 0 0;
84
+ max-width: 760px;
85
+ color: var(--halo-plugin-template-text-secondary);
86
+ line-height: 1.7;
87
+ }
88
+
89
+ .halo-plugin-template-admin-meta {
90
+ margin-top: 16px;
91
+ display: flex;
92
+ flex-wrap: wrap;
93
+ gap: 10px;
94
+ }
95
+
96
+ .halo-plugin-template-admin-meta-item {
97
+ display: inline-flex;
98
+ align-items: center;
99
+ gap: 8px;
100
+ padding: 8px 12px;
101
+ border-radius: 999px;
102
+ background: rgba(255, 255, 255, 0.62);
103
+ border: 1px solid rgba(148, 163, 184, 0.18);
104
+ color: var(--halo-plugin-template-text-secondary);
105
+ font-size: 13px;
106
+ }
107
+
108
+ .halo-plugin-template-admin-shell.dark .halo-plugin-template-admin-meta-item {
109
+ background: rgba(15, 23, 42, 0.58);
110
+ }
111
+
112
+ .halo-plugin-template-admin-hero-actions {
113
+ display: flex;
114
+ align-items: start;
115
+ justify-content: flex-end;
116
+ gap: 12px;
117
+ flex-wrap: wrap;
118
+ }
119
+
120
+ .halo-plugin-template-admin-section {
121
+ display: grid;
122
+ grid-template-columns: repeat(12, minmax(0, 1fr));
123
+ gap: 20px;
124
+ }
125
+
126
+ .halo-plugin-template-admin-section > * {
127
+ grid-column: span 12;
128
+ }
129
+
130
+ .halo-plugin-template-admin-surface {
131
+ border: 1px solid var(--halo-plugin-template-surface-border);
132
+ border-radius: var(--halo-plugin-template-radius-lg);
133
+ background: var(--halo-plugin-template-surface);
134
+ box-shadow: var(--halo-plugin-template-shadow-soft);
135
+ }
136
+
137
+ .halo-plugin-template-admin-card-header {
138
+ display: flex;
139
+ align-items: flex-start;
140
+ justify-content: space-between;
141
+ gap: 16px;
142
+ }
143
+
144
+ .halo-plugin-template-admin-card-title {
145
+ margin: 0;
146
+ font-size: 18px;
147
+ font-weight: 700;
148
+ }
149
+
150
+ .halo-plugin-template-admin-card-description {
151
+ margin: 8px 0 0;
152
+ color: var(--halo-plugin-template-text-secondary);
153
+ line-height: 1.6;
154
+ }
155
+
156
+ .halo-plugin-template-admin-stats {
157
+ display: grid;
158
+ grid-template-columns: repeat(3, minmax(0, 1fr));
159
+ gap: 16px;
160
+ }
161
+
162
+ .halo-plugin-template-admin-stat {
163
+ height: 100%;
164
+ padding: 18px;
165
+ border-radius: var(--halo-plugin-template-radius-lg);
166
+ border: 1px solid rgba(148, 163, 184, 0.18);
167
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.76), rgba(248, 250, 252, 0.86));
168
+ }
169
+
170
+ .halo-plugin-template-admin-shell.dark .halo-plugin-template-admin-stat {
171
+ background: linear-gradient(180deg, rgba(15, 23, 42, 0.88), rgba(15, 23, 42, 0.72));
172
+ }
173
+
174
+ .halo-plugin-template-admin-stat-label {
175
+ margin: 0 0 8px;
176
+ color: var(--halo-plugin-template-text-muted);
177
+ font-size: 13px;
178
+ }
179
+
180
+ .halo-plugin-template-admin-stat-value {
181
+ margin: 0;
182
+ font-size: 30px;
183
+ font-weight: 700;
184
+ }
185
+
186
+ .halo-plugin-template-admin-stat-helper {
187
+ margin: 12px 0 0;
188
+ color: var(--halo-plugin-template-text-secondary);
189
+ line-height: 1.6;
190
+ }
191
+
192
+ .halo-plugin-template-admin-grid {
193
+ display: grid;
194
+ grid-template-columns: repeat(2, minmax(0, 1fr));
195
+ gap: 20px;
196
+ }
197
+
198
+ .halo-plugin-template-admin-kpis,
199
+ .halo-plugin-template-admin-checklist {
200
+ display: grid;
201
+ gap: 14px;
202
+ }
203
+
204
+ .halo-plugin-template-admin-checklist-item {
205
+ display: flex;
206
+ align-items: flex-start;
207
+ justify-content: space-between;
208
+ gap: 16px;
209
+ padding: 14px 16px;
210
+ border-radius: var(--halo-plugin-template-radius-md);
211
+ background: var(--halo-plugin-template-surface-secondary);
212
+ border: 1px solid rgba(148, 163, 184, 0.14);
213
+ }
214
+
215
+ .halo-plugin-template-admin-checklist-copy {
216
+ display: grid;
217
+ gap: 4px;
218
+ }
219
+
220
+ .halo-plugin-template-admin-checklist-title {
221
+ margin: 0;
222
+ font-size: 14px;
223
+ font-weight: 600;
224
+ }
225
+
226
+ .halo-plugin-template-admin-checklist-description {
227
+ margin: 0;
228
+ color: var(--halo-plugin-template-text-secondary);
229
+ line-height: 1.5;
230
+ }
231
+
232
+ .halo-plugin-template-admin-widget {
233
+ height: 100%;
234
+ display: grid;
235
+ gap: 16px;
236
+ }
237
+
238
+ .halo-plugin-template-admin-widget-header {
239
+ display: flex;
240
+ justify-content: space-between;
241
+ gap: 16px;
242
+ align-items: flex-start;
243
+ }
244
+
245
+ .halo-plugin-template-admin-widget-title {
246
+ margin: 0;
247
+ font-size: 16px;
248
+ font-weight: 700;
249
+ }
250
+
251
+ .halo-plugin-template-admin-widget-description {
252
+ margin: 8px 0 0;
253
+ color: var(--halo-plugin-template-text-secondary);
254
+ line-height: 1.6;
255
+ }
256
+
257
+ .halo-plugin-template-admin-widget-stats {
258
+ display: grid;
259
+ grid-template-columns: repeat(2, minmax(0, 1fr));
260
+ gap: 12px;
261
+ }
262
+
263
+ .halo-plugin-template-admin-widget-stat {
264
+ padding: 14px;
265
+ border-radius: var(--halo-plugin-template-radius-md);
266
+ background: var(--halo-plugin-template-surface-secondary);
267
+ border: 1px solid rgba(148, 163, 184, 0.14);
268
+ }
269
+
270
+ .halo-plugin-template-admin-attachment-list {
271
+ display: grid;
272
+ gap: 12px;
273
+ }
274
+
275
+ .halo-plugin-template-admin-attachment-item {
276
+ padding: 16px;
277
+ border-radius: var(--halo-plugin-template-radius-md);
278
+ border: 1px solid rgba(148, 163, 184, 0.14);
279
+ background: var(--halo-plugin-template-surface-secondary);
280
+ display: grid;
281
+ gap: 12px;
282
+ }
283
+
284
+ .halo-plugin-template-admin-attachment-preview {
285
+ width: 100%;
286
+ max-width: 128px;
287
+ aspect-ratio: 1;
288
+ border-radius: 18px;
289
+ border: 1px solid rgba(148, 163, 184, 0.14);
290
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.9), rgba(241, 245, 249, 0.9));
291
+ display: inline-flex;
292
+ align-items: center;
293
+ justify-content: center;
294
+ overflow: hidden;
295
+ }
296
+
297
+ .halo-plugin-template-admin-attachment-preview img {
298
+ width: 72%;
299
+ height: 72%;
300
+ object-fit: contain;
301
+ }
302
+
303
+ .halo-plugin-template-admin-table-desktop {
304
+ display: block;
305
+ }
306
+
307
+ .halo-plugin-template-admin-table-mobile {
308
+ display: none;
309
+ }
310
+
311
+ .halo-plugin-template-admin-table-card {
312
+ display: grid;
313
+ gap: 12px;
314
+ padding: 16px;
315
+ border-radius: var(--halo-plugin-template-radius-md);
316
+ background: var(--halo-plugin-template-surface-secondary);
317
+ border: 1px solid rgba(148, 163, 184, 0.14);
318
+ }
319
+
320
+ .halo-plugin-template-admin-table-card-row {
321
+ display: grid;
322
+ gap: 4px;
323
+ }
324
+
325
+ .halo-plugin-template-admin-table-card-label {
326
+ font-size: 12px;
327
+ text-transform: uppercase;
328
+ letter-spacing: 0.08em;
329
+ color: var(--halo-plugin-template-text-muted);
330
+ }
331
+
332
+ .halo-plugin-template-admin-table-card-value {
333
+ color: var(--halo-plugin-template-text-primary);
334
+ }
335
+
336
+ @media (max-width: 960px) {
337
+ .halo-plugin-template-admin-hero,
338
+ .halo-plugin-template-admin-grid,
339
+ .halo-plugin-template-admin-stats {
340
+ grid-template-columns: minmax(0, 1fr);
341
+ }
342
+ }
343
+
344
+ @media (max-width: 768px) {
345
+ .halo-plugin-template-admin-page {
346
+ padding: 18px 18px 42px;
347
+ }
348
+
349
+ .halo-plugin-template-admin-widget-stats {
350
+ grid-template-columns: minmax(0, 1fr);
351
+ }
352
+
353
+ .halo-plugin-template-admin-table-desktop {
354
+ display: none;
355
+ }
356
+
357
+ .halo-plugin-template-admin-table-mobile {
358
+ display: grid;
359
+ gap: 12px;
360
+ }
361
+ }
@@ -0,0 +1 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 2144 877" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><path d="M1028.16,339.331c148.249,0 268.609,120.36 268.609,268.609c-0,148.249 -120.36,268.608 -268.609,268.608c-148.249,0 -268.608,-120.359 -268.608,-268.608c-0,-148.249 120.359,-268.609 268.608,-268.609Zm0,119.152c82.488,0 149.457,66.969 149.457,149.457c-0,82.487 -66.969,149.456 -149.457,149.456c-82.487,0 -149.456,-66.969 -149.456,-149.456c-0,-82.488 66.969,-149.457 149.456,-149.457Z" style="fill:url(#_Linear1);"/><path d="M1874.58,339.331c148.249,0 268.608,120.36 268.608,268.609c0,148.249 -120.359,268.608 -268.608,268.608c-148.249,0 -268.609,-120.359 -268.609,-268.608c0,-148.249 120.36,-268.609 268.609,-268.609Zm-0,119.152c82.487,0 149.456,66.969 149.456,149.457c0,82.487 -66.969,149.456 -149.456,149.456c-82.488,0 -149.457,-66.969 -149.457,-149.456c0,-82.488 66.969,-149.457 149.457,-149.457Z" style="fill:url(#_Linear2);"/><path d="M1309.27,377.585c-0,-10.083 -7.222,-18.719 -17.146,-20.504c-19.618,-3.528 -51.9,-9.334 -74.172,-13.34c-6.073,-1.092 -12.318,0.564 -17.052,4.522c-4.734,3.959 -7.469,9.812 -7.469,15.983c-0,91.374 -0,407.153 -0,491.469c-0,5.525 2.195,10.824 6.102,14.731c3.907,3.907 9.206,6.102 14.731,6.102c20.987,0 53.186,0 74.173,0c5.525,0 10.824,-2.195 14.731,-6.102c3.907,-3.907 6.102,-9.206 6.102,-14.731c-0,-84.425 -0,-400.286 -0,-478.13Z" style="fill:url(#_Linear3);"/><path d="M1542.59,72.033c0,-8.288 -3.292,-16.237 -9.153,-22.097c-5.86,-5.861 -13.809,-9.153 -22.097,-9.153c-23.867,-0 -56.609,-0 -80.477,-0c-8.288,-0 -16.236,3.292 -22.097,9.153c-5.86,5.86 -9.153,13.809 -9.153,22.097c0,131.79 0,641.475 0,773.265c0,8.288 3.293,16.237 9.153,22.097c5.861,5.861 13.809,9.153 22.097,9.153c23.868,0 56.61,0 80.477,0c8.288,0 16.237,-3.292 22.097,-9.153c5.861,-5.86 9.153,-13.809 9.153,-22.097c0,-131.79 0,-641.475 0,-773.265Z" style="fill:url(#_Linear4);fill-rule:nonzero;"/><g><path d="M506.409,822.063c-0,13.815 5.494,27.062 15.271,36.821c9.777,9.76 23.034,15.23 36.848,15.206c18.674,-0.034 39.711,-0.072 58.369,-0.105c28.696,-0.052 51.932,-23.329 51.932,-52.026l0,-769.586c0,-13.798 -5.481,-27.031 -15.238,-36.788c-9.756,-9.757 -22.99,-15.238 -36.788,-15.238l-58.368,-0c-13.798,-0 -27.031,5.481 -36.788,15.238c-9.757,9.757 -15.238,22.99 -15.238,36.788c-0,155.286 -0,614.283 -0,769.69Z" style="fill:url(#_Linear5);fill-rule:nonzero;"/><path d="M616.746,322.662c13.813,0 27.061,5.487 36.829,15.255c9.767,9.768 15.254,23.015 15.254,36.829c0,105.185 0,341.877 0,447.062c0,13.814 -5.487,27.061 -15.254,36.829c-9.768,9.767 -23.016,15.255 -36.829,15.255c-18.632,-0 -39.622,-0 -58.254,-0c-13.813,-0 -27.061,-5.488 -36.828,-15.255c-9.768,-9.768 -15.255,-23.015 -15.255,-36.829c-0,-68.223 -0,-187.159 -0,-255.383c-0,-13.813 -5.487,-27.061 -15.255,-36.828c-9.767,-9.768 -23.015,-15.255 -36.828,-15.255c-129.249,-0 -454.326,-0 -454.326,-0l0,-191.68l616.746,0Z" style="fill:#0051b0;fill-rule:nonzero;"/><path d="M-0,822.101c0,13.817 5.497,27.067 15.277,36.827c9.781,9.76 23.043,15.229 36.86,15.199c18.675,-0.04 39.713,-0.085 58.368,-0.124c28.69,-0.062 51.916,-23.337 51.916,-52.027c-0,-155.205 -0,-614.509 -0,-769.714c-0,-28.69 -23.226,-51.965 -51.916,-52.026c-18.655,-0.04 -39.693,-0.085 -58.368,-0.125c-13.817,-0.029 -27.079,5.439 -36.86,15.199c-9.78,9.76 -15.277,23.01 -15.277,36.827l-0,769.964Z" style="fill:url(#_Linear6);fill-rule:nonzero;"/></g><defs><linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(5.19814e-14,-848.921,848.921,5.19814e-14,1308.8,875.397)"><stop offset="0" style="stop-color:#0050b5;stop-opacity:1"/><stop offset="1" style="stop-color:#0b87fd;stop-opacity:1"/></linearGradient><linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(5.19814e-14,-848.921,848.921,5.19814e-14,1308.8,875.397)"><stop offset="0" style="stop-color:#0050b5;stop-opacity:1"/><stop offset="1" style="stop-color:#0b87fd;stop-opacity:1"/></linearGradient><linearGradient id="_Linear3" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(5.19814e-14,-848.921,848.921,5.19814e-14,1308.8,875.397)"><stop offset="0" style="stop-color:#0050b5;stop-opacity:1"/><stop offset="1" style="stop-color:#0b87fd;stop-opacity:1"/></linearGradient><linearGradient id="_Linear4" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(5.19814e-14,-848.921,848.921,5.19814e-14,1308.8,875.397)"><stop offset="0" style="stop-color:#0050b5;stop-opacity:1"/><stop offset="1" style="stop-color:#0b87fd;stop-opacity:1"/></linearGradient><linearGradient id="_Linear5" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-3.91885e-13,472.459,-473.895,-3.90698e-13,587.619,-0.861651)"><stop offset="0" style="stop-color:#0048af;stop-opacity:1"/><stop offset="1" style="stop-color:#003580;stop-opacity:1"/></linearGradient><linearGradient id="_Linear6" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(5.51848e-14,898.506,-901.236,5.50176e-14,162.421,-12.1337)"><stop offset="0" style="stop-color:#0b89ff;stop-opacity:1"/><stop offset="1" style="stop-color:#004eb2;stop-opacity:1"/></linearGradient></defs></svg>