xinyu-pro 0.21.0

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 (96) hide show
  1. package/.env.example +21 -0
  2. package/README.md +36 -0
  3. package/app/api/chat/route.ts +84 -0
  4. package/app/api/generate-svg/route.ts +171 -0
  5. package/app/api/generate-theme/route.ts +137 -0
  6. package/app/api/plugins/bindings/route.ts +173 -0
  7. package/app/api/plugins/export/route.ts +122 -0
  8. package/app/api/plugins/export-xye/route.ts +156 -0
  9. package/app/api/plugins/files/route.ts +146 -0
  10. package/app/api/plugins/files-list/route.ts +168 -0
  11. package/app/api/plugins/files-upload/route.ts +101 -0
  12. package/app/api/plugins/files-write/route.ts +272 -0
  13. package/app/api/plugins/import/route.ts +140 -0
  14. package/app/api/plugins/import-package/route.ts +231 -0
  15. package/app/api/plugins/resources/route.ts +109 -0
  16. package/app/api/plugins/route.ts +308 -0
  17. package/app/api/plugins/scan/route.ts +280 -0
  18. package/app/api/plugins/storage/route.ts +146 -0
  19. package/app/api/sessions/route.ts +165 -0
  20. package/app/api/settings/route.ts +40 -0
  21. package/app/api/suggest-fields/route.ts +129 -0
  22. package/app/api/templates/route.ts +159 -0
  23. package/app/api/test-api/route.ts +63 -0
  24. package/app/editor/page.tsx +1466 -0
  25. package/app/extensions/create/page.tsx +1422 -0
  26. package/app/extensions/edit/[id]/page.tsx +2342 -0
  27. package/app/extensions/page.tsx +1572 -0
  28. package/app/extensions/tutorial/page.tsx +4258 -0
  29. package/app/favicon.ico +0 -0
  30. package/app/fonts/GeistMonoVF.woff +0 -0
  31. package/app/fonts/GeistVF.woff +0 -0
  32. package/app/game/[id]/page.tsx +996 -0
  33. package/app/globals.css +3 -0
  34. package/app/layout.tsx +26 -0
  35. package/app/loading.tsx +26 -0
  36. package/app/page.tsx +345 -0
  37. package/app/settings/page.tsx +1490 -0
  38. package/bin/cli.js +262 -0
  39. package/components/ChatInput.tsx +106 -0
  40. package/components/ChatWindow.tsx +52 -0
  41. package/components/FullPageLoader.tsx +107 -0
  42. package/components/LoadingDots.tsx +20 -0
  43. package/components/MathCurveLoader.tsx +173 -0
  44. package/components/MessageBubble.tsx +147 -0
  45. package/components/WorldCardPreview.tsx +98 -0
  46. package/components/WorldCardUploader.tsx +58 -0
  47. package/components/ui/ConfirmDialog.tsx +135 -0
  48. package/components/ui/PageHeader.tsx +99 -0
  49. package/components/ui/PermissionConflictDialog.tsx +206 -0
  50. package/components/ui/PluginConfigForm.tsx +192 -0
  51. package/components/ui/PluginFloatingLayer.tsx +52 -0
  52. package/components/ui/PluginIcon.tsx +53 -0
  53. package/components/ui/PluginModalRenderer.tsx +185 -0
  54. package/components/ui/PluginProvider.tsx +1038 -0
  55. package/components/ui/PluginSlotRenderer.tsx +76 -0
  56. package/components/ui/ThemeCustomizer.tsx +174 -0
  57. package/components/ui/ThemeProvider.tsx +125 -0
  58. package/components/ui/ThemeSwitcher.tsx +140 -0
  59. package/components/ui/ToastProvider.tsx +141 -0
  60. package/lib/builtin-plugins.ts +11 -0
  61. package/lib/db-init.ts +35 -0
  62. package/lib/db.ts +244 -0
  63. package/lib/manifest-parser.ts +185 -0
  64. package/lib/parseWorldCard.ts +110 -0
  65. package/lib/plugin-dom-sandbox.ts +327 -0
  66. package/lib/plugin-events.ts +88 -0
  67. package/lib/plugin-files.ts +186 -0
  68. package/lib/plugin-html-sanitizer.ts +79 -0
  69. package/lib/plugin-resource-tracker.ts +175 -0
  70. package/lib/plugin-runtime.ts +2287 -0
  71. package/lib/plugin-security.ts +151 -0
  72. package/lib/plugin-types.ts +416 -0
  73. package/lib/prompt-builder.ts +55 -0
  74. package/lib/router-history.ts +119 -0
  75. package/lib/storage.ts +381 -0
  76. package/lib/themes.ts +129 -0
  77. package/lib/types.ts +117 -0
  78. package/lib/version.ts +55 -0
  79. package/next.config.mjs +43 -0
  80. package/package.json +56 -0
  81. package/plugins/xinyu.bag-system.xye +0 -0
  82. package/plugins/xinyu.cache-optimizer.xye +0 -0
  83. package/plugins/xinyu.dice-arbiter.xye +0 -0
  84. package/plugins/xinyu.game-auto-start-choices.xye +0 -0
  85. package/plugins/xinyu.markdown-render.xye +0 -0
  86. package/plugins/xinyu.slot-ui-beautify.xye +0 -0
  87. package/plugins/xinyu.world-info.xye +0 -0
  88. package/postcss.config.mjs +8 -0
  89. package/public/templates/atlantis.svg +63 -0
  90. package/public/templates/cyber-city.svg +68 -0
  91. package/public/templates/jianghu.svg +69 -0
  92. package/public/templates//351/255/224/346/263/225/344/270/226/347/225/214.svg +137 -0
  93. package/styles/themes.css +111 -0
  94. package/tailwind.config.ts +18 -0
  95. package/tsconfig.json +26 -0
  96. package/version.json +6 -0
