supaslidev 0.1.4 → 0.2.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.
- package/app/app.config.ts +9 -0
- package/app/assets/css/main.css +90 -0
- package/app/components/AppHeader.vue +429 -0
- package/app/components/CreatePresentationDialog.vue +236 -0
- package/app/components/EmptyState.vue +37 -0
- package/app/components/ImportPresentationDialog.vue +865 -0
- package/app/components/PresentationCard.vue +343 -0
- package/app/components/PresentationListItem.vue +242 -0
- package/app/composables/useServers.ts +148 -0
- package/app/layouts/default.vue +49 -0
- package/app/pages/index.vue +542 -0
- package/dist/cli/index.js +183751 -137
- package/dist/config.d.ts +8 -0
- package/dist/config.js +16 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +3 -0
- package/dist/module.d.ts +6 -0
- package/dist/module.js +9168 -0
- package/dist/prompt.js +847 -0
- package/nuxt.config.ts +53 -0
- package/package.json +26 -19
- package/server/api/export/[id].post.ts +67 -0
- package/server/api/open-editor/[id].post.ts +28 -0
- package/server/api/presentations/import.post.ts +139 -0
- package/server/api/presentations/index.get.ts +18 -0
- package/server/api/presentations/index.post.ts +175 -0
- package/server/api/presentations/upload.post.ts +174 -0
- package/server/api/presentations/validate.post.ts +14 -0
- package/server/api/servers/[id].delete.ts +15 -0
- package/server/api/servers/[id].post.ts +17 -0
- package/server/api/servers/index.delete.ts +5 -0
- package/server/api/servers/index.get.ts +5 -0
- package/server/api/servers/stop-all.post.ts +5 -0
- package/server/plugins/generate.ts +12 -0
- package/server/plugins/shutdown.ts +16 -0
- package/server/routes/exports/[...path].get.ts +25 -0
- package/server/utils/config.ts +13 -0
- package/server/utils/process-manager.ts +119 -0
- package/src/cli/commands/create.ts +125 -0
- package/src/cli/commands/deploy.ts +90 -0
- package/src/cli/commands/dev.ts +116 -0
- package/src/cli/commands/export.ts +63 -0
- package/src/cli/commands/import.ts +178 -0
- package/src/cli/commands/present.ts +111 -0
- package/src/cli/index.ts +87 -0
- package/src/cli/utils.ts +94 -0
- package/src/config.ts +21 -0
- package/src/index.ts +2 -0
- package/src/module.ts +12 -0
- package/src/shared/catalog.ts +94 -0
- package/src/shared/copy.ts +28 -0
- package/src/shared/index.ts +29 -0
- package/{scripts/generate-presentations.mjs → src/shared/presentations.ts} +23 -46
- package/src/shared/types.ts +29 -0
- package/src/shared/validation.ts +111 -0
- package/dist/assets/index-BerY9FcI.js +0 -49
- package/dist/assets/index-CVzsY-on.css +0 -1
- package/dist/index.html +0 -24
- package/server/api.js +0 -1225
- /package/{dist → public}/apple-touch-icon.png +0 -0
- /package/{dist → public}/favicon-96x96.png +0 -0
- /package/{dist → public}/favicon.ico +0 -0
- /package/{dist → public}/favicon.svg +0 -0
- /package/{dist → public}/site.webmanifest +0 -0
- /package/{dist → public}/ssl-logo.png +0 -0
- /package/{dist → public}/web-app-manifest-192x192.png +0 -0
- /package/{dist → public}/web-app-manifest-512x512.png +0 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { ref, readonly } from 'vue';
|
|
2
|
+
import type { Presentation } from '../../src/shared/types';
|
|
3
|
+
|
|
4
|
+
interface ServerInfo {
|
|
5
|
+
port: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const servers = ref<Record<string, ServerInfo>>({});
|
|
9
|
+
|
|
10
|
+
async function fetchStatus() {
|
|
11
|
+
try {
|
|
12
|
+
const response = await fetch('/api/servers');
|
|
13
|
+
if (response.ok) {
|
|
14
|
+
servers.value = await response.json();
|
|
15
|
+
}
|
|
16
|
+
} catch {
|
|
17
|
+
// API server not running
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function startServer(presentationId: string): Promise<{ success: boolean; port?: number }> {
|
|
22
|
+
try {
|
|
23
|
+
const response = await fetch(`/api/servers/${presentationId}`, { method: 'POST' });
|
|
24
|
+
const result = await response.json();
|
|
25
|
+
if (result.success) {
|
|
26
|
+
servers.value = { ...servers.value, [presentationId]: { port: result.port } };
|
|
27
|
+
return { success: true, port: result.port };
|
|
28
|
+
}
|
|
29
|
+
return { success: false };
|
|
30
|
+
} catch {
|
|
31
|
+
return { success: false };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function stopServer(presentationId: string): Promise<boolean> {
|
|
36
|
+
try {
|
|
37
|
+
const response = await fetch(`/api/servers/${presentationId}`, { method: 'DELETE' });
|
|
38
|
+
const result = await response.json();
|
|
39
|
+
if (result.success) {
|
|
40
|
+
const newServers = { ...servers.value };
|
|
41
|
+
delete newServers[presentationId];
|
|
42
|
+
servers.value = newServers;
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function stopAllServers(): Promise<boolean> {
|
|
52
|
+
try {
|
|
53
|
+
const response = await fetch('/api/servers', { method: 'DELETE' });
|
|
54
|
+
const result = await response.json();
|
|
55
|
+
if (result.success) {
|
|
56
|
+
servers.value = {};
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
} catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isRunning(presentationId: string): boolean {
|
|
66
|
+
return presentationId in servers.value;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function exportPresentation(
|
|
70
|
+
presentationId: string,
|
|
71
|
+
): Promise<{ success: boolean; pdfPath?: string; error?: string }> {
|
|
72
|
+
try {
|
|
73
|
+
const response = await fetch(`/api/export/${presentationId}`, { method: 'POST' });
|
|
74
|
+
const result = await response.json();
|
|
75
|
+
return result;
|
|
76
|
+
} catch {
|
|
77
|
+
return { success: false, error: 'Failed to connect to export service' };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function openInEditor(presentationId: string): Promise<{ success: boolean; error?: string }> {
|
|
82
|
+
try {
|
|
83
|
+
const response = await fetch(`/api/open-editor/${presentationId}`, { method: 'POST' });
|
|
84
|
+
return await response.json();
|
|
85
|
+
} catch {
|
|
86
|
+
return { success: false, error: 'Failed to open editor' };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function getPort(presentationId: string): number | undefined {
|
|
91
|
+
return servers.value[presentationId]?.port;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function waitForServerReady(
|
|
95
|
+
port: number,
|
|
96
|
+
options: { timeout?: number; interval?: number } = {},
|
|
97
|
+
): Promise<boolean> {
|
|
98
|
+
const { timeout = 30000, interval = 300 } = options;
|
|
99
|
+
const startTime = Date.now();
|
|
100
|
+
const url = `http://localhost:${port}`;
|
|
101
|
+
|
|
102
|
+
while (Date.now() - startTime < timeout) {
|
|
103
|
+
try {
|
|
104
|
+
const response = await fetch(url, { method: 'HEAD', mode: 'no-cors' });
|
|
105
|
+
if (response.ok || response.type === 'opaque') {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
109
|
+
// Server not ready yet
|
|
110
|
+
}
|
|
111
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let pollingInterval: ReturnType<typeof setInterval> | null = null;
|
|
117
|
+
|
|
118
|
+
function startPolling() {
|
|
119
|
+
if (pollingInterval) return;
|
|
120
|
+
fetchStatus();
|
|
121
|
+
pollingInterval = setInterval(fetchStatus, 2000);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function stopPolling() {
|
|
125
|
+
if (pollingInterval) {
|
|
126
|
+
clearInterval(pollingInterval);
|
|
127
|
+
pollingInterval = null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function useServers() {
|
|
132
|
+
return {
|
|
133
|
+
servers: readonly(servers),
|
|
134
|
+
fetchStatus,
|
|
135
|
+
startServer,
|
|
136
|
+
stopServer,
|
|
137
|
+
stopAllServers,
|
|
138
|
+
isRunning,
|
|
139
|
+
getPort,
|
|
140
|
+
startPolling,
|
|
141
|
+
stopPolling,
|
|
142
|
+
exportPresentation,
|
|
143
|
+
openInEditor,
|
|
144
|
+
waitForServerReady,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export type { Presentation };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<UApp>
|
|
3
|
+
<div class="min-h-screen bg-default flex flex-col">
|
|
4
|
+
<UContainer class="py-6 sm:py-8 lg:py-10 flex-1">
|
|
5
|
+
<slot />
|
|
6
|
+
</UContainer>
|
|
7
|
+
|
|
8
|
+
<footer class="footer">
|
|
9
|
+
<p class="footer-text">
|
|
10
|
+
Built on
|
|
11
|
+
<a href="https://sli.dev" target="_blank" rel="noopener" class="footer-link">Sli.dev</a>
|
|
12
|
+
by
|
|
13
|
+
<a href="https://github.com/antfu" target="_blank" rel="noopener" class="footer-link"
|
|
14
|
+
>Anthony Fu</a
|
|
15
|
+
>, Created with ❤️ by
|
|
16
|
+
<a href="https://github.com/timdamen" target="_blank" rel="noopener" class="footer-link"
|
|
17
|
+
>Tim Damen</a
|
|
18
|
+
>
|
|
19
|
+
in 🇳🇱
|
|
20
|
+
</p>
|
|
21
|
+
</footer>
|
|
22
|
+
</div>
|
|
23
|
+
</UApp>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<style scoped>
|
|
27
|
+
.footer {
|
|
28
|
+
margin-top: auto;
|
|
29
|
+
padding: 2rem 0;
|
|
30
|
+
text-align: center;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.footer-text {
|
|
34
|
+
font-size: 0.75rem;
|
|
35
|
+
color: var(--ui-text-muted);
|
|
36
|
+
font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.footer-link {
|
|
40
|
+
color: var(--ui-primary);
|
|
41
|
+
text-decoration: none;
|
|
42
|
+
transition: opacity 0.2s ease;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.footer-link:hover {
|
|
46
|
+
opacity: 0.8;
|
|
47
|
+
text-decoration: underline;
|
|
48
|
+
}
|
|
49
|
+
</style>
|