focomy 0.1.118__py3-none-any.whl → 0.1.120__py3-none-any.whl
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.
- core/admin/routes.py +7 -0
- core/engine/routes.py +2 -0
- core/templates/admin/base.html +3 -0
- {focomy-0.1.118.dist-info → focomy-0.1.120.dist-info}/METADATA +1 -1
- {focomy-0.1.118.dist-info → focomy-0.1.120.dist-info}/RECORD +9 -9
- themes/default/templates/base.html +396 -0
- {focomy-0.1.118.dist-info → focomy-0.1.120.dist-info}/WHEEL +0 -0
- {focomy-0.1.118.dist-info → focomy-0.1.120.dist-info}/entry_points.txt +0 -0
- {focomy-0.1.118.dist-info → focomy-0.1.120.dist-info}/licenses/LICENSE +0 -0
core/admin/routes.py
CHANGED
|
@@ -198,6 +198,12 @@ async def get_context(
|
|
|
198
198
|
except Exception:
|
|
199
199
|
pass # Post content type may not exist
|
|
200
200
|
|
|
201
|
+
# Get active theme for customize link
|
|
202
|
+
from ..services.settings import SettingsService
|
|
203
|
+
settings_svc = SettingsService(db)
|
|
204
|
+
theme_settings = await settings_svc.get_by_category("theme")
|
|
205
|
+
active_theme = theme_settings.get("active", "default")
|
|
206
|
+
|
|
201
207
|
return {
|
|
202
208
|
"request": request,
|
|
203
209
|
"content_types": content_types,
|
|
@@ -208,6 +214,7 @@ async def get_context(
|
|
|
208
214
|
"user_role": user_role,
|
|
209
215
|
"channels": channels,
|
|
210
216
|
"orphan_post_count": orphan_post_count,
|
|
217
|
+
"active_theme": active_theme,
|
|
211
218
|
}
|
|
212
219
|
|
|
213
220
|
|
core/engine/routes.py
CHANGED
|
@@ -160,6 +160,8 @@ async def render_theme(
|
|
|
160
160
|
if admin_info:
|
|
161
161
|
context["is_admin"] = True
|
|
162
162
|
context["admin_user"] = admin_info["user_data"]
|
|
163
|
+
context["active_theme"] = active_theme # For customize link
|
|
164
|
+
context["csrf_token"] = getattr(request.state, "csrf_token", "") # For API calls
|
|
163
165
|
# Build edit URL if entity provided
|
|
164
166
|
if entity and content_type:
|
|
165
167
|
context["edit_url"] = f"/admin/{content_type}/{entity.id}/edit"
|
core/templates/admin/base.html
CHANGED
|
@@ -551,6 +551,9 @@
|
|
|
551
551
|
</a>
|
|
552
552
|
|
|
553
553
|
<div class="nav-section">外観</div>
|
|
554
|
+
<a href="/admin/themes/{{ active_theme }}/customize" class="nav-item {% if current_page == 'customize' %}active{% endif %}">
|
|
555
|
+
カスタマイズ
|
|
556
|
+
</a>
|
|
554
557
|
<a href="/admin/themes" class="nav-item {% if current_page == 'themes' %}active{% endif %}">
|
|
555
558
|
テーマ
|
|
556
559
|
</a>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: focomy
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.120
|
|
4
4
|
Summary: The Most Beautiful CMS - A metadata-driven, zero-duplicate-code content management system
|
|
5
5
|
Project-URL: Homepage, https://github.com/focomy/focomy
|
|
6
6
|
Project-URL: Documentation, https://focomy.dev/docs
|
|
@@ -7,7 +7,7 @@ core/rate_limit.py,sha256=CX5UjmsU03aFWKXSKjweoHvH2xn0v4NBHNN5ynJC8LE,180
|
|
|
7
7
|
core/relations.yaml,sha256=7GUCrphKaouEXNkyd8Ht99e6TcUPERhc4m36RGcc41U,2128
|
|
8
8
|
core/utils.py,sha256=Rqs1WStB0JjTb8-750jL-xJ_kaPH3ddupvqt46BXIBc,2754
|
|
9
9
|
core/admin/__init__.py,sha256=IXrr-z-IDXmYodaZ-cVDou6wr_vsVhyWmXHdSNKkQsk,94
|
|
10
|
-
core/admin/routes.py,sha256=
|
|
10
|
+
core/admin/routes.py,sha256=6l24uI8gNiwBTa6YzOstMYik8DzBZaBcqsuCPzST4oU,150908
|
|
11
11
|
core/admin/url.py,sha256=FlusKnSz3bZgPSBmRu-dI3W-bQo7lKBDZ3zN8cFHwQc,2243
|
|
12
12
|
core/api/__init__.py,sha256=H1StbYGDVRS6g-Jk3UUf17ibAz1K8IUa27NfPMkaNrA,19
|
|
13
13
|
core/api/auth.py,sha256=Zb37IHcUSjf8_hXiVzhoZPQw6WAiOOS_AoMqE96yat8,11565
|
|
@@ -44,7 +44,7 @@ core/content_types/user.yaml,sha256=y3SwqzIc9_6C7R1GULk7AwYJPxcTT38ZmZe4_wekfyU,
|
|
|
44
44
|
core/content_types/widget.yaml,sha256=Jotbts5QQtHaF2bJWQL3rkEoCkp_aq_A3gN-58eJwv8,1454
|
|
45
45
|
core/content_types/workflow_history.yaml,sha256=3wi58LNLYbk7t6Z2QDRi9whQSedJCXKVKuyBhixNUK0,518
|
|
46
46
|
core/engine/__init__.py,sha256=ycR0Kdn6buwdCH6QFG8bV69wFciFSKEg9Ro26cHpa2U,83
|
|
47
|
-
core/engine/routes.py,sha256=
|
|
47
|
+
core/engine/routes.py,sha256=O4Olf0yzLzhsMydB9eFbZhGirGlsV2s4lkRSQDcWsA0,44016
|
|
48
48
|
core/migrations/env.py,sha256=1dLI8qcGojLDR_--MdgwP5q-V0p2Z-32klSPjokXx4M,1389
|
|
49
49
|
core/migrations/script.py.mako,sha256=LyYLSC7HzBBGwHZ8s2SguBPMXsWCph0FJp49kPsGhU8,590
|
|
50
50
|
core/migrations/versions/2038bdf6693b_add_import_jobs_table.py,sha256=v8lPC5WmwpUfHUG_YgQn6jepPtfKWFn0JIj9XvD9224,2325
|
|
@@ -150,7 +150,7 @@ core/services/wordpress_import/rollback.py,sha256=NomM71QsBI3nt1Y_Hpod2nw-E9kpXQ
|
|
|
150
150
|
core/services/wordpress_import/verification.py,sha256=efaTdah8oc63MsqJv-OWuse81ukxuLxl1xSwMYybJNY,19701
|
|
151
151
|
core/services/wordpress_import/wxr_parser.py,sha256=GrfiMoSj75hp3beHx9aLe-lxXtoWmq5eP_Jzx8UajKE,15982
|
|
152
152
|
core/templates/admin/backup.html,sha256=Di93BRvmyxdvF-eOAMKTYFB7qubH1Fms7ppYbJ3YHiA,3165
|
|
153
|
-
core/templates/admin/base.html,sha256=
|
|
153
|
+
core/templates/admin/base.html,sha256=jsOz2mG2HzDhTriZ3Pi6Z3MjsxGnoGvMqDzlSJz737Q,24127
|
|
154
154
|
core/templates/admin/comments.html,sha256=AEzCMYu1-EdFC1yUa9oIObtRS-U9RlMTe_5P3O5alb8,10012
|
|
155
155
|
core/templates/admin/customize.html,sha256=UohKyxBDmKhtbOiipyRkFJlrD_5u0JIc8b7--U5EuUk,18631
|
|
156
156
|
core/templates/admin/dashboard.html,sha256=WzURfANu1k9AIjdP82fwJE1o3sRhNVr77iUCRfUoBm8,3439
|
|
@@ -189,7 +189,7 @@ themes/default/theme.yaml,sha256=tgcUP1YFptyXVNL2a8DBiPrP7zTjWNH62Cy9D_w6Chk,187
|
|
|
189
189
|
themes/default/templates/404.html,sha256=6pYUz7zg5hx3nikgxiZWSkwYnv2nENCSV3KjdIF0_lE,1105
|
|
190
190
|
themes/default/templates/500.html,sha256=CtU3gEsHsxAh-vbcnx5McH8V8ruKtdP8usj8hPuu8zY,1174
|
|
191
191
|
themes/default/templates/archive.html,sha256=ZHBxPYewvc2TbrsB745LYO2uM5SJbTFQQR6savWUzYg,2385
|
|
192
|
-
themes/default/templates/base.html,sha256=
|
|
192
|
+
themes/default/templates/base.html,sha256=Vl0HbbOcCd6SRGoi5j7_xJopsaqZ7Kr9dI7ygS0vx14,26867
|
|
193
193
|
themes/default/templates/category.html,sha256=k-yN0vFoOpgxgg6DlGin5X4IzVDBG9xRZ0FOD7OJtU8,3061
|
|
194
194
|
themes/default/templates/channel.html,sha256=1i1zkAWmvpcqyoEfaeQNDc2zrMao2xSXCkjRuwzxOUU,3213
|
|
195
195
|
themes/default/templates/form.html,sha256=KFrFS6qxHELPrpRB0B_BNU-uqM3k11oMYwd6oY3qoPQ,8685
|
|
@@ -204,8 +204,8 @@ themes/minimal/templates/base.html,sha256=LFkx-XLDMGH7oFHHa0e6KPB0DJITOBvr6GtPkD
|
|
|
204
204
|
themes/minimal/templates/home.html,sha256=ygYQgYj1OGCiKwmfsxwkPselVKT8vDH3jLLbfphpqKI,1577
|
|
205
205
|
themes/minimal/templates/page.html,sha256=7Xcoq-ryaxlp913H2S1ishrAro2wsqqGmvsm1osXxd4,389
|
|
206
206
|
themes/minimal/templates/post.html,sha256=FkTRHci8HNIIi3DU6Mb3oL0aDisGyDcsT_IUDwHmrvo,1387
|
|
207
|
-
focomy-0.1.
|
|
208
|
-
focomy-0.1.
|
|
209
|
-
focomy-0.1.
|
|
210
|
-
focomy-0.1.
|
|
211
|
-
focomy-0.1.
|
|
207
|
+
focomy-0.1.120.dist-info/METADATA,sha256=7UzC55msNplib9gEMyoHDcrY9cR_WFPPfOqbCKpd6G8,7042
|
|
208
|
+
focomy-0.1.120.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
209
|
+
focomy-0.1.120.dist-info/entry_points.txt,sha256=_rF-wxGI1axY7gox3DBsTLHq-JrFKkMCjA65a6b_oqE,41
|
|
210
|
+
focomy-0.1.120.dist-info/licenses/LICENSE,sha256=z9Z7gN7NNV7zYCaY-Knh3bv8RBCu89VueYtAlN_-lro,1063
|
|
211
|
+
focomy-0.1.120.dist-info/RECORD,,
|
|
@@ -146,6 +146,7 @@
|
|
|
146
146
|
{% endif %}
|
|
147
147
|
</div>
|
|
148
148
|
</div>
|
|
149
|
+
<button type="button" id="customize-toggle" class="admin-bar-btn">カスタマイズ</button>
|
|
149
150
|
{% if edit_url %}
|
|
150
151
|
<a href="{{ edit_url }}">編集</a>
|
|
151
152
|
{% endif %}
|
|
@@ -223,8 +224,403 @@
|
|
|
223
224
|
.admin-bar-dropdown:hover .admin-bar-dropdown-menu {
|
|
224
225
|
display: block;
|
|
225
226
|
}
|
|
227
|
+
.admin-bar-btn {
|
|
228
|
+
background: transparent;
|
|
229
|
+
border: none;
|
|
230
|
+
color: white;
|
|
231
|
+
cursor: pointer;
|
|
232
|
+
font-size: inherit;
|
|
233
|
+
padding: 0;
|
|
234
|
+
}
|
|
235
|
+
.admin-bar-btn:hover {
|
|
236
|
+
text-decoration: underline;
|
|
237
|
+
}
|
|
226
238
|
body { padding-top: 32px; }
|
|
239
|
+
|
|
240
|
+
/* Customize Panel */
|
|
241
|
+
#customize-panel {
|
|
242
|
+
display: none;
|
|
243
|
+
position: fixed;
|
|
244
|
+
top: 32px;
|
|
245
|
+
left: 0;
|
|
246
|
+
width: 320px;
|
|
247
|
+
height: calc(100vh - 32px);
|
|
248
|
+
background: #1e293b;
|
|
249
|
+
color: white;
|
|
250
|
+
z-index: 9998;
|
|
251
|
+
box-shadow: 2px 0 10px rgba(0,0,0,0.3);
|
|
252
|
+
overflow-y: auto;
|
|
253
|
+
}
|
|
254
|
+
#customize-panel.open {
|
|
255
|
+
display: block;
|
|
256
|
+
}
|
|
257
|
+
#customize-panel-header {
|
|
258
|
+
display: flex;
|
|
259
|
+
justify-content: space-between;
|
|
260
|
+
align-items: center;
|
|
261
|
+
padding: 1rem;
|
|
262
|
+
border-bottom: 1px solid #374151;
|
|
263
|
+
}
|
|
264
|
+
#customize-panel-header h2 {
|
|
265
|
+
margin: 0;
|
|
266
|
+
font-size: 1rem;
|
|
267
|
+
font-weight: 600;
|
|
268
|
+
}
|
|
269
|
+
#customize-panel-close {
|
|
270
|
+
background: transparent;
|
|
271
|
+
border: none;
|
|
272
|
+
color: #94a3b8;
|
|
273
|
+
cursor: pointer;
|
|
274
|
+
font-size: 1.25rem;
|
|
275
|
+
padding: 0;
|
|
276
|
+
}
|
|
277
|
+
#customize-panel-close:hover {
|
|
278
|
+
color: white;
|
|
279
|
+
}
|
|
280
|
+
.customize-section {
|
|
281
|
+
padding: 1rem;
|
|
282
|
+
border-bottom: 1px solid #374151;
|
|
283
|
+
}
|
|
284
|
+
.customize-section h3 {
|
|
285
|
+
font-size: 0.75rem;
|
|
286
|
+
font-weight: 600;
|
|
287
|
+
text-transform: uppercase;
|
|
288
|
+
color: #94a3b8;
|
|
289
|
+
margin: 0 0 0.75rem 0;
|
|
290
|
+
}
|
|
291
|
+
.customize-field {
|
|
292
|
+
margin-bottom: 0.75rem;
|
|
293
|
+
}
|
|
294
|
+
.customize-field label {
|
|
295
|
+
display: block;
|
|
296
|
+
font-size: 0.8125rem;
|
|
297
|
+
margin-bottom: 0.25rem;
|
|
298
|
+
}
|
|
299
|
+
.customize-field input[type="color"] {
|
|
300
|
+
width: 40px;
|
|
301
|
+
height: 28px;
|
|
302
|
+
padding: 0;
|
|
303
|
+
border: 1px solid #374151;
|
|
304
|
+
border-radius: 4px;
|
|
305
|
+
cursor: pointer;
|
|
306
|
+
}
|
|
307
|
+
.customize-field input[type="text"] {
|
|
308
|
+
width: 100%;
|
|
309
|
+
padding: 0.5rem;
|
|
310
|
+
background: #0f172a;
|
|
311
|
+
border: 1px solid #374151;
|
|
312
|
+
border-radius: 4px;
|
|
313
|
+
color: white;
|
|
314
|
+
font-size: 0.8125rem;
|
|
315
|
+
}
|
|
316
|
+
.customize-field textarea {
|
|
317
|
+
width: 100%;
|
|
318
|
+
min-height: 120px;
|
|
319
|
+
padding: 0.5rem;
|
|
320
|
+
background: #0f172a;
|
|
321
|
+
border: 1px solid #374151;
|
|
322
|
+
border-radius: 4px;
|
|
323
|
+
color: #d4d4d4;
|
|
324
|
+
font-family: monospace;
|
|
325
|
+
font-size: 0.75rem;
|
|
326
|
+
resize: vertical;
|
|
327
|
+
}
|
|
328
|
+
.color-row {
|
|
329
|
+
display: flex;
|
|
330
|
+
align-items: center;
|
|
331
|
+
gap: 0.5rem;
|
|
332
|
+
}
|
|
333
|
+
.color-row input[type="text"] {
|
|
334
|
+
flex: 1;
|
|
335
|
+
font-family: monospace;
|
|
336
|
+
}
|
|
337
|
+
#customize-panel-footer {
|
|
338
|
+
padding: 1rem;
|
|
339
|
+
display: flex;
|
|
340
|
+
gap: 0.5rem;
|
|
341
|
+
justify-content: flex-end;
|
|
342
|
+
}
|
|
343
|
+
#customize-panel-footer button {
|
|
344
|
+
padding: 0.5rem 1rem;
|
|
345
|
+
border-radius: 4px;
|
|
346
|
+
font-size: 0.8125rem;
|
|
347
|
+
cursor: pointer;
|
|
348
|
+
}
|
|
349
|
+
#customize-reset {
|
|
350
|
+
background: transparent;
|
|
351
|
+
border: 1px solid #374151;
|
|
352
|
+
color: #94a3b8;
|
|
353
|
+
}
|
|
354
|
+
#customize-reset:hover {
|
|
355
|
+
background: #374151;
|
|
356
|
+
color: white;
|
|
357
|
+
}
|
|
358
|
+
#customize-save {
|
|
359
|
+
background: #2563eb;
|
|
360
|
+
border: none;
|
|
361
|
+
color: white;
|
|
362
|
+
}
|
|
363
|
+
#customize-save:hover {
|
|
364
|
+
background: #1d4ed8;
|
|
365
|
+
}
|
|
366
|
+
#customize-save:disabled {
|
|
367
|
+
background: #374151;
|
|
368
|
+
cursor: not-allowed;
|
|
369
|
+
}
|
|
370
|
+
.customize-message {
|
|
371
|
+
padding: 0.5rem 1rem;
|
|
372
|
+
margin: 0 1rem;
|
|
373
|
+
border-radius: 4px;
|
|
374
|
+
font-size: 0.8125rem;
|
|
375
|
+
}
|
|
376
|
+
.customize-message.success {
|
|
377
|
+
background: #22c55e20;
|
|
378
|
+
color: #22c55e;
|
|
379
|
+
}
|
|
380
|
+
.customize-message.error {
|
|
381
|
+
background: #ef444420;
|
|
382
|
+
color: #ef4444;
|
|
383
|
+
}
|
|
227
384
|
</style>
|
|
385
|
+
|
|
386
|
+
<!-- Customize Panel -->
|
|
387
|
+
<div id="customize-panel">
|
|
388
|
+
<div id="customize-panel-header">
|
|
389
|
+
<h2>カスタマイズ</h2>
|
|
390
|
+
<button type="button" id="customize-panel-close">×</button>
|
|
391
|
+
</div>
|
|
392
|
+
<div id="customize-panel-content">
|
|
393
|
+
<div class="customize-section">
|
|
394
|
+
<h3>カラー</h3>
|
|
395
|
+
<div class="customize-field">
|
|
396
|
+
<label>メインカラー</label>
|
|
397
|
+
<div class="color-row">
|
|
398
|
+
<input type="color" id="color_primary" value="#2563eb">
|
|
399
|
+
<input type="text" id="color_primary_text" value="#2563eb" pattern="^#[0-9A-Fa-f]{6}$">
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
<div class="customize-field">
|
|
403
|
+
<label>背景色</label>
|
|
404
|
+
<div class="color-row">
|
|
405
|
+
<input type="color" id="color_background" value="#ffffff">
|
|
406
|
+
<input type="text" id="color_background_text" value="#ffffff" pattern="^#[0-9A-Fa-f]{6}$">
|
|
407
|
+
</div>
|
|
408
|
+
</div>
|
|
409
|
+
<div class="customize-field">
|
|
410
|
+
<label>文字色</label>
|
|
411
|
+
<div class="color-row">
|
|
412
|
+
<input type="color" id="color_text" value="#1e293b">
|
|
413
|
+
<input type="text" id="color_text_text" value="#1e293b" pattern="^#[0-9A-Fa-f]{6}$">
|
|
414
|
+
</div>
|
|
415
|
+
</div>
|
|
416
|
+
</div>
|
|
417
|
+
<div class="customize-section">
|
|
418
|
+
<h3>カスタムCSS</h3>
|
|
419
|
+
<div class="customize-field">
|
|
420
|
+
<textarea id="custom_css" placeholder="/* CSSを入力 */"></textarea>
|
|
421
|
+
</div>
|
|
422
|
+
</div>
|
|
423
|
+
</div>
|
|
424
|
+
<div id="customize-panel-footer">
|
|
425
|
+
<button type="button" id="customize-reset">リセット</button>
|
|
426
|
+
<button type="button" id="customize-save">保存</button>
|
|
427
|
+
</div>
|
|
428
|
+
</div>
|
|
429
|
+
|
|
430
|
+
<script>
|
|
431
|
+
(function() {
|
|
432
|
+
const panel = document.getElementById('customize-panel');
|
|
433
|
+
const toggleBtn = document.getElementById('customize-toggle');
|
|
434
|
+
const closeBtn = document.getElementById('customize-panel-close');
|
|
435
|
+
const saveBtn = document.getElementById('customize-save');
|
|
436
|
+
const resetBtn = document.getElementById('customize-reset');
|
|
437
|
+
const csrfToken = '{{ csrf_token }}';
|
|
438
|
+
const themeName = '{{ active_theme }}';
|
|
439
|
+
|
|
440
|
+
let originalValues = {};
|
|
441
|
+
let currentValues = {};
|
|
442
|
+
|
|
443
|
+
// Toggle panel
|
|
444
|
+
toggleBtn.addEventListener('click', function() {
|
|
445
|
+
panel.classList.toggle('open');
|
|
446
|
+
if (panel.classList.contains('open')) {
|
|
447
|
+
loadSettings();
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
closeBtn.addEventListener('click', function() {
|
|
452
|
+
panel.classList.remove('open');
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
// Color input sync
|
|
456
|
+
document.querySelectorAll('#customize-panel input[type="color"]').forEach(colorInput => {
|
|
457
|
+
const textInput = document.getElementById(colorInput.id + '_text');
|
|
458
|
+
if (textInput) {
|
|
459
|
+
colorInput.addEventListener('input', () => {
|
|
460
|
+
textInput.value = colorInput.value;
|
|
461
|
+
updatePreview();
|
|
462
|
+
});
|
|
463
|
+
textInput.addEventListener('input', () => {
|
|
464
|
+
if (/^#[0-9A-Fa-f]{6}$/.test(textInput.value)) {
|
|
465
|
+
colorInput.value = textInput.value;
|
|
466
|
+
updatePreview();
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
// Custom CSS change
|
|
473
|
+
document.getElementById('custom_css').addEventListener('input', debounce(updatePreview, 300));
|
|
474
|
+
|
|
475
|
+
// Load settings from API
|
|
476
|
+
async function loadSettings() {
|
|
477
|
+
try {
|
|
478
|
+
const response = await fetch('/admin/api/theme/settings?theme_name=' + themeName, {
|
|
479
|
+
credentials: 'include'
|
|
480
|
+
});
|
|
481
|
+
if (!response.ok) throw new Error('Failed to load settings');
|
|
482
|
+
const data = await response.json();
|
|
483
|
+
|
|
484
|
+
// Populate form
|
|
485
|
+
data.settings.forEach(setting => {
|
|
486
|
+
if (setting.id.startsWith('color_')) {
|
|
487
|
+
const colorInput = document.getElementById(setting.id);
|
|
488
|
+
const textInput = document.getElementById(setting.id + '_text');
|
|
489
|
+
if (colorInput && textInput) {
|
|
490
|
+
colorInput.value = setting.value || setting.default;
|
|
491
|
+
textInput.value = setting.value || setting.default;
|
|
492
|
+
}
|
|
493
|
+
} else if (setting.id === 'custom_css') {
|
|
494
|
+
document.getElementById('custom_css').value = setting.value || '';
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
originalValues = getFormValues();
|
|
499
|
+
currentValues = {...originalValues};
|
|
500
|
+
} catch (error) {
|
|
501
|
+
console.error('Load settings error:', error);
|
|
502
|
+
showMessage('設定の読み込みに失敗しました', 'error');
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// Get current form values
|
|
507
|
+
function getFormValues() {
|
|
508
|
+
return {
|
|
509
|
+
color_primary: document.getElementById('color_primary').value,
|
|
510
|
+
color_background: document.getElementById('color_background').value,
|
|
511
|
+
color_text: document.getElementById('color_text').value,
|
|
512
|
+
custom_css: document.getElementById('custom_css').value,
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Update preview
|
|
517
|
+
async function updatePreview() {
|
|
518
|
+
currentValues = getFormValues();
|
|
519
|
+
try {
|
|
520
|
+
const response = await fetch('/admin/api/theme/preview-css', {
|
|
521
|
+
method: 'POST',
|
|
522
|
+
headers: {
|
|
523
|
+
'Content-Type': 'application/json',
|
|
524
|
+
'X-CSRF-Token': csrfToken
|
|
525
|
+
},
|
|
526
|
+
credentials: 'include',
|
|
527
|
+
body: JSON.stringify({
|
|
528
|
+
theme_name: themeName,
|
|
529
|
+
values: currentValues
|
|
530
|
+
})
|
|
531
|
+
});
|
|
532
|
+
if (!response.ok) throw new Error('Preview failed');
|
|
533
|
+
const css = await response.text();
|
|
534
|
+
applyPreviewCSS(css);
|
|
535
|
+
} catch (error) {
|
|
536
|
+
console.error('Preview error:', error);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Apply preview CSS
|
|
541
|
+
function applyPreviewCSS(css) {
|
|
542
|
+
let styleEl = document.getElementById('customize-preview-style');
|
|
543
|
+
if (!styleEl) {
|
|
544
|
+
styleEl = document.createElement('style');
|
|
545
|
+
styleEl.id = 'customize-preview-style';
|
|
546
|
+
document.head.appendChild(styleEl);
|
|
547
|
+
}
|
|
548
|
+
styleEl.textContent = css;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// Save settings
|
|
552
|
+
saveBtn.addEventListener('click', async function() {
|
|
553
|
+
saveBtn.disabled = true;
|
|
554
|
+
saveBtn.textContent = '保存中...';
|
|
555
|
+
|
|
556
|
+
try {
|
|
557
|
+
const response = await fetch('/admin/api/theme/settings', {
|
|
558
|
+
method: 'POST',
|
|
559
|
+
headers: {
|
|
560
|
+
'Content-Type': 'application/json',
|
|
561
|
+
'X-CSRF-Token': csrfToken
|
|
562
|
+
},
|
|
563
|
+
credentials: 'include',
|
|
564
|
+
body: JSON.stringify({
|
|
565
|
+
theme_name: themeName,
|
|
566
|
+
values: currentValues
|
|
567
|
+
})
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
const result = await response.json();
|
|
571
|
+
if (result.success) {
|
|
572
|
+
originalValues = {...currentValues};
|
|
573
|
+
showMessage('保存しました', 'success');
|
|
574
|
+
} else {
|
|
575
|
+
throw new Error(result.detail || 'Save failed');
|
|
576
|
+
}
|
|
577
|
+
} catch (error) {
|
|
578
|
+
console.error('Save error:', error);
|
|
579
|
+
showMessage('保存に失敗しました', 'error');
|
|
580
|
+
} finally {
|
|
581
|
+
saveBtn.disabled = false;
|
|
582
|
+
saveBtn.textContent = '保存';
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
// Reset
|
|
587
|
+
resetBtn.addEventListener('click', function() {
|
|
588
|
+
if (!confirm('変更をリセットしますか?')) return;
|
|
589
|
+
|
|
590
|
+
document.getElementById('color_primary').value = originalValues.color_primary || '#2563eb';
|
|
591
|
+
document.getElementById('color_primary_text').value = originalValues.color_primary || '#2563eb';
|
|
592
|
+
document.getElementById('color_background').value = originalValues.color_background || '#ffffff';
|
|
593
|
+
document.getElementById('color_background_text').value = originalValues.color_background || '#ffffff';
|
|
594
|
+
document.getElementById('color_text').value = originalValues.color_text || '#1e293b';
|
|
595
|
+
document.getElementById('color_text_text').value = originalValues.color_text || '#1e293b';
|
|
596
|
+
document.getElementById('custom_css').value = originalValues.custom_css || '';
|
|
597
|
+
|
|
598
|
+
updatePreview();
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
// Show message
|
|
602
|
+
function showMessage(text, type) {
|
|
603
|
+
const existing = document.querySelector('.customize-message');
|
|
604
|
+
if (existing) existing.remove();
|
|
605
|
+
|
|
606
|
+
const msg = document.createElement('div');
|
|
607
|
+
msg.className = 'customize-message ' + type;
|
|
608
|
+
msg.textContent = text;
|
|
609
|
+
document.getElementById('customize-panel-content').prepend(msg);
|
|
610
|
+
|
|
611
|
+
setTimeout(() => msg.remove(), 3000);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Debounce helper
|
|
615
|
+
function debounce(fn, delay) {
|
|
616
|
+
let timer;
|
|
617
|
+
return function(...args) {
|
|
618
|
+
clearTimeout(timer);
|
|
619
|
+
timer = setTimeout(() => fn.apply(this, args), delay);
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
})();
|
|
623
|
+
</script>
|
|
228
624
|
{% endif %}
|
|
229
625
|
<header class="site-header">
|
|
230
626
|
{% block header %}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|