create-fuzionx 0.1.48 β 0.1.49
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/package.json +1 -1
- package/templates/common/locales/en.json +7 -1
- package/templates/common/locales/ko.json +7 -1
- package/templates/common/package.json.tpl +2 -2
- package/templates/spa/meta.json +1 -1
- package/templates/spa/views/default/spa/src/components/FileUpload.vue +27 -11
- package/templates/spa/views/default/spa/src/composables/useApi.js +2 -2
- package/templates/spa/views/default/spa/src/views/BoardForm.vue +3 -3
- package/templates/ssr/routes/web.js +6 -4
- package/templates/ssr/views/default/pages/board/form.html +35 -9
package/package.json
CHANGED
|
@@ -21,7 +21,13 @@
|
|
|
21
21
|
"processing": "Processing",
|
|
22
22
|
"store_success": "Post saved successfully.",
|
|
23
23
|
"title": "Board",
|
|
24
|
-
"update_success": "Post updated successfully."
|
|
24
|
+
"update_success": "Post updated successfully.",
|
|
25
|
+
"upload_speed": "Speed",
|
|
26
|
+
"upload_complete": "Upload complete!",
|
|
27
|
+
"upload_error": "Upload error",
|
|
28
|
+
"upload_network_error": "Network error",
|
|
29
|
+
"uploading": "Uploading...",
|
|
30
|
+
"thumbnail_extracting": "π Extracting thumbnails..."
|
|
25
31
|
},
|
|
26
32
|
"btn": {
|
|
27
33
|
"back": "β Back",
|
|
@@ -21,7 +21,13 @@
|
|
|
21
21
|
"processing": "μ²λ¦¬μ€",
|
|
22
22
|
"store_success": "κ²μκΈμ΄ μ±κ³΅μ μΌλ‘ μ μ₯λμμ΅λλ€.",
|
|
23
23
|
"title": "κ²μν",
|
|
24
|
-
"update_success": "κ²μκΈμ΄ μ±κ³΅μ μΌλ‘ μμ λμμ΅λλ€."
|
|
24
|
+
"update_success": "κ²μκΈμ΄ μ±κ³΅μ μΌλ‘ μμ λμμ΅λλ€.",
|
|
25
|
+
"upload_speed": "μλ",
|
|
26
|
+
"upload_complete": "μ
λ‘λ μλ£!",
|
|
27
|
+
"upload_error": "μ€λ₯ λ°μ",
|
|
28
|
+
"upload_network_error": "λ€νΈμν¬ μ€λ₯",
|
|
29
|
+
"uploading": "μ
λ‘λ μ€...",
|
|
30
|
+
"thumbnail_extracting": "π μΈλ€μΌ μΆμΆμ€..."
|
|
25
31
|
},
|
|
26
32
|
"btn": {
|
|
27
33
|
"back": "β λͺ©λ‘",
|
package/templates/spa/meta.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"description": "Vue.js 3 SPA + Tera SSR νμ΄λΈλ¦¬λ. WASM μνΈν ν΅μ .",
|
|
5
5
|
"features": ["auth", "board", "i18n", "asp", "wasm"],
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@fuzionx/client": "^0.1.
|
|
7
|
+
"@fuzionx/client": "^0.1.49"
|
|
8
8
|
},
|
|
9
9
|
"devDependencies": {},
|
|
10
10
|
"spaDevDependencies": {
|
|
@@ -54,7 +54,8 @@
|
|
|
54
54
|
</div>
|
|
55
55
|
<div class="progress-info" style="display: flex; justify-content: space-between; margin-top: 6px; font-size: 0.85rem; color: #aaa;">
|
|
56
56
|
<span>{{ progressText }}</span>
|
|
57
|
-
<span>{{
|
|
57
|
+
<span>{{ sizeText }}</span>
|
|
58
|
+
<span>{{ speedLabel }}</span>
|
|
58
59
|
</div>
|
|
59
60
|
</div>
|
|
60
61
|
</div>
|
|
@@ -62,6 +63,9 @@
|
|
|
62
63
|
|
|
63
64
|
<script setup>
|
|
64
65
|
import { ref, computed } from 'vue';
|
|
66
|
+
import { useLocale } from '../composables/useLocale.js';
|
|
67
|
+
|
|
68
|
+
const { t } = useLocale();
|
|
65
69
|
|
|
66
70
|
/**
|
|
67
71
|
* @prop {string} label - λ μ΄λΈ ν
μ€νΈ
|
|
@@ -83,14 +87,16 @@ const selectedFiles = ref([]);
|
|
|
83
87
|
const uploading = ref(false);
|
|
84
88
|
const progress = ref(0);
|
|
85
89
|
const progressText = ref('0%');
|
|
86
|
-
const
|
|
90
|
+
const sizeText = ref('');
|
|
91
|
+
const speedLabel = ref('');
|
|
87
92
|
const progressColor = ref('linear-gradient(90deg, #667eea, #764ba2)');
|
|
88
93
|
|
|
89
94
|
/** νμΌ ν¬κΈ° ν¬λ§· */
|
|
90
95
|
function formatSize(bytes) {
|
|
91
96
|
if (bytes < 1024) return bytes + ' B';
|
|
92
97
|
if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
|
|
93
|
-
return (bytes / 1048576).toFixed(1) + ' MB';
|
|
98
|
+
if (bytes < 1073741824) return (bytes / 1048576).toFixed(1) + ' MB';
|
|
99
|
+
return (bytes / 1073741824).toFixed(2) + ' GB';
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
/** νμΌ μ ν μ΄λ²€νΈ */
|
|
@@ -122,23 +128,32 @@ function setFiles(fileList) {
|
|
|
122
128
|
}
|
|
123
129
|
|
|
124
130
|
/** μ§νλ₯ μ
λ°μ΄νΈ (μΈλΆμμ νΈμΆ) */
|
|
125
|
-
function setProgress(pct, speed) {
|
|
131
|
+
function setProgress(pct, speed, loaded, total) {
|
|
126
132
|
uploading.value = true;
|
|
127
133
|
progress.value = pct;
|
|
128
134
|
progressText.value = pct + '%';
|
|
129
|
-
|
|
135
|
+
|
|
136
|
+
// νμΌ ν¬κΈ° νμ
|
|
137
|
+
if (loaded !== undefined && total !== undefined) {
|
|
138
|
+
sizeText.value = formatSize(loaded) + ' / ' + formatSize(total);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// μλ λ μ΄λΈ
|
|
142
|
+
if (speed) {
|
|
143
|
+
speedLabel.value = t('board.upload_speed', 'μλ') + ': ' + speed;
|
|
144
|
+
}
|
|
130
145
|
}
|
|
131
146
|
|
|
132
147
|
/** μ
λ‘λ μλ£ */
|
|
133
|
-
function setComplete(text
|
|
148
|
+
function setComplete(text) {
|
|
134
149
|
progress.value = 100;
|
|
135
|
-
progressText.value = text;
|
|
136
|
-
|
|
150
|
+
progressText.value = text || t('board.upload_complete', 'μ
λ‘λ μλ£!');
|
|
151
|
+
speedLabel.value = '';
|
|
137
152
|
}
|
|
138
153
|
|
|
139
154
|
/** μ
λ‘λ μ€λ₯ */
|
|
140
|
-
function setError(text
|
|
141
|
-
progressText.value = text;
|
|
155
|
+
function setError(text) {
|
|
156
|
+
progressText.value = text || t('board.upload_error', 'μ€λ₯ λ°μ');
|
|
142
157
|
progressColor.value = '#e74c3c';
|
|
143
158
|
}
|
|
144
159
|
|
|
@@ -153,7 +168,8 @@ function reset() {
|
|
|
153
168
|
uploading.value = false;
|
|
154
169
|
progress.value = 0;
|
|
155
170
|
progressText.value = '0%';
|
|
156
|
-
|
|
171
|
+
sizeText.value = '';
|
|
172
|
+
speedLabel.value = '';
|
|
157
173
|
progressColor.value = 'linear-gradient(90deg, #667eea, #764ba2)';
|
|
158
174
|
}
|
|
159
175
|
|
|
@@ -80,7 +80,7 @@ export function useApi() {
|
|
|
80
80
|
* XHR μ
λ‘λ β μ§νλ₯ μ½λ°± μ§μ.
|
|
81
81
|
* @param {string} url - μ
λ‘λ URL
|
|
82
82
|
* @param {FormData} formData - νΌ λ°μ΄ν°
|
|
83
|
-
* @param {Function} onProgress - μ§νλ₯ μ½λ°± (percent, speed)
|
|
83
|
+
* @param {Function} onProgress - μ§νλ₯ μ½λ°± (percent, speed, loaded, total)
|
|
84
84
|
* @param {string} [method='POST'] - HTTP λ©μλ
|
|
85
85
|
* @returns {Promise<{ok: boolean, responseURL: string}>}
|
|
86
86
|
*/
|
|
@@ -100,7 +100,7 @@ export function useApi() {
|
|
|
100
100
|
? (bps / 1048576).toFixed(1) + ' MB/s'
|
|
101
101
|
: (bps / 1024).toFixed(0) + ' KB/s';
|
|
102
102
|
}
|
|
103
|
-
onProgress(pct, speed);
|
|
103
|
+
onProgress(pct, speed, ev.loaded, ev.total);
|
|
104
104
|
};
|
|
105
105
|
|
|
106
106
|
xhr.onload = () => {
|
|
@@ -162,10 +162,10 @@ async function handleSubmit() {
|
|
|
162
162
|
try {
|
|
163
163
|
if (hasFiles) {
|
|
164
164
|
// XHR μ
λ‘λ + μ§νλ₯
|
|
165
|
-
const result = await api.uploadWithProgress(uploadUrl, formData, (pct, speed) => {
|
|
166
|
-
fileUploader.value?.setProgress(pct, speed);
|
|
165
|
+
const result = await api.uploadWithProgress(uploadUrl, formData, (pct, speed, loaded, total) => {
|
|
166
|
+
fileUploader.value?.setProgress(pct, speed, loaded, total);
|
|
167
167
|
}, method);
|
|
168
|
-
fileUploader.value?.setComplete(
|
|
168
|
+
fileUploader.value?.setComplete();
|
|
169
169
|
toast.success(isEdit.value ? t('board.updated', 'κΈμ΄ μμ λμμ΅λλ€.') : t('board.created', 'κΈμ΄ μμ±λμμ΅λλ€.'));
|
|
170
170
|
setTimeout(() => {
|
|
171
171
|
router.push(isEdit.value ? `/board/${route.params.id}` : '/board');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { auth } from '@fuzionx/framework';
|
|
1
|
+
import { auth, loadUser } from '@fuzionx/framework';
|
|
2
2
|
import HomeController from '../controllers/HomeController.js';
|
|
3
3
|
import FeaturesController from '../controllers/FeaturesController.js';
|
|
4
4
|
import ChatController from '../controllers/ChatController.js';
|
|
@@ -7,9 +7,11 @@ import UserController from '../controllers/UserController.js';
|
|
|
7
7
|
import PostController from '../controllers/PostController.js';
|
|
8
8
|
|
|
9
9
|
export default (r) => {
|
|
10
|
-
// ββ κ³΅κ° νμ΄μ§ (μΈμ¦
|
|
11
|
-
r.
|
|
12
|
-
|
|
10
|
+
// ββ κ³΅κ° νμ΄μ§ (μΈμ¦ λΆνμ, μΈμ
μ μ λ‘λ) ββ
|
|
11
|
+
r.group('', { middleware: [loadUser()] }, (r) => {
|
|
12
|
+
r.get('/', HomeController.index);
|
|
13
|
+
r.get('/features', FeaturesController.index);
|
|
14
|
+
});
|
|
13
15
|
|
|
14
16
|
// ββ μΈμ¦ ββ
|
|
15
17
|
r.get('/login', AuthController.loginPage);
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
</div>
|
|
82
82
|
<div class="progress-info" style="display:flex;justify-content:space-between;margin-top:6px;font-size:0.85rem;color:#aaa">
|
|
83
83
|
<span id="progressText">0%</span>
|
|
84
|
+
<span id="progressSize"></span>
|
|
84
85
|
<span id="progressSpeed"></span>
|
|
85
86
|
</div>
|
|
86
87
|
</div>
|
|
@@ -128,7 +129,8 @@ function editorInsert(text) {
|
|
|
128
129
|
function formatSize(bytes) {
|
|
129
130
|
if (bytes < 1024) return bytes + ' B';
|
|
130
131
|
if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
|
|
131
|
-
return (bytes / 1048576).toFixed(1) + ' MB';
|
|
132
|
+
if (bytes < 1073741824) return (bytes / 1048576).toFixed(1) + ' MB';
|
|
133
|
+
return (bytes / 1073741824).toFixed(2) + ' GB';
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
function renderFiles() {
|
|
@@ -168,7 +170,25 @@ function editorInsert(text) {
|
|
|
168
170
|
});
|
|
169
171
|
})();
|
|
170
172
|
|
|
171
|
-
/**
|
|
173
|
+
/** i18n ν
μ€νΈ */
|
|
174
|
+
var _uploadLabels = {
|
|
175
|
+
speed: '{{ t(key="board.upload_speed", default="μλ") }}',
|
|
176
|
+
complete: '{{ t(key="board.upload_complete", default="μ
λ‘λ μλ£!") }}',
|
|
177
|
+
error: '{{ t(key="board.upload_error", default="μ€λ₯ λ°μ") }}',
|
|
178
|
+
networkError: '{{ t(key="board.upload_network_error", default="λ€νΈμν¬ μ€λ₯") }}',
|
|
179
|
+
uploading: '{{ t(key="board.uploading", default="μ
λ‘λ μ€...") }}',
|
|
180
|
+
thumbnailExtracting: '{{ t(key="board.thumbnail_extracting", default="π μΈλ€μΌ μΆμΆμ€...") }}'
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/** νμΌ ν¬κΈ° ν¬λ§· (μ§νλ₯ μ©) */
|
|
184
|
+
function _fmtSize(bytes) {
|
|
185
|
+
if (bytes < 1024) return bytes + ' B';
|
|
186
|
+
if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
|
|
187
|
+
if (bytes < 1073741824) return (bytes / 1048576).toFixed(1) + ' MB';
|
|
188
|
+
return (bytes / 1073741824).toFixed(2) + ' GB';
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** XHR μ
λ‘λ β μ§νλ₯ + νμΌ ν¬κΈ° + μλ + μλ 리λ€μ΄λ νΈ */
|
|
172
192
|
function handleUpload(e) {
|
|
173
193
|
var fileInput = document.getElementById('fileInput');
|
|
174
194
|
if (!fileInput || !fileInput.files || fileInput.files.length === 0) {
|
|
@@ -181,10 +201,11 @@ function handleUpload(e) {
|
|
|
181
201
|
var progress = document.getElementById('uploadProgress');
|
|
182
202
|
var fill = document.getElementById('progressFill');
|
|
183
203
|
var pText = document.getElementById('progressText');
|
|
204
|
+
var pSize = document.getElementById('progressSize');
|
|
184
205
|
var pSpeed = document.getElementById('progressSpeed');
|
|
185
206
|
|
|
186
207
|
btn.disabled = true;
|
|
187
|
-
btn.textContent =
|
|
208
|
+
btn.textContent = _uploadLabels.uploading;
|
|
188
209
|
progress.style.display = 'block';
|
|
189
210
|
|
|
190
211
|
var formData = new FormData(form);
|
|
@@ -197,30 +218,35 @@ function handleUpload(e) {
|
|
|
197
218
|
fill.style.width = pct + '%';
|
|
198
219
|
pText.textContent = pct + '%';
|
|
199
220
|
|
|
221
|
+
// νμΌ ν¬κΈ° νμ (loaded / total)
|
|
222
|
+
pSize.textContent = _fmtSize(ev.loaded) + ' / ' + _fmtSize(ev.total);
|
|
223
|
+
|
|
200
224
|
var elapsed = (Date.now() - startTime) / 1000;
|
|
201
225
|
if (elapsed > 0.5) {
|
|
202
226
|
var bps = ev.loaded / elapsed;
|
|
227
|
+
var speedVal;
|
|
203
228
|
if (bps > 1048576) {
|
|
204
|
-
|
|
229
|
+
speedVal = (bps / 1048576).toFixed(1) + ' MB/s';
|
|
205
230
|
} else {
|
|
206
|
-
|
|
231
|
+
speedVal = (bps / 1024).toFixed(0) + ' KB/s';
|
|
207
232
|
}
|
|
233
|
+
pSpeed.textContent = _uploadLabels.speed + ': ' + speedVal;
|
|
208
234
|
}
|
|
209
235
|
};
|
|
210
236
|
|
|
211
237
|
xhr.onload = function() {
|
|
212
238
|
if (xhr.status >= 200 && xhr.status < 400) {
|
|
213
239
|
fill.style.width = '100%';
|
|
214
|
-
pText.textContent =
|
|
240
|
+
pText.textContent = _uploadLabels.complete;
|
|
215
241
|
pSpeed.textContent = '';
|
|
216
|
-
btn.textContent =
|
|
242
|
+
btn.textContent = _uploadLabels.thumbnailExtracting;
|
|
217
243
|
setTimeout(function() {
|
|
218
244
|
window.location.href = xhr.responseURL || '/board';
|
|
219
245
|
}, 1500);
|
|
220
246
|
} else {
|
|
221
247
|
btn.disabled = false;
|
|
222
248
|
btn.textContent = 'μ¬μλ';
|
|
223
|
-
pText.textContent =
|
|
249
|
+
pText.textContent = _uploadLabels.error;
|
|
224
250
|
fill.style.background = '#e74c3c';
|
|
225
251
|
}
|
|
226
252
|
};
|
|
@@ -228,7 +254,7 @@ function handleUpload(e) {
|
|
|
228
254
|
xhr.onerror = function() {
|
|
229
255
|
btn.disabled = false;
|
|
230
256
|
btn.textContent = 'μ¬μλ';
|
|
231
|
-
pText.textContent =
|
|
257
|
+
pText.textContent = _uploadLabels.networkError;
|
|
232
258
|
fill.style.background = '#e74c3c';
|
|
233
259
|
};
|
|
234
260
|
|