Skip to content

Commit f92b09e

Browse files
committed
Allow custom styles for codeblocks
1 parent fa185fb commit f92b09e

File tree

3 files changed

+93
-32
lines changed

3 files changed

+93
-32
lines changed

packages/ui-extensions/docs/surfaces/admin/build-docs.mjs

Lines changed: 85 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -48,41 +48,95 @@ const decodeHTML = (str) => {
4848
.replace(/'/g, "'");
4949
};
5050

51-
const htmlWrapper = (htmlString, layout) => {
52-
return `<!DOCTYPE html><html><head><style>html, body {height:100%} body {box-sizing: border-box; margin: 0; padding:0.5rem; ${layout}}</style><script src="https://cdn.shopify.com/shopifycloud/polaris.js"></script></head><body>${decodeHTML(
51+
const composeStyles = (...styles) => {
52+
return styles
53+
.filter(Boolean)
54+
.map((style) => style.trim())
55+
.filter((style) => style.length > 0)
56+
.join(' ');
57+
};
58+
59+
/**
60+
* Converts CSS style object to CSS string
61+
* @param {string | object} styles - CSS string or object
62+
* @returns {string} CSS string
63+
*/
64+
const stylesToString = (styles) => {
65+
if (typeof styles === 'string') {
66+
return styles;
67+
}
68+
if (typeof styles === 'object' && styles !== null) {
69+
return Object.entries(styles)
70+
.map(([property, value]) => {
71+
// Convert camelCase to kebab-case
72+
const kebabProperty = property.replace(
73+
/[A-Z]/g,
74+
(match) => `-${match.toLowerCase()}`,
75+
);
76+
return `${kebabProperty}: ${value}`;
77+
})
78+
.join('; ');
79+
}
80+
return '';
81+
};
82+
83+
const htmlWrapper = (htmlString, layoutStyles = '', customStyles = '') => {
84+
const baseStyles = 'box-sizing: border-box; margin: 0; padding: 0.5rem;';
85+
const customStylesString = stylesToString(customStyles);
86+
const composedStyles = composeStyles(
87+
baseStyles,
88+
layoutStyles,
89+
customStylesString,
90+
);
91+
92+
return `<!DOCTYPE html><html><head><style>html, body {height:100%} body {${composedStyles}}</style><script src="https://cdn.shopify.com/shopifycloud/polaris.js"></script></head><body>${decodeHTML(
5393
htmlString,
5494
)}</body></html>`;
5595
};
5696

97+
const createTemplate = ({
98+
layoutStyles,
99+
wrapperElement = null,
100+
wrapperAttributes = '',
101+
}) => {
102+
return (htmlString, customStyles = '') => {
103+
const wrappedHtml = wrapperElement
104+
? `<${wrapperElement}${
105+
wrapperAttributes ? ` ${wrapperAttributes}` : ''
106+
}>${htmlString}</${wrapperElement}>`
107+
: htmlString;
108+
109+
return htmlWrapper(wrappedHtml, layoutStyles, stylesToString(customStyles));
110+
};
111+
};
112+
57113
const templates = {
58-
default: (htmlString) =>
59-
htmlWrapper(htmlString, 'display: grid; place-items: center; gap: 0.5rem;'),
60-
alignStart: (htmlString) =>
61-
htmlWrapper(
62-
`<div>${htmlString}</div>`,
63-
'display: grid; place-items: start center; gap: 0.5rem;',
64-
),
65-
wrapped: (htmlString) =>
66-
htmlWrapper(
67-
`<div>${htmlString}</div>`,
68-
'display: grid; place-items: center; gap: 0.5rem;',
69-
),
70-
inline: (htmlString) =>
71-
htmlWrapper(
72-
htmlString,
114+
default: createTemplate({
115+
layoutStyles: 'display: grid; place-items: center; gap: 0.5rem;',
116+
}),
117+
alignStart: createTemplate({
118+
layoutStyles: 'display: grid; place-items: start center; gap: 0.5rem;',
119+
wrapperElement: 'div',
120+
}),
121+
wrapped: createTemplate({
122+
layoutStyles: 'display: grid; place-items: center; gap: 0.5rem;',
123+
wrapperElement: 'div',
124+
}),
125+
inline: createTemplate({
126+
layoutStyles:
73127
'display: flex; justify-content: center; align-items: center; gap: 0.5rem;',
74-
),
75-
section: (htmlString) =>
76-
htmlWrapper(
77-
`<s-section padding="none">${htmlString}</s-section>`,
78-
'display: grid; place-items: center; background: #F1F1F1',
79-
),
80-
page: (htmlString) =>
81-
htmlWrapper(
82-
htmlString,
83-
'display: grid; place-items: center; background: #F1F1F1;',
84-
),
85-
none: (htmlString) => htmlWrapper(htmlString, 'padding: 0'),
128+
}),
129+
section: createTemplate({
130+
layoutStyles: 'display: grid; place-items: center; background: #F1F1F1',
131+
wrapperElement: 's-section',
132+
wrapperAttributes: 'padding="none"',
133+
}),
134+
page: createTemplate({
135+
layoutStyles: 'display: grid; place-items: center; background: #F1F1F1;',
136+
}),
137+
none: createTemplate({
138+
layoutStyles: 'padding: 0',
139+
}),
86140
};
87141

88142
const transformJson = async (filePath, isExtensions) => {
@@ -124,8 +178,8 @@ const transformJson = async (filePath, isExtensions) => {
124178

125179
const previewHTML =
126180
tab.layout && tab.layout in templates
127-
? templates[tab.layout](tab.code)
128-
: templates.default(tab.code);
181+
? templates[tab.layout](tab.code, tab.customStyles)
182+
: templates.default(tab.code, tab.customStyles);
129183

130184
newTabs.push(
131185
{code: tab.code, language: 'html'},

packages/ui-extensions/src/surfaces/admin/components/DateField/DateField.doc.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ const data: AdminReferenceEntityTemplateSchema = {
2727
code: './examples/default.html',
2828
language: 'preview',
2929
layout: 'alignStart',
30+
customStyles: {
31+
minHeight: '300px',
32+
},
3033
},
3134
],
3235
},

packages/ui-extensions/src/surfaces/admin/docs-types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type {CSSProperties} from 'react';
12
import {
23
ReferenceEntityTemplateSchema,
34
CodeTabType,
@@ -11,7 +12,10 @@ export interface AdminReferenceEntityTemplateSchema
1112
> & {
1213
codeblock?: {
1314
title: string;
14-
tabs: (CodeTabType & {layout?: string})[];
15+
tabs: (CodeTabType & {
16+
layout?: string;
17+
customStyles?: string | CSSProperties;
18+
})[];
1519
};
1620
};
1721
}

0 commit comments

Comments
 (0)