Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit cbb31ba

Browse files
committedOct 1, 2024·
wip
1 parent d74b3e6 commit cbb31ba

File tree

8 files changed

+285
-74
lines changed

8 files changed

+285
-74
lines changed
 

‎apps/builder/app/shared/copy-paste/plugin-webflow/__generated__/style-presets.ts

+21-14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎apps/builder/app/shared/copy-paste/plugin-webflow/instances-properties.ts

+10
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,16 @@ const toFragment = (
108108
addInstance(component);
109109
return fragment;
110110
}
111+
case "Figure": {
112+
addInstance("Box");
113+
addProp("tag", "figure");
114+
return fragment;
115+
}
116+
case "Figcaption": {
117+
addInstance("Text");
118+
addProp("tag", "figcaption");
119+
return fragment;
120+
}
111121
case "Block": {
112122
const component = wfNode.data?.text ? "Text" : "Box";
113123
if (wfNode.tag !== "div") {

‎apps/builder/app/shared/copy-paste/plugin-webflow/plugin-webflow.test.tsx

+157-32
Original file line numberDiff line numberDiff line change
@@ -534,38 +534,6 @@ test("Section", async () => {
534534
`);
535535
});
536536

537-
test("Figure", async () => {
538-
const fragment = await toWebstudioFragment({
539-
type: "@webflow/XscpData",
540-
payload: {
541-
nodes: [
542-
{
543-
_id: "7c6bc1fd-128d-514b-167b-605a910e435c",
544-
type: "Block",
545-
tag: "figure",
546-
classes: [],
547-
children: [],
548-
},
549-
],
550-
styles: [],
551-
assets: [],
552-
},
553-
});
554-
555-
equalFragment(fragment, <$.Box tag="figure" />);
556-
expect(toCss(fragment)).toMatchInlineSnapshot(`
557-
"@media all {
558-
figure {
559-
display: block;
560-
margin-top: 0;
561-
margin-right: 0;
562-
margin-bottom: 10px;
563-
margin-left: 0
564-
}
565-
}"
566-
`);
567-
});
568-
569537
test("BlockContainer", async () => {
570538
const fragment = await toWebstudioFragment({
571539
type: "@webflow/XscpData",
@@ -1550,6 +1518,163 @@ test("RichText", async () => {
15501518
`);
15511519
});
15521520

