cinqcinqdev-seo 1.0.5 → 1.0.6

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/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.0.0"
6
6
  },
7
- "version": "1.0.5",
7
+ "version": "1.0.6",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "unknown"
@@ -1220,29 +1220,37 @@ export const DEFAULT_SECTIONS = {
1220
1220
  }
1221
1221
  }
1222
1222
  };
1223
- export const computeBlockCss = (props, blockId) => {
1224
- if (!props) return "";
1225
- const s = props._style || {};
1226
- const id = `[data-block-id="${blockId}"]`;
1223
+ const _shadowMap = {
1224
+ sm: "0 1px 3px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.08)",
1225
+ md: "0 4px 6px rgba(0,0,0,.1),0 2px 4px rgba(0,0,0,.06)",
1226
+ lg: "0 10px 15px rgba(0,0,0,.1),0 4px 6px rgba(0,0,0,.05)",
1227
+ xl: "0 20px 25px rgba(0,0,0,.12)",
1228
+ "2xl": "0 25px 50px rgba(0,0,0,.25)"
1229
+ };
1230
+ const _buildStyleCss = (s, id) => {
1227
1231
  const parts = [];
1228
1232
  const titleSels = `${id} h1,${id} h2,${id} h3,${id} h4`;
1229
1233
  const tr = [];
1230
- if (s.titleFontSize) tr.push(`font-size:${s.titleFontSize}px !important`);
1234
+ if (s.titleFontSize) tr.push(`font-size:${s.titleFontSize}rem !important`);
1231
1235
  if (s.titleFontWeight) tr.push(`font-weight:${s.titleFontWeight} !important`);
1232
1236
  if (s.titleFontStyle) tr.push(`font-style:${s.titleFontStyle} !important`);
1233
1237
  if (s.titleTextDecoration) tr.push(`text-decoration:${s.titleTextDecoration} !important`);
1234
1238
  if (s.titleColor) tr.push(`color:${s.titleColor} !important`);
1235
1239
  if (tr.length) parts.push(`${titleSels}{${tr.join(";")}}`);
1236
1240
  const bodySels = `${id} p,${id} li`;
1237
- const br2 = [];
1238
- if (s.bodyFontSize) br2.push(`font-size:${s.bodyFontSize}px !important`);
1239
- if (s.bodyFontWeight) br2.push(`font-weight:${s.bodyFontWeight} !important`);
1240
- if (s.bodyColor) br2.push(`color:${s.bodyColor} !important`);
1241
- if (br2.length) parts.push(`${bodySels}{${br2.join(";")}}`);
1241
+ const br = [];
1242
+ if (s.bodyFontSize) br.push(`font-size:${s.bodyFontSize}rem !important`);
1243
+ if (s.bodyFontWeight) br.push(`font-weight:${s.bodyFontWeight} !important`);
1244
+ if (s.bodyColor) br.push(`color:${s.bodyColor} !important`);
1245
+ if (br.length) parts.push(`${bodySels}{${br.join(";")}}`);
1242
1246
  const gr = [];
1243
1247
  if (s.lineHeight) gr.push(`line-height:${s.lineHeight}`);
1244
1248
  if (s.letterSpacing) gr.push(`letter-spacing:${s.letterSpacing}em`);
1245
1249
  if (gr.length) parts.push(`${id}{${gr.join(";")}}`);
1250
+ const lay = [];
1251
+ if (s.maxWidth) lay.push(`max-width:${s.maxWidth}px;margin-left:auto;margin-right:auto`);
1252
+ if (s.translateX || s.translateY) lay.push(`transform:translate(${s.translateX || 0}px,${s.translateY || 0}px)`);
1253
+ if (lay.length) parts.push(`${id}{${lay.join(";")}}`);
1246
1254
  const sp = [];
1247
1255
  if (s.paddingTop) sp.push(`padding-top:${s.paddingTop}px`);
1248
1256
  if (s.paddingBottom) sp.push(`padding-bottom:${s.paddingBottom}px`);
@@ -1253,19 +1261,29 @@ export const computeBlockCss = (props, blockId) => {
1253
1261
  if (sp.length) parts.push(`${id}{${sp.join(";")}}`);
1254
1262
  const bl = [];
1255
1263
  if (s.opacity !== "" && s.opacity != null) bl.push(`opacity:${s.opacity}`);
1256
- const shadowMap = {
1257
- sm: "0 1px 3px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.08)",
1258
- md: "0 4px 6px rgba(0,0,0,.1),0 2px 4px rgba(0,0,0,.06)",
1259
- lg: "0 10px 15px rgba(0,0,0,.1),0 4px 6px rgba(0,0,0,.05)",
1260
- xl: "0 20px 25px rgba(0,0,0,.12)",
1261
- "2xl": "0 25px 50px rgba(0,0,0,.25)"
1262
- };
1263
- if (s.boxShadow && s.boxShadow !== "none") bl.push(`box-shadow:${shadowMap[s.boxShadow] || s.boxShadow}`);
1264
+ if (s.boxShadow && s.boxShadow !== "none") bl.push(`box-shadow:${_shadowMap[s.boxShadow] || s.boxShadow}`);
1264
1265
  if (s.borderWidth) bl.push(`border-width:${s.borderWidth}px`);
1265
1266
  if (s.borderColor) bl.push(`border-color:${s.borderColor}`);
1266
1267
  if (s.borderStyle && s.borderStyle !== "none") bl.push(`border-style:${s.borderStyle}`);
1267
1268
  if (s.borderRadius) bl.push(`border-radius:${s.borderRadius}px`);
1268
1269
  if (bl.length) parts.push(`${id}{${bl.join(";")}}`);
1270
+ return parts.join("");
1271
+ };
1272
+ export const computeBlockCss = (props, blockId) => {
1273
+ if (!props) return "";
1274
+ const s = props._style || {};
1275
+ const id = `[data-block-id="${blockId}"]`;
1276
+ const parts = [];
1277
+ const desktopCss = _buildStyleCss(s, id);
1278
+ if (desktopCss) parts.push(desktopCss);
1279
+ if (s.tablet && Object.values(s.tablet).some(Boolean)) {
1280
+ const css = _buildStyleCss(s.tablet, id);
1281
+ if (css) parts.push(`@media(max-width:1024px){${css}}`);
1282
+ }
1283
+ if (s.mobile && Object.values(s.mobile).some(Boolean)) {
1284
+ const css = _buildStyleCss(s.mobile, id);
1285
+ if (css) parts.push(`@media(max-width:640px){${css}}`);
1286
+ }
1269
1287
  if (props.customCss) parts.push(`${id}{${props.customCss}}`);
1270
1288
  return parts.join("");
1271
1289
  };
@@ -94,14 +94,23 @@ const showAddModal = ref(false);
94
94
  const sectionSearch = ref("");
95
95
  const selectedFieldGroup = ref("contenu");
96
96
  const styleSection = ref("typo");
97
+ const styleBreakpoint = ref("desktop");
97
98
  const getStyle = (key) => {
98
- return page.value?.content[selectedBlockIndex.value]?.props?._style?.[key] ?? "";
99
+ const style = page.value?.content[selectedBlockIndex.value]?.props?._style;
100
+ if (!style) return "";
101
+ if (styleBreakpoint.value === "desktop") return style[key] ?? "";
102
+ return style[styleBreakpoint.value]?.[key] ?? "";
99
103
  };
100
104
  const setStyle = (key, value) => {
101
105
  const props = page.value?.content[selectedBlockIndex.value]?.props;
102
106
  if (!props) return;
103
107
  if (!props._style) props._style = {};
104
- props._style[key] = value;
108
+ if (styleBreakpoint.value === "desktop") {
109
+ props._style[key] = value;
110
+ } else {
111
+ if (!props._style[styleBreakpoint.value]) props._style[styleBreakpoint.value] = {};
112
+ props._style[styleBreakpoint.value][key] = value;
113
+ }
105
114
  trigger();
106
115
  };
107
116
  const SECTION_GROUPS = [
@@ -935,6 +944,49 @@ const savePage = async () => {
935
944
  <!-- ── STYLE PANEL (when Style tab active) ──────────────────── -->
936
945
  <div v-if="selectedFieldGroup === 'style'" class="mb-6 space-y-3">
937
946
 
947
+ <!-- Breakpoint switcher -->
948
+ <div class="flex gap-1 bg-gray-100 rounded-xl p-1">
949
+ <button v-for="bp in [{ v: 'desktop', l: '\u{1F5A5} Desktop' }, { v: 'tablet', l: '\u2B1B Tablet' }, { v: 'mobile', l: '\u{1F4F1} Mobile' }]" :key="bp.v"
950
+ @click="styleBreakpoint = bp.v"
951
+ :class="['flex-1 py-1.5 rounded-lg text-[7px] font-black uppercase tracking-wide transition-all', styleBreakpoint === bp.v ? 'bg-white shadow text-[#3d35ff]' : 'text-gray-400 hover:text-gray-600']">
952
+ {{ bp.l }}
953
+ </button>
954
+ </div>
955
+
956
+ <!-- Layout -->
957
+ <div class="border border-gray-100 rounded-2xl overflow-hidden">
958
+ <button @click="styleSection = styleSection === 'layout' ? '' : 'layout'"
959
+ class="w-full flex items-center justify-between px-4 py-3 bg-gray-50 hover:bg-gray-100 transition-colors">
960
+ <span class="text-[9px] font-black uppercase tracking-widest text-gray-700">⊞ Layout</span>
961
+ <svg :class="['w-3 h-3 text-gray-400 transition-transform', styleSection === 'layout' ? 'rotate-180' : '']" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M19 9l-7 7-7-7"/></svg>
962
+ </button>
963
+ <div v-show="styleSection === 'layout'" class="p-4 space-y-3">
964
+ <div>
965
+ <label class="text-[7px] font-black uppercase text-gray-400 block mb-1">Max Width (px)</label>
966
+ <div class="flex items-center gap-1 bg-gray-50 rounded-xl ring-1 ring-gray-100 overflow-hidden px-2">
967
+ <input type="number" :value="getStyle('maxWidth')" @input="setStyle('maxWidth', $event.target.value)" min="0" max="3000" step="10" placeholder="—" class="flex-1 bg-transparent py-2.5 text-[10px] font-mono outline-none w-0" />
968
+ <span class="text-[8px] text-gray-300 shrink-0">px</span>
969
+ </div>
970
+ </div>
971
+ <div class="flex gap-2">
972
+ <div class="flex-1">
973
+ <label class="text-[7px] font-black uppercase text-gray-400 block mb-1">Position X (px)</label>
974
+ <div class="flex items-center gap-1 bg-gray-50 rounded-xl ring-1 ring-gray-100 overflow-hidden px-2">
975
+ <input type="number" :value="getStyle('translateX')" @input="setStyle('translateX', $event.target.value)" step="1" placeholder="0" class="flex-1 bg-transparent py-2.5 text-[10px] font-mono outline-none w-0" />
976
+ <span class="text-[8px] text-gray-300 shrink-0">px</span>
977
+ </div>
978
+ </div>
979
+ <div class="flex-1">
980
+ <label class="text-[7px] font-black uppercase text-gray-400 block mb-1">Position Y (px)</label>
981
+ <div class="flex items-center gap-1 bg-gray-50 rounded-xl ring-1 ring-gray-100 overflow-hidden px-2">
982
+ <input type="number" :value="getStyle('translateY')" @input="setStyle('translateY', $event.target.value)" step="1" placeholder="0" class="flex-1 bg-transparent py-2.5 text-[10px] font-mono outline-none w-0" />
983
+ <span class="text-[8px] text-gray-300 shrink-0">px</span>
984
+ </div>
985
+ </div>
986
+ </div>
987
+ </div>
988
+ </div>
989
+
938
990
  <!-- Typography -->
939
991
  <div class="border border-gray-100 rounded-2xl overflow-hidden">
940
992
  <button @click="styleSection = styleSection === 'typo' ? '' : 'typo'"
@@ -948,10 +1000,10 @@ const savePage = async () => {
948
1000
  <p class="text-[8px] font-black uppercase tracking-widest text-[#3d35ff]/60 mb-2">Title (h1–h4)</p>
949
1001
  <div class="flex gap-2 mb-2">
950
1002
  <div class="flex-1">
951
- <label class="text-[7px] font-black uppercase text-gray-400 block mb-1">Size (px)</label>
1003
+ <label class="text-[7px] font-black uppercase text-gray-400 block mb-1">Size (rem)</label>
952
1004
  <div class="flex items-center gap-1 bg-gray-50 rounded-xl ring-1 ring-gray-100 overflow-hidden px-2">
953
- <input type="number" :value="getStyle('titleFontSize')" @input="setStyle('titleFontSize', $event.target.value)" min="8" max="300" placeholder="—" class="flex-1 bg-transparent py-2.5 text-[10px] font-mono outline-none w-0" />
954
- <span class="text-[8px] text-gray-300 shrink-0">px</span>
1005
+ <input type="number" :value="getStyle('titleFontSize')" @input="setStyle('titleFontSize', $event.target.value)" min="0.1" max="20" step="0.1" placeholder="—" class="flex-1 bg-transparent py-2.5 text-[10px] font-mono outline-none w-0" />
1006
+ <span class="text-[8px] text-gray-300 shrink-0">rem</span>
955
1007
  </div>
956
1008
  </div>
957
1009
  <div class="flex-1">
@@ -983,10 +1035,10 @@ const savePage = async () => {
983
1035
  <p class="text-[8px] font-black uppercase tracking-widest text-[#3d35ff]/60 mb-2">Body (p, li)</p>
984
1036
  <div class="flex gap-2 mb-2">
985
1037
  <div class="flex-1">
986
- <label class="text-[7px] font-black uppercase text-gray-400 block mb-1">Size (px)</label>
1038
+ <label class="text-[7px] font-black uppercase text-gray-400 block mb-1">Size (rem)</label>
987
1039
  <div class="flex items-center gap-1 bg-gray-50 rounded-xl ring-1 ring-gray-100 px-2">
988
- <input type="number" :value="getStyle('bodyFontSize')" @input="setStyle('bodyFontSize', $event.target.value)" min="8" max="100" placeholder="—" class="flex-1 bg-transparent py-2.5 text-[10px] font-mono outline-none w-0" />
989
- <span class="text-[8px] text-gray-300 shrink-0">px</span>
1040
+ <input type="number" :value="getStyle('bodyFontSize')" @input="setStyle('bodyFontSize', $event.target.value)" min="0.1" max="10" step="0.1" placeholder="—" class="flex-1 bg-transparent py-2.5 text-[10px] font-mono outline-none w-0" />
1041
+ <span class="text-[8px] text-gray-300 shrink-0">rem</span>
990
1042
  </div>
991
1043
  </div>
992
1044
  <div class="flex-1">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cinqcinqdev-seo",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "A reusable Nuxt 3 admin CMS module with visual page editor powered by Supabase",
5
5
  "license": "MIT",
6
6
  "module": "./dist/module.mjs",