domma-cms 0.46.4 → 0.47.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "domma-cms",
3
- "version": "0.46.4",
3
+ "version": "0.47.0",
4
4
  "description": "File-based CMS powered by Domma and Fastify. Run npx domma-cms my-site to create a new project.",
5
5
  "type": "module",
6
6
  "main": "server/server.js",
@@ -0,0 +1 @@
1
+ export const SIZE_MAP={xs:".75rem",sm:".875rem",base:"1rem",lg:"1.125rem",xl:"1.25rem","2xl":"1.5rem","3xl":"1.875rem","4xl":"2.25rem"},WEIGHT_MAP={thin:"100",light:"300",normal:"400",medium:"500",semibold:"600",bold:"700",extrabold:"800",black:"900"},SPACING_MAP={tight:"-0.05em",normal:"0em",wide:"0.05em",wider:"0.1em"},COLOUR_TOKENS={primary:"var(--dm-color-primary)",secondary:"var(--dm-color-secondary)",muted:"var(--dm-text-muted)",danger:"var(--dm-color-danger)",success:"var(--dm-color-success)",warning:"var(--dm-color-warning)",info:"var(--dm-color-info)"},FONT_MAP={Georgia:"Georgia,serif",Arial:"Arial,sans-serif",Verdana:"Verdana,sans-serif","Courier New":"'Courier New',monospace","Times New Roman":"'Times New Roman',serif","Trebuchet MS":"'Trebuchet MS',sans-serif"},TRANSFORM_MAP={upper:"uppercase",lower:"lowercase",capitalize:"capitalize",none:"none"},DECORATION_MAP={underline:"underline","line-through":"line-through",none:"none"};function l(e){return e!=null&&e!==!1&&e!=="false"&&e!=="0"}function i(e){return String(e).replace(/["<>]/g,"").trim()}export function buildTextStyle(e={}){const o=[];if(e.size&&o.push(`font-size:${SIZE_MAP[e.size]||i(e.size)}`),e["point-size"]){const r=parseFloat(e["point-size"]);!isNaN(r)&&r>0&&o.push(`font-size:${r}pt`)}l(e.bold)?o.push("font-weight:700"):e.weight&&WEIGHT_MAP[e.weight]&&o.push(`font-weight:${WEIGHT_MAP[e.weight]}`),l(e.italic)&&o.push("font-style:italic");const n=e.colour||e.color;return n&&o.push(`color:${COLOUR_TOKENS[n]||i(n)}`),e.font&&FONT_MAP[e.font]&&o.push(`font-family:${FONT_MAP[e.font]}`),e.transform&&TRANSFORM_MAP[e.transform]&&o.push(`text-transform:${TRANSFORM_MAP[e.transform]}`),e.decoration&&DECORATION_MAP[e.decoration]&&o.push(`text-decoration:${DECORATION_MAP[e.decoration]}`),e.spacing&&o.push(`letter-spacing:${SPACING_MAP[e.spacing]||i(e.spacing)}`),e.align&&(o.push("display:block"),o.push(`text-align:${i(e.align)}`)),e.style&&o.push(i(e.style).replace(/;+$/,"")),o.join(";")}
@@ -15,6 +15,7 @@ import {getMenu, resolveLocation, resolveMenuDecorations} from './menus.js';
15
15
  import {buildMenuNav} from './menuRender.js';
16
16
  import {checkVisibility} from '../middleware/auth.js';
17
17
  import {getRoleHierarchy} from './roles.js';
18
+ import {buildTextStyle} from '../../public/js/text-style.mjs';
18
19
 
19
20
  const __dirname_md = path.dirname(fileURLToPath(import.meta.url));
20
21
  const BLOCKS_DIR = path.resolve(__dirname_md, '../../content/blocks');
@@ -3014,94 +3015,12 @@ function processBadgeBlocks(markdown) {
3014
3015
  function processTextBlocks(markdown) {
3015
3016
  const {scrubbed, restore} = scrubCodeRegions(markdown);
3016
3017
 
3017
- const SIZE_MAP = {
3018
- xs: '.75rem', sm: '.875rem', base: '1rem', lg: '1.125rem',
3019
- xl: '1.25rem', '2xl': '1.5rem', '3xl': '1.875rem', '4xl': '2.25rem',
3020
- };
3021
- const WEIGHT_MAP = {
3022
- thin: '100', light: '300', normal: '400', medium: '500',
3023
- semibold: '600', bold: '700', extrabold: '800', black: '900',
3024
- };
3025
- const SPACING_MAP = {
3026
- tight: '-0.05em', normal: '0em', wide: '0.05em', wider: '0.1em',
3027
- };
3028
- const COLOR_TOKENS = {
3029
- primary: 'var(--dm-color-primary)', secondary: 'var(--dm-color-secondary)',
3030
- muted: 'var(--dm-text-muted)', danger: 'var(--dm-color-danger)',
3031
- success: 'var(--dm-color-success)', warning: 'var(--dm-color-warning)',
3032
- info: 'var(--dm-color-info)',
3033
- };
3034
- const FONT_MAP = {
3035
- 'Georgia': 'Georgia,serif',
3036
- 'Arial': 'Arial,sans-serif',
3037
- 'Verdana': 'Verdana,sans-serif',
3038
- 'Courier New': "'Courier New',monospace",
3039
- 'Times New Roman': "'Times New Roman',serif",
3040
- 'Trebuchet MS': "'Trebuchet MS',sans-serif",
3041
- };
3042
- const TRANSFORM_MAP = {
3043
- upper: 'uppercase', lower: 'lowercase', capitalize: 'capitalize', none: 'none',
3044
- };
3045
- const DECORATION_MAP = {
3046
- underline: 'underline', 'line-through': 'line-through', none: 'none',
3047
- };
3048
-
3049
3018
  function buildText(attrStr, inner) {
3050
3019
  const attrs = parseShortcodeAttrs(attrStr || '');
3051
- const styles = [];
3052
-
3053
- if (attrs.size) {
3054
- styles.push(`font-size:${SIZE_MAP[attrs.size] || attrs.size}`);
3055
- }
3056
-
3057
- if (attrs['point-size']) {
3058
- const pt = parseFloat(attrs['point-size']);
3059
- if (!isNaN(pt) && pt > 0) styles.push(`font-size:${pt}pt`);
3060
- }
3061
-
3062
- // bold flag takes precedence over weight attr
3063
- const isBold = /\bbold\b/i.test(attrStr);
3064
- if (isBold) {
3065
- styles.push('font-weight:700');
3066
- } else if (attrs.weight && WEIGHT_MAP[attrs.weight]) {
3067
- styles.push(`font-weight:${WEIGHT_MAP[attrs.weight]}`);
3068
- }
3069
-
3070
- if (/\bitalic\b/i.test(attrStr)) {
3071
- styles.push('font-style:italic');
3072
- }
3073
-
3074
- const colourVal = attrs.colour || attrs.color;
3075
- if (colourVal) {
3076
- styles.push(`color:${COLOR_TOKENS[colourVal] || colourVal}`);
3077
- }
3078
-
3079
- if (attrs.font && FONT_MAP[attrs.font]) {
3080
- styles.push(`font-family:${FONT_MAP[attrs.font]}`);
3081
- }
3082
-
3083
- if (attrs.transform && TRANSFORM_MAP[attrs.transform]) {
3084
- styles.push(`text-transform:${TRANSFORM_MAP[attrs.transform]}`);
3085
- }
3086
-
3087
- if (attrs.decoration && DECORATION_MAP[attrs.decoration]) {
3088
- styles.push(`text-decoration:${DECORATION_MAP[attrs.decoration]}`);
3089
- }
3090
-
3091
- if (attrs.spacing) {
3092
- styles.push(`letter-spacing:${SPACING_MAP[attrs.spacing] || attrs.spacing}`);
3093
- }
3094
-
3095
- if (attrs.align) {
3096
- styles.push('display:block');
3097
- styles.push(`text-align:${escapeAttr(attrs.align)}`);
3098
- }
3099
-
3100
- if (attrs.style) {
3101
- styles.push(attrs.style.trim().replace(/;+$/, ''));
3102
- }
3103
-
3104
- const styleAttr = styles.length ? ` style="${styles.join(';')}"` : '';
3020
+ // The attribute → CSS mapping is shared with the admin editor's live
3021
+ // preview (public/js/text-style.mjs), so the two cannot disagree.
3022
+ const style = buildTextStyle(attrs);
3023
+ const styleAttr = style ? ` style="${style}"` : '';
3105
3024
  const classAttr = attrs.class ? ` class="${escapeAttr(attrs.class)}"` : '';
3106
3025
  const idAttr = attrs.id ? ` id="${escapeAttr(attrs.id)}"` : '';
3107
3026