Skip to content

Commit b5d8609

Browse files
committed
fix: merge conflict 수정
2 parents ed36433 + 8724127 commit b5d8609

3 files changed

Lines changed: 175 additions & 4 deletions

File tree

app/cms/admin.py

Lines changed: 151 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,156 @@
11
from cms.admin_mixins import RelatedReadonlyFieldsMixin
22
from cms.models import Page, Section, Sitemap
3+
from django import forms
34
from django.contrib import admin
5+
from django.utils.html import format_html
46

7+
_CODE_PREVIEW_TEMPLATE = """
8+
<style>
9+
/* ── 래퍼 기본 ── */
10+
.code-preview-wrapper {{
11+
display: flex;
12+
flex-direction: column;
13+
width: 800px;
14+
gap: 8px;
15+
background: #fff;
16+
}}
17+
.code-preview-wrapper > textarea {{ display: none !important; }}
518
19+
/* ── 툴바 ── */
20+
.cp-toolbar {{
21+
display: flex;
22+
align-items: center;
23+
gap: 6px;
24+
padding: 4px;
25+
background: #333;
26+
border-bottom: 1px solid #444;
27+
position: relative;
28+
z-index: 2001; /* admin nav 위 */
29+
}}
30+
.cp-toolbar button {{
31+
padding: 4px 8px;
32+
font-size: 13px;
33+
border: 1px solid #555;
34+
background: #444;
35+
color: #fff;
36+
cursor: pointer;
37+
}}
38+
.cp-toolbar .preview-toggle {{ display: inline-block; }}
39+
.cp-toolbar .lang-toggle,
40+
.cp-toolbar .theme-toggle {{ display: none !important; }}
41+
.code-preview-wrapper.fullscreen .cp-toolbar .lang-toggle,
42+
.code-preview-wrapper.fullscreen .cp-toolbar .theme-toggle {{
43+
display: inline-block !important;
44+
}}
45+
.lang-toggle.js-mode.active {{ background: #f1c40f; border-color: #d4ac0d; color: #333; }}
46+
.lang-toggle.ts-mode.active {{ background: #3498db; border-color: #2e86c1; color: #fff; }}
47+
.theme-toggle.active {{ background: #888; border-color: #666; color: #fff; }}
48+
49+
/* ── 에디터·프리뷰 컨테이너 ── */
50+
.cp-main {{
51+
display: flex;
52+
flex-direction: column;
53+
gap: 8px;
54+
min-height: 0;
55+
}}
56+
.code-preview-wrapper:not(.fullscreen) .cp-main {{
57+
display: none !important;
58+
}}
59+
60+
/* 에디터 블록 */
61+
.editor-block {{
62+
flex: 1;
63+
min-height: 0;
64+
position: relative;
65+
}}
66+
.editor-block .CodeMirror,
67+
.editor-block .CodeMirror-scroll {{
68+
height: 100% !important;
69+
overflow: auto !important;
70+
}}
71+
72+
/* 프리뷰 iframe */
73+
.cp-main iframe {{
74+
flex: 1;
75+
min-height: 0;
76+
overflow: auto;
77+
}}
78+
79+
/* ── 풀스크린 모드 ── */
80+
.code-preview-wrapper.fullscreen {{
81+
position: fixed !important;
82+
top: 0 !important; left: 0 !important; right: 0 !important; bottom: 0 !important;
83+
width: 100vw !important;
84+
height: 100vh !important;
85+
margin: 0; padding: 0;
86+
display: flex;
87+
flex-direction: column;
88+
background: #fff;
89+
z-index: 2000;
90+
}}
91+
.code-preview-wrapper.fullscreen .cp-main {{
92+
flex: 1;
93+
display: flex;
94+
flex-direction: row;
95+
min-height: 0;
96+
}}
97+
.code-preview-wrapper.fullscreen .editor-block {{
98+
max-height: none !important;
99+
}}
100+
.code-preview-wrapper.fullscreen .cp-toolbar {{
101+
flex-shrink: 0;
102+
}}
103+
104+
/* ── 다크모드 ── */
105+
.dark-editor .CodeMirror {{ background: #2d2d2d !important; color: #ccc; }}
106+
.dark-preview iframe {{ background: #2d2d2d; }}
107+
</style>
108+
109+
<div class="code-preview-wrapper" id="cpw_{name}">
110+
<div class="cp-toolbar">
111+
<button type="button" class="preview-toggle">Preview Mode</button>
112+
<button type="button" class="lang-toggle js-mode active" data-lang="js">JS</button>
113+
<button type="button" class="lang-toggle ts-mode" data-lang="ts">TS</button>
114+
<button type="button" class="theme-toggle" data-target="editor">Editor Dark</button>
115+
<button type="button" class="theme-toggle" data-target="preview">Preview Dark</button>
116+
</div>
117+
{ta}
118+
<div class="cp-main">
119+
<div class="editor-block" id="editor_{name}"></div>
120+
<iframe id="preview_{name}"></iframe>
121+
</div>
122+
</div>
123+
"""
124+
125+
126+
class CodeEditorWidget(forms.Textarea):
127+
class Media:
128+
css = {
129+
"all": (
130+
"https://unpkg.com/codemirror@5.65.5/lib/codemirror.css",
131+
"https://unpkg.com/codemirror@5.65.5/theme/dracula.css",
132+
)
133+
}
134+
js = (
135+
"https://unpkg.com/codemirror@5.65.5/lib/codemirror.js",
136+
"https://unpkg.com/codemirror@5.65.5/mode/javascript/javascript.js",
137+
"https://unpkg.com/@babel/standalone/babel.min.js",
138+
"/static/admin/js/editor.js",
139+
)
140+
141+
def render(self, name, value, attrs=None, renderer=None):
142+
ta = super().render(name, value, attrs, renderer)
143+
return format_html(_CODE_PREVIEW_TEMPLATE, name=name, ta=ta)
144+
145+
146+
class SectionAdminForm(forms.ModelForm):
147+
class Meta:
148+
model = Section
149+
fields = "__all__"
150+
widgets = {"body": CodeEditorWidget()}
151+
152+
153+
@admin.register(Sitemap)
6154
class SitemapAdmin(RelatedReadonlyFieldsMixin, admin.ModelAdmin):
7155
fields = ["id", "parent_sitemap", "page", "name", "order", "display_start_at", "display_end_at"]
8156
readonly_fields = ["id"]
@@ -43,7 +191,9 @@ class PageAdmin(admin.ModelAdmin):
43191
pass
44192