@@ -0,0 +1,185 @@
1
+ // components/ui/PluginModalRenderer.tsx - 模态框渲染器组件
2
+ // 负责渲染插件创建的模态框和确认对话框
3
+ 'use client';
4
+
5
+ import React, { useState, useCallback } from 'react';
6
+ import { ModalRegistration } from '@/lib/plugin-types';
7
+ import { getPluginRuntime } from '@/lib/plugin-runtime';
8
+
9
+ interface PluginModalRendererProps {
10
+ modals: ModalRegistration[];
11
+ onClose: (modalId: string) => void;
12
+ }
13
+
14
+ export function PluginModalRenderer({ modals, onClose }: PluginModalRendererProps) {
15
+ if (!modals || modals.length === 0) return null;
16
+
17
+ return (
18
+ <>
19
+ {modals.map((modal) => (
20
+ <PluginModal
21
+ key={modal.id}
22
+ modal={modal}
23
+ onClose={() => onClose(modal.id)}
24
+ />
25
+ ))}
26
+ </>
27
+ );
28
+ }
29
+
30
+ function PluginModal({
31
+ modal,
32
+ onClose,
33
+ }: {
34
+ modal: ModalRegistration;
35
+ onClose: () => void;
36
+ }) {
37
+ const [visible, setVisible] = useState(true);
38
+
39
+ // 事件委托:处理模态框内容中 data-action 属性的点击事件
40
+ const handleContentClick = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
41
+ const target = e.target as HTMLElement;
42
+ const actionEl = target.closest<HTMLElement>('[data-action]');
43
+ if (!actionEl) return;
44
+
45
+ const actionName = actionEl.getAttribute('data-action');
46
+ const payload = actionEl.getAttribute('data-payload') || undefined;
47
+
48
+ if (actionName && modal.pluginId) {
49
+ e.preventDefault();
50
+ e.stopPropagation();
51
+ const runtime = getPluginRuntime();
52
+ runtime.dispatchAction(modal.pluginId, actionName, actionEl, payload);
53
+ }
54
+ }, [modal.pluginId]);
55
+
56
+ const handleClose = useCallback(() => {
57
+ setVisible(false);
58
+ // 等待动画完成后真正关闭
59
+ setTimeout(() => {
60
+ onClose();
61
+ }, 200);
62
+ }, [onClose]);
63
+
64
+ if (!visible) return null;
65
+
66
+ return (
67
+ <div
68
+ className="fixed inset-0 z-[60] flex items-center justify-center"
69
+ style={{
70
+ opacity: visible ? 1 : 0,
71
+ transition: 'opacity 0.2s ease',
72
+ }}
73
+ >
74
+ {/* 遮罩 */}
75
+ {modal.backdrop !== false && (
76
+ <div
77
+ className="absolute inset-0"
78
+ style={{ backgroundColor: 'rgba(0, 0, 0, 0.5)' }}
79
+ onClick={modal.closable !== false ? handleClose : undefined}
80
+ />
81
+ )}
82
+
83
+ {/* 模态框主体 */}
84
+ <div
85
+ id={`xinyu-modal-${modal.id}`}
86
+ data-plugin-slot="modal"
87
+ data-plugin-id={modal.pluginId}
88
+ className="relative rounded-xl shadow-2xl flex flex-col max-h-[80vh]"
89
+ style={{
90
+ backgroundColor: 'var(--color-bg-secondary)',
91
+ border: '1px solid var(--color-border)',
92
+ width: modal.width || '480px',
93
+ maxWidth: '90vw',
94
+ animation: 'pluginModalIn 0.2s ease',
95
+ ...modal.style,
96
+ }}
97
+ >
98
+ {/* 标题栏 */}
99
+ <div
100
+ className="flex items-center justify-between px-5 py-3.5 shrink-0"
101
+ style={{ borderBottom: '1px solid var(--color-border)' }}
102
+ >
103
+ <h3
104
+ className="text-sm font-bold"
105
+ style={{ color: 'var(--color-text-primary)' }}
106
+ >
107
+ {modal.title}
108
+ </h3>
109
+ {modal.closable !== false && (
110
+ <button
111
+ onClick={handleClose}
112
+ className="p-1 rounded-lg transition-colors"
113
+ style={{ color: 'var(--color-text-muted)' }}
114
+ >
115
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
116
+ <line x1="18" y1="6" x2="6" y2="18" />
117
+ <line x1="6" y1="6" x2="18" y2="18" />
118
+ </svg>
119
+ </button>
120
+ )}
121
+ </div>
122
+
123
+ {/* 内容区 */}
124
+ <div
125
+ className="flex-1 overflow-y-auto px-5 py-4"
126
+ style={{ color: 'var(--color-text-secondary)' }}
127
+ onClick={handleContentClick}
128
+ data-plugin-id={modal.pluginId}
129
+ >
130
+ <div dangerouslySetInnerHTML={{ __html: modal.content }} />
131
+ </div>
132
+
133
+ {/* 底部按钮 */}
134
+ {modal.actions && modal.actions.length > 0 && (
135
+ <div
136
+ className="flex items-center justify-end gap-2 px-5 py-3.5 shrink-0"
137
+ style={{ borderTop: '1px solid var(--color-border)' }}
138
+ >
139
+ {modal.actions.map((action, idx) => (
140
+ <button
141
+ key={idx}
142
+ onClick={() => {
143
+ try {
144
+ action.onClick();
145
+ } catch (e) {
146
+ console.error('[PluginModal] 按钮点击出错:', e);
147
+ }
148
+ }}
149
+ className="px-4 py-2 rounded-lg text-xs font-medium transition-colors"
150
+ style={{
151
+ backgroundColor: action.primary
152
+ ? 'var(--color-accent)'
153
+ : action.danger
154
+ ? 'rgba(220, 38, 38, 0.9)'
155
+ : 'transparent',
156
+ color: action.primary || action.danger
157
+ ? '#fff'
158
+ : 'var(--color-text-secondary)',
159
+ border: action.primary || action.danger
160
+ ? 'none'
161
+ : '1px solid var(--color-border)',
162
+ }}
163
+ >
164
+ {action.text}
165
+ </button>
166
+ ))}
167
+ </div>
168
+ )}
169
+ </div>
170
+
171
+ <style jsx>{`
172
+ @keyframes pluginModalIn {
173
+ from {
174
+ opacity: 0;
175
+ transform: scale(0.95) translateY(10px);
176
+ }
177
+ to {
178
+ opacity: 1;
179
+ transform: scale(1) translateY(0);
180
+ }
181
+ }
182
+ `}</style>
183
+ </div>
184
+ );
185
+ }