diff --git a/dashboard/backend/src/routes/www/sections.ts b/dashboard/backend/src/routes/www/sections.ts index b3aadbc..fb708cc 100644 --- a/dashboard/backend/src/routes/www/sections.ts +++ b/dashboard/backend/src/routes/www/sections.ts @@ -1,5 +1,5 @@ import { Router, type Request, type Response } from 'express'; -import { eq, and } from 'drizzle-orm'; +import { eq, and, max } from 'drizzle-orm'; import { db } from '../../config/database.js'; import { wwwSectionBlocks, wwwSpecGroups, wwwSpecItems } from '../../schemas/index.js'; import logger from '../../config/logger.js'; @@ -77,6 +77,15 @@ router.post('/api/www/sections', async (req: Request, res: Response) => { return; } + // 未指定排序时,自动追加到同 page_type(及同产品)已有区块的最后,避免默认 0 导致乱序 + let sortOrder = Number(b.sort_order) || 0; + if (b.sort_order === undefined || b.sort_order === null) { + const scope = [eq(wwwSectionBlocks.pageType, b.page_type)]; + if (b.product_id) scope.push(eq(wwwSectionBlocks.productId, b.product_id)); + const [agg] = await db.select({ max: max(wwwSectionBlocks.sortOrder) }).from(wwwSectionBlocks).where(and(...scope)); + sortOrder = (agg?.max ?? -1) + 1; + } + const result = await db.insert(wwwSectionBlocks).values({ pageType: b.page_type, productId: b.product_id || null, @@ -108,7 +117,7 @@ router.post('/api/www/sections', async (req: Request, res: Response) => { videoUrl: b.video_url || '', config: b.config || null, isVisible: b.is_visible !== undefined ? (b.is_visible ? 1 : 0) : 1, - sortOrder: b.sort_order || 0, + sortOrder, }); const newId = result[0].insertId; diff --git a/dashboard/frontend/src/router/elegant/routes.ts b/dashboard/frontend/src/router/elegant/routes.ts index 965c50f..c85cf44 100644 --- a/dashboard/frontend/src/router/elegant/routes.ts +++ b/dashboard/frontend/src/router/elegant/routes.ts @@ -246,7 +246,7 @@ export const generatedRoutes: GeneratedRoute[] = [ meta: { title: 'www', i18nKey: 'route.www', - icon: 'mdi:globe-model', + icon: 'iconoir:www', order: 7 }, children: [ diff --git a/dashboard/frontend/src/service/api/www-sections.ts b/dashboard/frontend/src/service/api/www-sections.ts index df34ec6..eb32025 100644 --- a/dashboard/frontend/src/service/api/www-sections.ts +++ b/dashboard/frontend/src/service/api/www-sections.ts @@ -35,7 +35,7 @@ export function fetchDuplicateSection(id: number) { // ===== 参数分组 ===== export function fetchGetSpecGroups(sectionId: number) { - return request({ url: `/www/sections/${sectionId}/spec-groups`, method: 'get' }); + return request<{ items: Api.Www.SpecGroup[]; total: number }>({ url: `/www/sections/${sectionId}/spec-groups`, method: 'get' }); } export function fetchCreateSpecGroup(sectionId: number, data: { title_zh: string; title_en: string; default_visible?: number }) { @@ -56,7 +56,7 @@ export function fetchSortSpecGroups(sectionId: number, data: Array<{ id: number; // ===== 参数项 ===== export function fetchGetSpecItems(groupId: number) { - return request({ url: `/www/spec-groups/${groupId}/items`, method: 'get' }); + return request<{ items: Api.Www.SpecItem[]; total: number }>({ url: `/www/spec-groups/${groupId}/items`, method: 'get' }); } export function fetchCreateSpecItem(groupId: number, data: { name_zh: string; name_en: string; value_zh: string; value_en: string }) { diff --git a/dashboard/frontend/src/typings/api/www.d.ts b/dashboard/frontend/src/typings/api/www.d.ts index 0c4aa42..7123f4d 100644 --- a/dashboard/frontend/src/typings/api/www.d.ts +++ b/dashboard/frontend/src/typings/api/www.d.ts @@ -147,6 +147,8 @@ declare namespace Api { title_en: string; default_visible: number; sort_order: number; + /** GET spec-groups 列表接口内联返回的参数项 */ + items?: SpecItem[]; } interface SpecItem { diff --git a/dashboard/frontend/src/views/www/components/SectionManager.vue b/dashboard/frontend/src/views/www/components/SectionManager.vue index 6b05306..0ff7ed3 100644 --- a/dashboard/frontend/src/views/www/components/SectionManager.vue +++ b/dashboard/frontend/src/views/www/components/SectionManager.vue @@ -4,6 +4,7 @@ import { NButton, NSpace, NSwitch, NTag, type DataTableColumns, type FormInst, t import ColorInput from '../page/home/components/ColorInput.vue'; import MediaSelectInput from './MediaSelectInput.vue'; import RichTextEditor from './RichTextEditor.vue'; +import SpecManager from './SpecManager.vue'; import { fetchCreateSection, fetchDeleteSection, @@ -110,7 +111,7 @@ const formData = reactive({ media_url_en: '', video_url: '', is_visible: true, - config: { text_position: 'middle_left', width_percent: 100, container_width: '1200', border_radius: 0, padding_y: null, title_font_size: null, bg_fit: 'cover', media_position: 'left', mosaic_pattern: 'big_3', mosaic_items: emptyMosaicItems(4), min_height: null } as Record + config: { text_position: 'middle_left', width_percent: 100, container_width: '1200', border_radius: 0, padding_y: null, margin_y: null, title_font_size: null, bg_fit: 'cover', media_position: 'left', split_ratio: 50, mosaic_pattern: 'big_3', mosaic_items: emptyMosaicItems(4), min_height: null } as Record }); // 背景图/视频显示模式选项(bg_type 为图片/视频时生效) @@ -128,6 +129,20 @@ const containerWidthOptions = [ { label: '全宽', value: 'full' } ]; +// 图文分栏比例选项(值为素材栏宽占比);标签顺序随「媒体位置」联动: +// 素材在左 → 「素材 : 文案」,素材在右 → 「文案 : 素材」(与视觉左右顺序一致,底层存值不变) +const splitRatioOptions = computed(() => { + const mediaRight = formData.config.media_position === 'right'; + const label = (media: number) => (mediaRight ? `${100 - media} : ${media}` : `${media} : ${100 - media}`); + return [ + { label: `${label(30)}`, value: 30 }, + { label: `${label(40)}`, value: 40 }, + { label: `${label(50)}(默认)`, value: 50 }, + { label: `${label(60)}`, value: 60 }, + { label: `${label(70)}`, value: 70 } + ]; +}); + // ===== 马赛克拼贴(layout=mosaic):固定版式 + 槽位素材,存 config.mosaic_pattern / config.mosaic_items ===== interface MosaicItemForm { type: 'image' | 'video'; @@ -247,11 +262,15 @@ const columns = computed((): DataTableColumns => [ { title: '操作', key: 'actions', - width: 240, + width: 290, fixed: 'right', render(row) { return h('div', { class: 'flex-y-center gap-8px' }, [ h(NButton, { size: 'small', type: 'primary', onClick: () => handleEdit(row) }, { default: () => '编辑' }), + // spec_table 布局:管理参数分组与参数项 + row.layout === 'spec_table' + ? h(NButton, { size: 'small', type: 'info', onClick: () => handleSpecManage(row) }, { default: () => '参数' }) + : null, h(NButton, { size: 'small', onClick: () => handleCopy(row) }, { default: () => '复制' }), h(NButton, { size: 'small', type: 'error', onClick: () => handleDelete(row) }, { default: () => '删除' }) ]); @@ -315,7 +334,7 @@ function handleAdd() { formData.media_url_en = ''; formData.video_url = ''; formData.is_visible = true; - formData.config = { text_position: 'middle_left', width_percent: 100, container_width: '1200', border_radius: 0, padding_y: null, title_font_size: null, bg_fit: 'cover', media_position: 'left', mosaic_pattern: 'big_3', mosaic_items: emptyMosaicItems(4), min_height: null }; + formData.config = { text_position: 'middle_left', width_percent: 100, container_width: '1200', border_radius: 0, padding_y: null, margin_y: null, title_font_size: null, bg_fit: 'cover', media_position: 'left', split_ratio: 50, mosaic_pattern: 'big_3', mosaic_items: emptyMosaicItems(4), min_height: null }; dialogVisible.value = true; } @@ -356,9 +375,11 @@ function fillFormFromRow(row: Api.Www.SectionBlock) { container_width: ['1400', '1600', 'full'].includes(String(cfg.container_width)) ? String(cfg.container_width) : '1200', border_radius: typeof cfg.border_radius === 'number' && cfg.border_radius > 0 ? cfg.border_radius : 0, padding_y: typeof cfg.padding_y === 'number' && cfg.padding_y >= 0 ? cfg.padding_y : null, + margin_y: typeof cfg.margin_y === 'number' && cfg.margin_y >= 0 ? cfg.margin_y : null, title_font_size: typeof cfg.title_font_size === 'number' && cfg.title_font_size > 0 ? cfg.title_font_size : null, bg_fit: cfg.bg_fit === 'contain' || cfg.bg_fit === 'auto' ? cfg.bg_fit : 'cover', media_position: cfg.media_position === 'right' ? 'right' : 'left', + split_ratio: [30, 40, 50, 60, 70].includes(Number(cfg.split_ratio)) ? Number(cfg.split_ratio) : 50, min_height: typeof cfg.min_height === 'number' && cfg.min_height >= 0 ? cfg.min_height : null, mosaic_pattern: ['big_3', 'half_2', 'big_4', 'big_2'].includes(String(cfg.mosaic_pattern)) ? String(cfg.mosaic_pattern) : 'big_3' }; @@ -404,7 +425,14 @@ function handleDelete(row: Api.Www.SectionBlock) { }); } -async function handleSubmit() { +// 参数管理(spec_table 布局):唤起 SpecManager +const specManagerRef = ref | null>(null); + +function handleSpecManage(row: Api.Www.SectionBlock) { + specManagerRef.value?.open(row); +} + +async function handleSubmit(closeAfter = true) { submitLoading.value = true; const { id, ...payload } = formData; const reqData = { @@ -412,13 +440,15 @@ async function handleSubmit() { page_type: props.pageType, product_id: props.productId || null }; - const { error } = id + const { data, error } = id ? await fetchUpdateSection(id, reqData) : await fetchCreateSection(reqData); submitLoading.value = false; if (!error) { + // 「应用」新建后回填新 id,后续保存走更新接口,避免重复创建 + if (!id && data?.id) formData.id = data.id; window.$message?.success(id ? '更新成功' : '创建成功'); - dialogVisible.value = false; + if (closeAfter) dialogVisible.value = false; loadData(); } } @@ -447,6 +477,8 @@ onMounted(loadData); :title="dialogTitle" class="w-1000px" :mask-closable="false" + :segmented="{ content: true, footer: 'soft' }" + content-style="max-height: calc(85vh - 130px); overflow-y: auto;" > 基础配置 @@ -515,6 +547,23 @@ onMounted(loadData); 内容区与区块上下边缘的间距。留空 = 布局默认(多数 96px / 全幅横幅 120px / 主视觉分屏 64px);0 = 完全贴边 + +
+ + + + 区块与上下相邻区块之间的间隙,露出页面背景色;适合「区块宽度 < 100 + 圆角」的卡片式区块。留空/0 = 紧贴(默认) +
+
- 图片/视频在左 - 图片/视频在右 + 素材|文案 + 文案|素材 + +
+ + 按页面视觉左右顺序标注({{ formData.config.media_position === 'right' ? '文案 : 素材' : '素材 : 文案' }}),默认五五等分;移动端(小屏)始终单列堆叠不受影响 +
+
@@ -700,10 +759,14 @@ onMounted(loadData); + + +
diff --git a/dashboard/frontend/src/views/www/components/SpecManager.vue b/dashboard/frontend/src/views/www/components/SpecManager.vue new file mode 100644 index 0000000..b550363 --- /dev/null +++ b/dashboard/frontend/src/views/www/components/SpecManager.vue @@ -0,0 +1,306 @@ + + + diff --git a/db/migrations/x8_balanced_headphone_specs.sql b/db/migrations/x8_balanced_headphone_specs.sql new file mode 100644 index 0000000..551fe7d --- /dev/null +++ b/db/migrations/x8_balanced_headphone_specs.sql @@ -0,0 +1,9 @@ +-- 产品详情(product_id=1)参数区块「平衡耳机输出性能参数(4.4mm/XLR4输出)」参数项 +-- 区块:www_section_blocks.id=28(spec_table),分组已预建:gid=5 + +INSERT INTO www_spec_items (spec_group_id, name_zh, name_en, value_zh, value_en, sort_order) VALUES +(5, '高增益', 'High Gain', 'L+R≥4840mW+4840mW(16Ω, THD+N<1%)', 'L+R≥4840mW+4840mW (16Ω, THD+N < 1%)', 0), +(5, '输出阻抗', 'Output Impedance', '<1Ω', '< 1Ω', 1), +(5, '总谐波失真', 'THD+N', '<−117dB (1kHz/0dB@32Ω)', '< -117dB (1kHz / 0dB @ 32Ω)', 2), +(5, '信噪比', 'SNR', '≥123dB', '≥123dB', 3), +(5, '声道分离度', 'Crosstalk', '≥119dB (1kHz@32Ω)', '≥119dB (1kHz @ 32Ω)', 4); diff --git a/db/migrations/x8_basic_specs.sql b/db/migrations/x8_basic_specs.sql new file mode 100644 index 0000000..8fa38c9 --- /dev/null +++ b/db/migrations/x8_basic_specs.sql @@ -0,0 +1,20 @@ +-- 产品详情(product_id=1)参数区块「基本规格」补充参数项 +-- 区块:www_section_blocks.id=28(spec_table),分组:www_spec_groups.id=1(基本规格) +-- 已存在:型号 / 尺寸 / 重量(手工新增,sort_order 均为 0,此处一并规范化) + +-- 1) 规范化已有 3 项排序 +UPDATE www_spec_items SET sort_order = 0 WHERE id = 1; +UPDATE www_spec_items SET sort_order = 1 WHERE id = 2; +UPDATE www_spec_items SET sort_order = 2 WHERE id = 3; + +-- 2) 按图片补充剩余 9 项 +INSERT INTO www_spec_items (spec_group_id, name_zh, name_en, value_zh, value_en, sort_order) VALUES +(1, '电源输入', 'Input Power', 'AC 100–120V/220–240V~50/60Hz', 'AC 100-120V/220-240V~50/60Hz', 3), +(1, '屏幕', 'Display', '4英寸 LCD(480×960)触摸屏', '4" LCD (480*960) Touchscreen', 4), +(1, '解码', 'DAC', 'Cirrus Logic CS43198 × 8', 'Cirrus Logic CS43198 × 8', 5), +(1, '内部电源', 'Power Supply', '超低底噪可调电压线性电源', 'Ultra-low-noise, voltage-adjustable Linear Power Supply', 6), +(1, 'WiFi', 'WiFi', '支持2.4G/5G双频WiFi', 'Wi-Fi 2.4GHz / 5GHz', 7), +(1, '蓝牙接收', 'Bluetooth', 'Qualcomm SXW5125 (BT 5.1)', 'Qualcomm SXW5125 (BT 5.1)', 8), +(1, '控制方式', 'Control Methods', '触控屏, 移动设备 APP (Android/iOS), 电脑浏览器, 红外遥控器(选购配件)', 'Touchscreen, Mobile APP (Android/iOS), Web Browser, IR Remote(Optional)', 9), +(1, '额定功率', 'Rated Power', '25W', '25W', 10), +(1, '包装清单', 'Packing List', '电源线×1,USB-B线×1, 3.5mm转6.35mm适配器×1', 'Power Cable ×1, USB-B cable ×1, 3.5mm to 6.35mm adapter ×1', 11); diff --git a/db/migrations/x8_io_specs.sql b/db/migrations/x8_io_specs.sql new file mode 100644 index 0000000..1bb6a2a --- /dev/null +++ b/db/migrations/x8_io_specs.sql @@ -0,0 +1,15 @@ +-- 产品详情(product_id=1)参数区块「输入 / 输出」参数项 +-- 区块:www_section_blocks.id=28(spec_table),分组:www_spec_groups.id=2(输入 / 输出) + +INSERT INTO www_spec_items (spec_group_id, name_zh, name_en, value_zh, value_en, sort_order) VALUES +(2, 'USB-A 输入', 'USB-A Input', '用于本地固件更新', 'For local firmware update', 0), +(2, 'USB-B 输入', 'USB-B Input', '最高支持 PCM 768kHz/32bit; DSD512(Native)', 'Up to PCM 768kHz/32bit; DSD512(Native)', 1), +(2, 'USB-C 输入', 'USB-C Input', '最高支持 PCM 768kHz/32bit; DSD512(Native)', 'Up to PCM 768kHz/32bit; DSD512(Native)', 2), +(2, 'IIS 输入', 'IIS Input', '最高支持 PCM 768kHz/32bit; DSD512(Native)', 'Up to PCM 768kHz/32bit; DSD512(Native)', 3), +(2, '同轴输入', 'Coaxial Input', '最高支持 PCM 192kHz/24bit', 'Up to PCM 192kHz/24bit', 4), +(2, '光纤输入', 'Optical Input', '最高支持 PCM 192kHz/24bit', 'Up to PCM 192kHz/24bit', 5), +(2, 'TRIGGER IN', 'TRIGGER IN', '标准3.5mm耳机插座', 'Standard 3.5mm headphone jack', 6), +(2, 'TRIGGER OUT', 'TRIGGER OUT', '标准3.5mm耳机插座', 'Standard 3.5mm headphone jack', 7), +(2, '模拟输出接口', 'Analog Output', 'RCA', 'RCA', 8), +(2, '数字输出接口', 'Balanced Output', 'XLR', 'XLR', 9), +(2, '耳机输出接口', 'Headphone Output', '6.35mm(非平衡),4.4mm(平衡),4 pin XLR(平衡)', '6.35mm (Unbalanced), 4.4mm (Balanced), 4 pin XLR (Balanced)', 10); diff --git a/db/migrations/x8_rca_output_specs.sql b/db/migrations/x8_rca_output_specs.sql new file mode 100644 index 0000000..46c126f --- /dev/null +++ b/db/migrations/x8_rca_output_specs.sql @@ -0,0 +1,9 @@ +-- 产品详情(product_id=1)参数区块「RCA 输出音频特性」参数项 +-- 区块:www_section_blocks.id=28(spec_table),分组已预建:gid=4 + +INSERT INTO www_spec_items (spec_group_id, name_zh, name_en, value_zh, value_en, sort_order) VALUES +(4, '信噪比', 'SNR', '≥124.5dB', '≥124.5dB', 0), +(4, '总谐波失真', 'THD+N', '<−120dB @不加权', '< -120dB @ unweighted', 1), +(4, '声道分离度', 'Crosstalk', '≥125dB (1kHz@100kΩ)', '≥125dB (1kHz@100kΩ)', 2), +(4, '底噪', 'Noise Floor', '<1.3uVrms', '< 1.3uVrms', 3), +(4, '线路输出电平', 'Output Level', '2.1Vrms (1kHz@100kΩ)', '2.1Vrms (1kHz@100kΩ)', 4); diff --git a/db/migrations/x8_se_headphone_specs.sql b/db/migrations/x8_se_headphone_specs.sql new file mode 100644 index 0000000..30d3b82 --- /dev/null +++ b/db/migrations/x8_se_headphone_specs.sql @@ -0,0 +1,8 @@ +-- 产品详情(product_id=1)参数区块「单端耳机输出性能参数(6.35mm输出)」参数项 +-- 区块:www_section_blocks.id=28(spec_table),分组已预建:gid=6 + +INSERT INTO www_spec_items (spec_group_id, name_zh, name_en, value_zh, value_en, sort_order) VALUES +(6, '高增益', 'High Gain', 'L+R≥2900mW+2900mW(16Ω,THD+N<1%)', 'L+R≥2900mW+2900mW (16Ω, THD+N < 1%)', 0), +(6, '输出阻抗', 'Output Impedance', '<1Ω', '< 1Ω', 1), +(6, '总谐波失真', 'THD+N', '<−115dB (1kHz/0dB@32Ω)', '< -115dB (1kHz/0dB@32Ω)', 2), +(6, '信噪比', 'SNR', '≥121dB', '≥121dB', 3); diff --git a/db/migrations/x8_section_sort_fix.sql b/db/migrations/x8_section_sort_fix.sql new file mode 100644 index 0000000..5948323 --- /dev/null +++ b/db/migrations/x8_section_sort_fix.sql @@ -0,0 +1,11 @@ +-- Luxsin X8(product_id=1)区块排序修复 +-- 背景:所有区块 sort_order 均为 0,前台按 sort_order 排序导致顺序混乱。 +-- 已确认 www_section_blocks.id 为自增主键,按 id 升序(即创建顺序)重新分配 sort_order(0 起)。 +-- 同时后端 POST /api/www/sections 已改为:未指定 sort_order 时取同 page_type(+product_id) +-- 下现有区块的 max(sort_order)+1 自动追加,不再默认 0。 + +SET @row := -1; +UPDATE www_section_blocks +SET sort_order = (@row := @row + 1) +WHERE page_type = 'product_detail' AND product_id = 1 +ORDER BY id; diff --git a/db/migrations/x8_xlr_output_specs.sql b/db/migrations/x8_xlr_output_specs.sql new file mode 100644 index 0000000..b7a6bf1 --- /dev/null +++ b/db/migrations/x8_xlr_output_specs.sql @@ -0,0 +1,12 @@ +-- 产品详情(product_id=1)参数区块「XLR 输出音频特性」参数项 +-- 区块:www_section_blocks.id=28(spec_table) +-- 说明:分组「XLR 输出音频特性」已预先存在(gid=3),本脚本仅补参数项; +-- 执行中发现重复建组(gid=7)已清理:参数项改挂 gid=3,重复组已删除。 +-- 顺带规范了各分组 sort_order:基本规格=0、输入/输出=1、XLR=2、RCA=3、平衡耳机=4、单端耳机=5 + +INSERT INTO www_spec_items (spec_group_id, name_zh, name_en, value_zh, value_en, sort_order) VALUES +(3, '信噪比', 'SNR', '≥129.5dB', '≥129.5dB', 0), +(3, '总谐波失真', 'THD+N', '<−121.8dB @不加权', '< -121.8dB @ unweighted', 1), +(3, '声道分离度', 'Crosstalk', '≥133dB (1kHz@200kΩ)', '≥133dB (1kHz@200kΩ)', 2), +(3, '底噪', 'Noise Floor', '<1.1uVrms', '< 1.1uVrms', 3), +(3, '线路输出电平', 'Output Level', '4.2Vrms (1kHz@200kΩ)', '4.2Vrms (1kHz@200kΩ)', 4); diff --git a/tmp_home_check.png b/tmp_home_check.png new file mode 100644 index 0000000..d8bd5b3 Binary files /dev/null and b/tmp_home_check.png differ diff --git a/www/app/assets/css/main.css b/www/app/assets/css/main.css index cb69dbc..1c19697 100644 --- a/www/app/assets/css/main.css +++ b/www/app/assets/css/main.css @@ -4,6 +4,17 @@ html { -moz-osx-font-smoothing: grayscale; } +/* UnoCSS wind3 preflight 未含 Tailwind 标准的 border 重置:浏览器默认 border-style 为 none, + 导致 border-b / border 等宽度工具类不可见,此处补上(宽度默认 0,不影响未显式设置边框的元素) */ +*, +::before, +::after { + box-sizing: border-box; + border-width: 0; + border-style: solid; + border-color: currentColor; +} + body { margin: 0; font-family: diff --git a/www/app/components/section/SectionRenderer.vue b/www/app/components/section/SectionRenderer.vue index 0e35d8d..a355e9d 100644 --- a/www/app/components/section/SectionRenderer.vue +++ b/www/app/components/section/SectionRenderer.vue @@ -72,6 +72,13 @@ const paddingY = computed(() => { return typeof v === 'number' && v >= 0 ? `${v}px` : ''; }); +// 区块上下外边距(config.margin_y):单位 px,区块与相邻区块的间隙(露出页面背景); +// 未设置或 0 = 紧贴相邻区块(默认,全宽无缝拼接设计) +const marginY = computed(() => { + const v = props.section.config?.margin_y; + return typeof v === 'number' && v > 0 ? `${v}px` : ''; +}); + // 标题字号(config.title_font_size):桌面端 px,未设置时不下发变量(main.css 的 section h2 规则兜底 36px); // 移动端按桌面值 62.5% 等比缩小(--sec-title-fs-m) const titleFontSize = computed(() => { @@ -89,6 +96,7 @@ const sectionStyleVars = computed(() => { '--sec-cw': containerWidth, borderRadius: borderRadius.value, ...(paddingY.value ? { '--sec-py': paddingY.value } : {}), + ...(marginY.value ? { marginTop: marginY.value, marginBottom: marginY.value } : {}), ...(titleFontSize.value ? { '--sec-title-fs': titleFontSize.value.desktop, '--sec-title-fs-m': titleFontSize.value.mobile } : {}) } as CSSProperties; }); diff --git a/www/app/components/section/layouts/LayoutSpecTable.vue b/www/app/components/section/layouts/LayoutSpecTable.vue index 0e2e8e2..777e6e8 100644 --- a/www/app/components/section/layouts/LayoutSpecTable.vue +++ b/www/app/components/section/layouts/LayoutSpecTable.vue @@ -1,13 +1,14 @@