1521+
test("RichText with Figure and Figcaption", async () => {
1522+
const fragment = await toWebstudioFragment({
1523+
type: "@webflow/XscpData",
1524+
payload: {
1525+
nodes: [
1526+
{
1527+
_id: "a7a2b490-c6c5-30aa-1827-b38a0ae42a08",
1528+
type: "RichText",
1529+
tag: "div",
1530+
classes: [],
1531+
children: ["3ddc1727-a0f4-33c5-3879-cb1d9d932c59"],
1532+
},
1533+
{
1534+
_id: "3ddc1727-a0f4-33c5-3879-cb1d9d932c59",
1535+
type: "Figure",
1536+
tag: "figure",
1537+
classes: [],
1538+
children: [
1539+
"72cdf71c-b2da-c44a-3ecd-9ec9891f6023",
1540+
"f48219da-c3ef-2439-07e3-a843ef8c0891",
1541+
],
1542+
data: {
1543+
figure: {
1544+
type: "image",
1545+
align: "center",
1546+
maxWidth: "",
1547+
},
1548+
},
1549+
},
1550+
{
1551+
_id: "72cdf71c-b2da-c44a-3ecd-9ec9891f6023",
1552+
type: "Block",
1553+
tag: "div",
1554+
classes: [],
1555+
children: ["4b0dc79a-bbb0-b136-d913-f1e3581f2b36"],
1556+
data: {
1557+
text: false,
1558+
},
1559+
},
1560+
{
1561+
_id: "4b0dc79a-bbb0-b136-d913-f1e3581f2b36",
1562+
type: "Image",
1563+
tag: "img",
1564+
classes: [],
1565+
children: [],
1566+
data: {
1567+
//srcsetDisabled: false,
1568+
attr: {
1569+
width: "auto",
1570+
height: "auto",
1571+
alt: "__wf_reserved_inherit",
1572+
src: "https://test.com/image.jpg",
1573+
loading: "lazy",
1574+
id: "",
1575+
},
1576+
sizes: [],
1577+
devlink: {
1578+
runtimeProps: {},
1579+
slot: "",
1580+
},
1581+
displayName: "",
1582+
xattr: [],
1583+
search: {
1584+
exclude: false,
1585+
},
1586+
visibility: {
1587+
conditions: [],
1588+
},
1589+
},
1590+
},
1591+
{
1592+
_id: "f48219da-c3ef-2439-07e3-a843ef8c0891",
1593+
type: "Figcaption",
1594+
tag: "figcaption",
1595+
classes: [],
1596+
children: ["d5e8480a-f395-38d5-530b-78cb05b6888f"],
1597+
},
1598+
{
1599+
_id: "d5e8480a-f395-38d5-530b-78cb05b6888f",
1600+
text: true,
1601+
v: "test",
1602+
},
1603+
],
1604+
styles: [],
1605+
assets: [
1606+
{
1607+
cdnUrl: "https://test.com/image.jpg",
1608+
siteId: "66ab8a32bcc969149d6a7a1a",
1609+
width: 174,
1610+
height: 136,
1611+
fileName:
1612+
"66d8522c8e9dbb5e2b2de76c_Screenshot 2024-09-02 at 18.20.14.png",
1613+
createdOn: "2024-09-04T12:27:24.621Z",
1614+
origFileName: "Screenshot 2024-09-02 at 18.20.14.png",
1615+
fileHash: "496bace14fbde33d31e0417dd70216d0",
1616+
//translationLoading: false,
1617+
variants: [],
1618+
mimeType: "image/png",
1619+
_id: "66d8522c8e9dbb5e2b2de76c",
1620+
updatedOn: "2024-09-04T12:55:38.572Z",
1621+
fileSize: 20599,
1622+
localizedSettings: {},
1623+
},
1624+
],
1625+
ix1: [],
1626+
ix2: {
1627+
interactions: [],
1628+
events: [],
1629+
actionLists: [],
1630+
},
1631+
},
1632+
meta: {
1633+
droppedLinks: 0,
1634+
dynBindRemovedCount: 0,
1635+
dynListBindRemovedCount: 0,
1636+
paginationRemovedCount: 0,
1637+
universalBindingsRemovedCount: 0,
1638+
unlinkedSymbolCount: 0,
1639+
},
1640+
});
1641+
1642+
equalFragment(
1643+
fragment,
1644+
<$.Box>
1645+
<$.Box tag="figure">
1646+
<$.Box>
1647+
<$.Image loading="lazy" src="https://test.com/image.jpg" />
1648+
</$.Box>
1649+
<$.Text tag="figcaption">test</$.Text>
1650+
</$.Box>
1651+
</$.Box>
1652+
);
1653+
1654+
expect(toCss(fragment)).toMatchInlineSnapshot(`
1655+
"@media all {
1656+
figure {
1657+
display: block;
1658+
margin-top: 0;
1659+
margin-right: 0;
1660+
margin-bottom: 10px;
1661+
margin-left: 0
1662+
}
1663+
img {
1664+
vertical-align: middle;
1665+
max-width: 100%;
1666+
display: inline-block;
1667+
border: 0 none currentcolor
1668+
}
1669+
figcaption {
1670+
display: block;
1671+
text-align: center;
1672+
margin-top: 5px
1673+
}
1674+
}"
1675+
`);
1676+
});
1677+
15531678
test("Form", async () => {
15541679
const fragment = await toWebstudioFragment({
15551680
type: "@webflow/XscpData",

‎apps/builder/app/shared/copy-paste/plugin-webflow/plugin-webflow.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ const parse = (clipboardData: string) => {
117117
if (data.type !== "@webflow/XscpData") {
118118
return;
119119
}
120-
120+
console.log(data);
121121
const unsupportedNodeTypes: Set<string> = new Set(
122122
data.payload.nodes
123123
.filter((node: { type: string }) => {
@@ -139,7 +139,7 @@ const parse = (clipboardData: string) => {
139139
const result = WfData.safeParse(data);
140140

141141
if (result.success) {
142-
const unpasedTypes = new Set<string>();
142+
const unparsedTypes = new Set<string>();
143143

144144
for (let i = 0; i !== result.data.payload.nodes.length; ++i) {
145145
if ("type" in result.data.payload.nodes[i]) {
@@ -156,11 +156,11 @@ const parse = (clipboardData: string) => {
156156
continue;
157157
}
158158

159-
unpasedTypes.add(probablyUnparsedType);
159+
unparsedTypes.add(probablyUnparsedType);
160160
}
161161

162-
if (unpasedTypes.size !== 0) {
163-
const message = `The following types were skipped due to a parsing error: ${[...unpasedTypes.values()].join(", ")}`;
162+
if (unparsedTypes.size !== 0) {
163+
const message = `The following types were skipped due to a parsing error: ${[...unparsedTypes.values()].join(", ")}`;
164164
toast.info(message);
165165
console.info(message);
166166
}

‎apps/builder/app/shared/copy-paste/plugin-webflow/schema.ts

+22-2
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ export const wfNodeTypes = [
127127
"NavbarContainer",
128128
"Icon",
129129
"LightboxWrapper",
130+
"Figure",
131+
"Figcaption",
130132
] as const;
131133

132134
const WfElementNode = z.union([
@@ -190,6 +192,23 @@ const WfElementNode = z.union([
190192
WfBaseNode.extend({ type: z.enum(["Grid"]) }),
191193
WfBaseNode.extend({ type: z.enum(["Row"]) }),
192194
WfBaseNode.extend({ type: z.enum(["Column"]) }),
195+
WfBaseNode.extend({ type: z.enum(["Figcaption"]) }),
196+
WfBaseNode.extend({
197+
type: z.enum(["Figure"]),
198+
data: WfNodeData.extend({
199+
style: z.record(styleProperty, styleValue).optional(),
200+
figure: z.object({
201+
type: z.enum(["image"]), // @todo add more types
202+
align: z.enum([
203+
"normal",
204+
"center",
205+
"fullwidth",
206+
"floatleft",
207+
"floatright",
208+
]),
209+
}),
210+
}),
211+
}),
193212
WfBaseNode.extend({
194213
type: z.enum(["CodeBlock"]),
195214
data: WfNodeData.extend({
@@ -209,8 +228,9 @@ const WfElementNode = z.union([
209228
alt: z.string().optional(),
210229
loading: z.enum(["lazy", "eager", "auto"]),
211230
src: z.string(),
212-
width: z.string(),
213-
height: z.string(),
231+
// width/height is not provided for rich text image
232+
width: z.string().optional(),
233+
height: z.string().optional(),
214234
}),
215235
}),
216236
}),

‎apps/builder/app/shared/copy-paste/plugin-webflow/styles.ts

+10
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,16 @@ const mapComponentAndPresetStyles = (
440440
case "NavbarButton":
441441
presetStyles.push("w-nav-button");
442442
return presetStyles;
443+
444+
case "RichText":
445+
presetStyles.push("w-richtext");
446+
return presetStyles;
447+
case "Figure": {
448+
const { align } = wfNode.data.figure;
449+
presetStyles.push("w-richtext-figure-type-image");
450+
presetStyles.push(`w-richtext-align-${align}`);
451+
return presetStyles;
452+
}
443453
}
444454

445455
return presetStyles;

‎packages/css-data/src/parse-css.test.ts

+25-3
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ describe("Parse CSS", () => {
221221
]);
222222
});
223223

224-
test("parse multiple selectors, both with state", () => {
224+
test.only("parse multiple selectors, both with state", () => {
225225
expect(parseCss(`a:active, a:hover { color: #ff0000 }`)).toEqual([
226226
{
227227
selector: "a",
@@ -460,11 +460,33 @@ describe("Parse CSS", () => {
460460
});
461461

462462
test("parse child combinator", () => {
463-
expect(parseCss(`a > b { color: #ff0000 }`)).toEqual([]);
463+
expect(parseCss(`a > b { color: #ff0000 }`)).toEqual([
464+
{
465+
selector: "a > b",
466+
property: "color",
467+
value: { alpha: 1, b: 0, g: 0, r: 255, type: "rgb" },
468+
},
469+
]);
464470
});
465471

466472
test("parse space combinator", () => {
467-
expect(parseCss(`a b { color: #ff0000 }`)).toEqual([]);
473+
expect(parseCss(`.a b { color: #ff0000 }`)).toEqual([
474+
{
475+
selector: "a b",
476+
property: "color",
477+
value: { alpha: 1, b: 0, g: 0, r: 255, type: "rgb" },
478+
},
479+
]);
480+
});
481+
482+
test("parse nested selectors as one token", () => {
483+
expect(parseCss(`a b c.d { color: #ff0000 }`)).toEqual([
484+
{
485+
selector: "a b c.d",
486+
property: "color",
487+
value: { alpha: 1, b: 0, g: 0, r: 255, type: "rgb" },
488+
},
489+
]);
468490
});
469491
});
470492

‎packages/css-data/src/parse-css.ts

+35-18
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@
161161
if (node.type === "MediaQuery" && node.children.size > 1) {
162162
invalidBreakpoint = true;
163163
}
164+
``;
164165
},
165166
});
166167
const generated = csstree.generate(this.atrule.prelude);
@@ -173,32 +174,48 @@
173174
}
174175

175176
const selectors: Selector[] = [];
177+
//console.log(csstree.generate(this.rule.prelude));
178+
176179
csstree.walk(this.rule.prelude, (node, item) => {
177180
if (node.type !== "ClassSelector" && node.type !== "TypeSelector") {
178181
return;
179182
}
180-
// We don't support nesting yet.
181-
if (
182-
(item?.prev && item.prev.data.type === "Combinator") ||
183-
(item?.next && item.next.data.type === "Combinator")
184-
) {
183+
184+
// Previous item is a combinator
185+
if (item.prev?.data.type === "Combinator") {
186+
selectors[selectors.length - 1].name += node.name;
187+
return;
188+
}
189+
190+
if (item.next?.data.type === "Combinator") {
191+
const { name } = item.next.data;
192+
// keep space as-is, but add space around other combinators
193+
selectors[selectors.length - 1].name +=
194+
name === " " ? name : ` ${name} `;
185195
return;
186196
}
187197

188-
if (item?.next && item.next.data.type === "PseudoElementSelector") {
189-
selectors.push({
190-
name: node.name,
191-
state: `::${item.next.data.name}`,
192-
});
193-
} else if (item?.next && item.next.data.type === "PseudoClassSelector") {
194-
selectors.push({
195-
name: node.name,
196-
state: `:${item.next.data.name}`,
197-
});
198+
let { name } = node;
199+
let state: string | undefined;
200+
201+
if (item.next?.data.type === "PseudoElementSelector") {
202+
state = `::${item.next.data.name}`;
203+
} else if (item.next?.data.type === "PseudoClassSelector") {
204+
state = `:${item.next.data.name}`;
205+
} else if (selectors.length !== 0) {
206+
// a.b
207+
name = `.${node.name}`;
208+
}
209+
210+
console.log(item);
211+
if (selectors.length === 0) {
212+
selectors.push({ name, state });
198213
} else {
199-
selectors.push({
200-
name: node.name,
201-
});
214+
const selector = selectors[selectors.length - 1];
215+
selector.name += name;
216+
if (state) {
217+
selector.state = (selector.state ?? "") + state;
218+
}
202219
}
203220
});
204221

0 commit comments

Comments
 (0)
Please sign in to comment.