45193

194+
@admin.register(Section)
46195
class SectionAdmin(RelatedReadonlyFieldsMixin, admin.ModelAdmin):
196+
form = SectionAdminForm
47197
fields = ["id", "page", "order", "css", "body"]
48198
readonly_fields = ["id"]
49199
related_readonly_config = {"page": ["id", "is_active", "css", "title", "subtitle"]}
@@ -66,6 +216,4 @@ def get_queryset(self, request):
66216
return super().get_queryset(request).select_related("page")
67217

68218

69-
admin.site.register(Sitemap, SitemapAdmin)
70-
admin.site.register(Page, PageAdmin)
71-
admin.site.register(Section, SectionAdmin)
219+
admin.site.register(Page)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Generated by Django 5.2 on 2025-05-07 11:52
2+
3+
import django.core.validators
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
dependencies = [
9+
("cms", "0002_historicalpage_historicalsection_historicalsitemap"),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name="historicalsitemap",
15+
name="order",
16+
field=models.IntegerField(default=0, validators=[django.core.validators.MinValueValidator(0)]),
17+
),
18+
migrations.AlterField(
19+
model_name="sitemap",
20+
name="order",
21+
field=models.IntegerField(default=0, validators=[django.core.validators.MinValueValidator(0)]),
22+
),
23+
]

app/cms/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class Sitemap(models.Model):
2222
"self", null=True, blank=True, default=None, on_delete=models.SET_NULL, related_name="children"
2323
)
2424
name = models.CharField(max_length=256)
25-
order = models.IntegerField(default=0, validators=MinValueValidator(0))
25+
order = models.IntegerField(default=0, validators=[MinValueValidator(0)])
2626
page = models.ForeignKey(Page, on_delete=models.PROTECT)
2727
display_start_at = models.DateTimeField(null=True, blank=True)
2828
display_end_at = models.DateTimeField(null=True, blank=True)

0 commit comments

Comments
 (0)