11 | ) {
12 | res.status(200).json({ name: "John Doe" });
13 | }
14 |
--------------------------------------------------------------------------------
/apps/design-system-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easyblockshq/easyblocks/c97eaa1170131224644fd119bb61173b9c8d6e88/apps/design-system-app/public/favicon.ico
--------------------------------------------------------------------------------
/apps/design-system-app/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/design-system-app/src/InputStories.tsx:
--------------------------------------------------------------------------------
1 | import { Input, Typography } from "@easyblocks/design-system";
2 |
3 | export function InputStories() {
4 | return (
5 |
6 | Input
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/apps/design-system-app/src/MultiSelectStories.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | FormElement,
3 | MultiSelect,
4 | Input,
5 | Typography,
6 | } from "@easyblocks/design-system";
7 |
8 | export function MultiSelectStories() {
9 | return (
10 |
11 | Multiselect
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/apps/design-system-app/src/RangeSliderStories.tsx:
--------------------------------------------------------------------------------
1 | import { RangeSlider, Typography } from "@easyblocks/design-system";
2 |
3 | export function RangeSliderStories() {
4 | return (
5 |
6 | Range slider
7 |
8 |
9 |
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/apps/design-system-app/src/SelectStories.tsx:
--------------------------------------------------------------------------------
1 | import { Select, SelectItem, Typography } from "@easyblocks/design-system";
2 | import { useState } from "react";
3 |
4 | export function SelectStories() {
5 | const [value, setValue] = useState("");
6 |
7 | return (
8 |
9 | Select
10 |
11 |
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/apps/design-system-app/src/ToggleStories.tsx:
--------------------------------------------------------------------------------
1 | import { Toggle, Typography } from "@easyblocks/design-system";
2 |
3 | export function ToggleStories() {
4 | return (
5 |
6 | Toggle
7 |
8 |
9 |
10 | Forced checked
11 |
12 |
13 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/apps/design-system-app/src/TypographyStories.tsx:
--------------------------------------------------------------------------------
1 | import { Typography } from "@easyblocks/design-system";
2 |
3 | export function TypographyStories() {
4 | return (
5 |
6 | Typography
7 |
8 |
9 | Body
10 |
11 | Body 4
12 |
13 | Label
14 |
15 | Label 2
16 |
17 | Label 3
18 |
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/apps/design-system-app/styles/globals.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | padding: 0;
4 | margin: 0;
5 | }
6 |
7 | html,
8 | body {
9 | max-width: 100vw;
10 | overflow-x: hidden;
11 | }
12 |
13 | body {
14 | padding: 32px;
15 | }
16 |
17 | a {
18 | color: inherit;
19 | text-decoration: none;
20 | }
21 |
--------------------------------------------------------------------------------
/apps/design-system-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true,
17 | "baseUrl": ".",
18 | "paths": {
19 | "@/*": ["./*"]
20 | }
21 | },
22 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
23 | "exclude": ["node_modules"]
24 | }
25 |
--------------------------------------------------------------------------------
/apps/liquid-demo/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/apps/liquid-demo/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env*.local
29 |
30 | # vercel
31 | .vercel
32 |
33 | # typescript
34 | *.tsbuildinfo
35 | next-env.d.ts
36 |
--------------------------------------------------------------------------------
/apps/liquid-demo/README.md:
--------------------------------------------------------------------------------
1 | # Introduction
2 |
3 | Easyblocks Quickstart project.
4 |
--------------------------------------------------------------------------------
/apps/liquid-demo/next.config.js:
--------------------------------------------------------------------------------
1 | const path = require("node:path");
2 |
3 | /** @type {import('next').NextConfig} */
4 | const nextConfig = {
5 | webpack: (config) => {
6 | // apps/README.md#Apps and internal packages
7 | config.resolve.modules.unshift(path.resolve(__dirname, "node_modules"));
8 |
9 | return config;
10 | },
11 | };
12 |
13 | module.exports = nextConfig;
14 |
--------------------------------------------------------------------------------
/apps/liquid-demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "liquid-demo",
3 | "version": "1.0.10",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@easyblocks/core": "workspace:*",
13 | "@easyblocks/editor": "workspace:*",
14 | "@types/node": "20.4.2",
15 | "@types/react": "18.2.20",
16 | "@types/react-dom": "18.2.7",
17 | "autoprefixer": "10.4.14",
18 | "eslint": "8.45.0",
19 | "eslint-config-next": "13.4.10",
20 | "html-to-react": "^1.7.0",
21 | "liquidjs": "^10.9.3",
22 | "next": "13.4.12",
23 | "postcss": "8.4.26",
24 | "react": "18.2.0",
25 | "react-dom": "18.2.0",
26 | "tailwindcss": "3.3.3",
27 | "typescript": "5.1.6"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/apps/liquid-demo/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/apps/liquid-demo/src/app/easyblocks-editor/layout.tsx:
--------------------------------------------------------------------------------
1 | import "../globals.css";
2 |
3 | export default function RootLayout({
4 | children,
5 | }: {
6 | children: React.ReactNode;
7 | }) {
8 | return (
9 |
10 | {children}
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/apps/liquid-demo/src/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easyblockshq/easyblocks/c97eaa1170131224644fd119bb61173b9c8d6e88/apps/liquid-demo/src/app/favicon.ico
--------------------------------------------------------------------------------
/apps/liquid-demo/src/app/globals.css:
--------------------------------------------------------------------------------
1 | body {
2 | -webkit-font-smoothing: antialiased;
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
--------------------------------------------------------------------------------
/apps/liquid-demo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "bundler",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true,
17 | "plugins": [
18 | {
19 | "name": "next"
20 | }
21 | ],
22 | "paths": {
23 | "@/*": ["./src/*"]
24 | }
25 | },
26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
27 | "exclude": ["node_modules"]
28 | }
29 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env*.local
29 |
30 | # vercel
31 | .vercel
32 |
33 | # typescript
34 | *.tsbuildinfo
35 | next-env.d.ts
36 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/README.md:
--------------------------------------------------------------------------------
1 | # Easyblocks Page Builder Example
2 |
3 | This repository serves as an example of how you can use Easyblocks to create a page builder.
4 |
5 | ## Installation
6 |
7 | `npm install`
8 |
9 | ## Add an access token
10 |
11 | Easyblocks editor requires an external service for saving, updating and versioning of your documents and templates. In order to play around with this demo we recommend using our simple and free cloud service. You'll be able to provide your custom one later (read [here](https://docs.easyblocks.io/essentials/backend) for more info).
12 |
13 | 1. Go to [https://app.easyblocks.io](https://app.easyblocks.io) and create a free account.
14 | 2. Go to "Playground project"
15 | 3. Copy acccess token
16 | 4. Create `.env.local` file and assign the acquired token to `NEXT_PUBLIC_EASYBLOCKS_ACCESS_TOKEN` environment variable.
17 |
18 | ## Run
19 |
20 | `npm run dev`
21 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/next.config.js:
--------------------------------------------------------------------------------
1 | const path = require("node:path");
2 |
3 | /** @type {import('next').NextConfig} */
4 | const nextConfig = {
5 | webpack: (config) => {
6 | // apps/README.md#Apps and internal packages
7 | config.resolve.modules.unshift(path.resolve(__dirname, "node_modules"));
8 |
9 | return config;
10 | },
11 | transpilePackages: ["@easyblocks/utils"],
12 | };
13 |
14 | module.exports = nextConfig;
15 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/(system)/layout.tsx:
--------------------------------------------------------------------------------
1 | import "../globals.css";
2 | import type { Metadata } from "next";
3 | import { Inter } from "next/font/google";
4 |
5 | const inter = Inter({ subsets: ["latin"] });
6 |
7 | export const metadata: Metadata = {
8 | title: "Easyblocks demo",
9 | description: "Easyblocks demo",
10 | };
11 |
12 | export default function RootLayout({
13 | children,
14 | }: {
15 | children: React.ReactNode;
16 | }) {
17 | return (
18 |
19 | {children}
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/(system)/not-found.tsx:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 |
3 | export default function NotFound() {
4 | return (
5 |
6 |
Could not find requested resource
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/(system)/page/[documentId]/EasyblocksContent.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { Easyblocks, easyblocksGetStyleTag } from "@easyblocks/core";
3 | import { useServerInsertedHTML } from "next/navigation";
4 | import { ComponentPropsWithoutRef } from "react";
5 |
6 | function EasyblocksContent({
7 | renderableDocument,
8 | externalData,
9 | components,
10 | }: ComponentPropsWithoutRef) {
11 | useServerInsertedHTML(() => {
12 | return easyblocksGetStyleTag();
13 | });
14 |
15 | return (
16 |
21 | );
22 | }
23 |
24 | export { EasyblocksContent };
25 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks-editor/layout.tsx:
--------------------------------------------------------------------------------
1 | import "../globals.css";
2 |
3 | export default function RootLayout({
4 | children,
5 | }: {
6 | children: React.ReactNode;
7 | }) {
8 | return (
9 |
10 |
11 | {children}
12 |
13 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/AlertAction/AlertAction.definition.ts:
--------------------------------------------------------------------------------
1 | import { NoCodeComponentDefinition } from "@easyblocks/core";
2 |
3 | export const alertActionDefinition: NoCodeComponentDefinition = {
4 | id: "AlertAction",
5 | label: "Alert (demo)",
6 | type: "action",
7 | thumbnail:
8 | "https://shopstory.s3.eu-central-1.amazonaws.com/picker_icon_action.png",
9 | schema: [
10 | {
11 | prop: "text",
12 | type: "string",
13 | defaultValue: "Lorem ipsum",
14 | },
15 | ],
16 | };
17 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/AlertAction/AlertAction.tsx:
--------------------------------------------------------------------------------
1 | export const AlertAction = (props: any) => {
2 | const { text, trigger: TriggerElement } = props;
3 |
4 | return (
5 | {
9 | alert(text);
10 | }}
11 | />
12 | );
13 | };
14 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/BannerCard/BannerCard.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | export function BannerCard(props: any) {
4 | const {
5 | Container,
6 | Root,
7 | Stack,
8 | StackContainer,
9 | StackInnerContainer,
10 | CoverContainer,
11 | CoverCard,
12 | } = props;
13 |
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/BannerCard/CoverCard/CoverCard.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | export function CoverCard(props: any) {
4 | const { Root, Background, Overlay } = props;
5 |
6 | return (
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/ButtonGroup/ButtonGroup.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactElement } from "react";
2 |
3 | function ButtonGroup(props: {
4 | ButtonsContainer: ReactElement;
5 | Buttons: Array;
6 | }) {
7 | const { ButtonsContainer, Buttons } = props;
8 |
9 | return (
10 |
11 | {Buttons.map((Button, index) => (
12 |
13 | ))}
14 |
15 | );
16 | }
17 |
18 | export { ButtonGroup };
19 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/Code/Code.definition.ts:
--------------------------------------------------------------------------------
1 | import { NoCodeComponentDefinition } from "@easyblocks/core";
2 |
3 | const codeDefinition: NoCodeComponentDefinition = {
4 | id: "Code",
5 | type: "@easyblocks/text-wrapper",
6 | schema: [],
7 | styles() {
8 | return {
9 | styled: {
10 | Wrapper: {
11 | __as: "span",
12 | padding: "0.1em 0.3em",
13 | background: "rgba(135,131,120,0.15)",
14 | borderRadius: 3,
15 | color: "#EB5757",
16 | fontFamily: "monospace",
17 | fontSize: "0.8em",
18 | },
19 | },
20 | };
21 | },
22 | thumbnail:
23 | "https://shopstory.s3.eu-central-1.amazonaws.com/picker_icon_text.png",
24 | };
25 |
26 | export { codeDefinition };
27 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/Code/Code.tsx:
--------------------------------------------------------------------------------
1 | import { NoCodeComponentProps } from "@easyblocks/core";
2 |
3 | function Code({
4 | children,
5 | Wrapper,
6 | }: NoCodeComponentProps & Record) {
7 | return {children};
8 | }
9 |
10 | export { Code };
11 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/Image/ImageRenderer.tsx:
--------------------------------------------------------------------------------
1 | import { ImageSrc } from "../../externalData/types";
2 | import { Placeholder } from "./Placeholder";
3 |
4 | type ImageRendererProps = {
5 | image: ImageSrc | undefined;
6 | };
7 |
8 | function ImageRenderer({ image }: ImageRendererProps) {
9 | if (!image) {
10 | return ;
11 | }
12 |
13 | const { srcset, alt } = image;
14 |
15 | return (
16 |
27 | );
28 | }
29 |
30 | export { ImageRenderer };
31 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/Link/Link.definition.ts:
--------------------------------------------------------------------------------
1 | import { NoCodeComponentDefinition } from "@easyblocks/core";
2 |
3 | /**
4 | * ProductCard is just for the demo purpose, it's not really styleable
5 | * It's only to show how external data can be connected to component
6 | */
7 | export const linkDefinition: NoCodeComponentDefinition = {
8 | id: "Link",
9 | label: "Link",
10 | type: "action",
11 | thumbnail:
12 | "https://shopstory.s3.eu-central-1.amazonaws.com/picker_icon_link.png",
13 | schema: [
14 | {
15 | prop: "url",
16 | type: "url",
17 | },
18 | {
19 | prop: "shouldOpenInNewWindow",
20 | label: "Open in new window?",
21 | type: "boolean",
22 | defaultValue: true,
23 | },
24 | ],
25 | };
26 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/Link/Link.tsx:
--------------------------------------------------------------------------------
1 | export const Link = (props: any) => {
2 | const { url, shouldOpenInNewWindow, trigger: TriggerElement } = props;
3 |
4 | return (
5 |
11 | );
12 | };
13 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/RootSectionStack/RootSectionStack.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment, ReactElement } from "react";
2 |
3 | export function RootSectionStack(props: {
4 | data: Array;
5 | ItemWrappers: Array;
6 | }) {
7 | const { data, ItemWrappers: itemWrappers } = props;
8 |
9 | return (
10 |
11 | {data.map((Item, index) => {
12 | const ItemWrapper = itemWrappers[index];
13 |
14 | return (
15 |
16 |
17 |
18 | );
19 | })}
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/SimpleBanner/SimpleBanner.tsx:
--------------------------------------------------------------------------------
1 | import { ReactElement } from "react";
2 |
3 | type SimpleBannerProps = {
4 | Root: ReactElement;
5 | Title: ReactElement;
6 | Wrapper: ReactElement;
7 | Buttons: ReactElement[];
8 | ButtonsWrapper: ReactElement;
9 | };
10 |
11 | export function SimpleBanner(props: SimpleBannerProps) {
12 | const { Root, Title, Wrapper, Buttons, ButtonsWrapper } = props;
13 |
14 | return (
15 |
16 |
17 |
18 |
19 | {Buttons.map((Button, index) => (
20 |
21 | ))}
22 |
23 |
24 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/SolidColor/SolidColor.definition.ts:
--------------------------------------------------------------------------------
1 | import { NoCodeComponentDefinition, TokenValue } from "@easyblocks/core";
2 | import { solidColorStyles } from "./SolidColor.styles";
3 |
4 | const solidColorComponentDefinition: NoCodeComponentDefinition = {
5 | id: "SolidColor",
6 | label: "Solid color",
7 | styles: solidColorStyles,
8 | thumbnail:
9 | "https://shopstory.s3.eu-central-1.amazonaws.com/picker_solid_color.png",
10 | schema: [
11 | {
12 | prop: "color",
13 | label: "Color",
14 | type: "color",
15 | },
16 | ],
17 | preview({ values }) {
18 | const colorValue = values.color as TokenValue;
19 |
20 | return {
21 | thumbnail: {
22 | type: "color",
23 | color: colorValue.value,
24 | },
25 | description: colorValue.tokenId ?? colorValue.value,
26 | };
27 | },
28 | };
29 |
30 | export { solidColorComponentDefinition };
31 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/SolidColor/SolidColor.styles.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | NoCodeComponentStylesFunctionInput,
3 | NoCodeComponentStylesFunctionResult,
4 | } from "@easyblocks/core";
5 |
6 | export function solidColorStyles({
7 | values,
8 | }: NoCodeComponentStylesFunctionInput): NoCodeComponentStylesFunctionResult {
9 | return {
10 | styled: {
11 | Root: {
12 | position: "relative",
13 | backgroundColor: values.color,
14 | },
15 | },
16 | };
17 | }
18 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/SolidColor/SolidColor.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactElement } from "react";
2 |
3 | function SolidColor(props: { Root: ReactElement }) {
4 | const { Root } = props;
5 | return ;
6 | }
7 |
8 | export { SolidColor };
9 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/Stack/Stack.types.ts:
--------------------------------------------------------------------------------
1 | import { Spacing } from "@easyblocks/core";
2 |
3 | export type StackCompiledValues = {
4 | Items: Array<{
5 | _component: string;
6 | width: string;
7 | marginBottom: Spacing;
8 | align: string;
9 | }>;
10 | };
11 |
12 | export type StackParams = {
13 | paddingLeft?: Spacing;
14 | paddingRight?: Spacing;
15 | paddingTop?: Spacing;
16 | paddingBottom?: Spacing;
17 | passedAlign?: string;
18 | };
19 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/TextLink/TextLink.tsx:
--------------------------------------------------------------------------------
1 | import { NoCodeComponentProps } from "@easyblocks/core";
2 |
3 | function TextLink({
4 | Link,
5 | url,
6 | shouldOpenInNewWindow,
7 | children,
8 | __easyblocks,
9 | }: NoCodeComponentProps & Record) {
10 | return (
11 |
19 | {children}
20 |
21 | );
22 | }
23 |
24 | export { TextLink };
25 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/TwoCards/TwoCards.types.ts:
--------------------------------------------------------------------------------
1 | import { Spacing } from "@easyblocks/core";
2 |
3 | export type TwoCardsCompiledValues = {
4 | Card1: any[];
5 | Card2: any[];
6 | card1Width: string;
7 | card2Width: string;
8 | card1EscapeMargin: boolean;
9 | card2EscapeMargin: boolean;
10 | verticalLayout: string;
11 | verticalOffset: string;
12 | collapse: boolean;
13 | verticalGap: Spacing;
14 | gap: Spacing;
15 | invertCollapsed: boolean;
16 | };
17 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/TwoCards/twoCardsConstants.ts:
--------------------------------------------------------------------------------
1 | export const TWO_CARDS_COL_NUM = 24;
2 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/VimeoPlayer/VimeoPlayer.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactElement } from "react";
2 | import { VimeoPlayerInternal } from "./VimeoPlayerInternal";
3 |
4 | export function VimeoPlayer(props: {
5 | AspectRatioMaker: ReactElement;
6 | ContentWrapper: ReactElement;
7 | Wrapper: ReactElement;
8 | }) {
9 | const { AspectRatioMaker, ContentWrapper, Wrapper } = props;
10 |
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/utils/corners.ts:
--------------------------------------------------------------------------------
1 | import { pxValueNormalize } from "@/app/easyblocks/components/utils/pxValueNormalize";
2 | import { SchemaProp } from "@easyblocks/core";
3 |
4 | export const cornerSchemaProps: SchemaProp[] = [
5 | {
6 | prop: "cornerRadius",
7 | label: "Radius",
8 | group: "Corner",
9 | type: "string",
10 | responsive: true,
11 | params: {
12 | normalize: pxValueNormalize(0, 32),
13 | },
14 | defaultValue: "0",
15 | },
16 | ];
17 |
18 | export function cornerStyles(
19 | values: Record,
20 | disable: boolean = false
21 | ) {
22 | return {
23 | borderRadius: disable ? "initial" : `${values.cornerRadius}px`,
24 | };
25 | }
26 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/utils/getFieldProvider.ts:
--------------------------------------------------------------------------------
1 | import { EditingInfo } from "@easyblocks/core";
2 |
3 | export const getFieldProvider = (editingInfo: EditingInfo) => (path: string) =>
4 | editingInfo.fields.find((field) => field.path === path)!;
5 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/utils/parseAspectRatio.ts:
--------------------------------------------------------------------------------
1 | function parseAspectRatio(aspectRatio: string): number {
2 | const error = new Error(`wrong input to parseAspectRatio: ${aspectRatio}`);
3 |
4 | const split = aspectRatio.split(":");
5 | const val1 = parseInt(split[0]);
6 | const val2 = parseInt(split[1]);
7 |
8 | if (isNaN(val1) || isNaN(val2)) {
9 | throw error;
10 | }
11 |
12 | const result = val2 / val1;
13 |
14 | if (isNaN(result)) {
15 | throw error;
16 | }
17 |
18 | return result;
19 | }
20 |
21 | export function getPaddingBottomFromAspectRatio(aspectRatio: string) {
22 | return `${parseAspectRatio(aspectRatio) * 100}%`;
23 | }
24 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/utils/pxValueNormalize.ts:
--------------------------------------------------------------------------------
1 | export function pxValueNormalize(from: number, to: number) {
2 | return (x: string) => {
3 | const num = parseInt(x);
4 | if (isNaN(num)) {
5 | return null;
6 | }
7 |
8 | if (num < from || num > to) {
9 | return null;
10 | }
11 |
12 | return num.toString();
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/components/utils/toStartEnd.ts:
--------------------------------------------------------------------------------
1 | export function toStartEnd(
2 | position: "left" | "center" | "right" | "top" | "bottom"
3 | ) {
4 | if (position === "left" || position === "top") {
5 | return "start";
6 | } else if (position === "center") {
7 | return "center";
8 | } else if (position === "right" || position === "bottom") {
9 | return "end";
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/externalData/mockMedia/Media.ts:
--------------------------------------------------------------------------------
1 | export type Media = {
2 | id: string;
3 | title: string;
4 | url: string;
5 | mimeType: string;
6 | isVideo: boolean;
7 | thumbnail?: string;
8 | width?: number;
9 | height?: number;
10 | };
11 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/externalData/mockMedia/MockImagePicker.tsx:
--------------------------------------------------------------------------------
1 | import type { WidgetComponentProps } from "@easyblocks/core";
2 | import { MediaPicker } from "./MediaPicker";
3 |
4 | export function MockImagePicker({
5 | id,
6 | onChange,
7 | }: WidgetComponentProps) {
8 | return ;
9 | }
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/externalData/mockMedia/MockVideoPicker.tsx:
--------------------------------------------------------------------------------
1 | import type { WidgetComponentProps } from "@easyblocks/core";
2 | import { MediaPicker } from "./MediaPicker";
3 |
4 | export function MockVideoPicker({
5 | id,
6 | onChange,
7 | }: WidgetComponentProps) {
8 | return ;
9 | }
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/externalData/mockMedia/mockImageWidget.tsx:
--------------------------------------------------------------------------------
1 | import type { Widget } from "@easyblocks/core";
2 |
3 | export const mockImageWidget: Widget = {
4 | id: "mockImage",
5 | label: "Library",
6 | };
7 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/externalData/mockMedia/mockVideoWidget.tsx:
--------------------------------------------------------------------------------
1 | import type { Widget } from "@easyblocks/core";
2 |
3 | export const mockVideoWidget: Widget = {
4 | id: "mockVideo",
5 | label: "Library",
6 | };
7 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/externalData/pexels/pexelsShared.ts:
--------------------------------------------------------------------------------
1 | export const PEXELS_VIDEO_WIDGET_ID = "@pexels/video";
2 | export const PEXELS_IMAGE_WIDGET_ID = "@pexels/photo";
3 |
4 | const pexelsApiKey = "us4Cvb33zDTkpH0RqYmuSgzyx0Nnc4qwDkIMkDMOuCw5giL06WmSONgY";
5 |
6 | export const pexelsApiFetch: (path: `/${string}`) => Promise = async (
7 | path
8 | ) => {
9 | return fetch(`https://api.pexels.com${path}`, {
10 | headers: {
11 | Authorization: pexelsApiKey,
12 | },
13 | });
14 | };
15 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/externalData/product/productShared.ts:
--------------------------------------------------------------------------------
1 | export const PRODUCT_WIDGET_ID = "product";
2 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/externalData/types.ts:
--------------------------------------------------------------------------------
1 | type ImageSrcSetEntry = {
2 | w: number;
3 | h: number;
4 | url: string;
5 | };
6 |
7 | export type ImageSrc = {
8 | alt: string;
9 | url: string;
10 | aspectRatio: number;
11 | srcset: ImageSrcSetEntry[];
12 | mimeType: string;
13 | };
14 |
15 | export type VideoSrc = {
16 | alt: string;
17 | url: string;
18 | aspectRatio: number;
19 | };
20 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/basic/BasicCard_empty.json:
--------------------------------------------------------------------------------
1 | {
2 | "_id": "2daa681f-f8d8-49ec-abdf-7e4807a7ac07",
3 | "_component": "BannerCard"
4 | }
5 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/BannerSection1/NoomaBannerSection1.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaBannerSection1Entry.json";
3 |
4 | export const NoomaBannerSection1: Template = {
5 | id: "BannerSection1",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/2lBJl4UUaSkpiadI6vOT7b/82f09dd9b1d700ff4f2e43c89f31f74b/Screenshot_2023-10-16_at_12.24.20.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/BannerSection2/NoomaBannerSection2.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaBannerSection2Entry.json";
3 |
4 | export const NoomaBannerSection2: Template = {
5 | id: "BannerSection2",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/7E9ZU6yqFUj8EgTz0zXqtf/93558c209d1f087f7b29a9795c53aea7/Screenshot_2023-10-16_at_13.22.35.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/BannerSection3/NoomaBannerSection3.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaBannerSection3Entry.json";
3 |
4 | export const NoomaBannerSection3: Template = {
5 | id: "BannerSection3",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/7GjSPRpFYrh2wvCeBSSg3Z/9f11e67bfb7b4dae813f85cc377ee8c8/Screenshot_2023-10-16_at_13.37.45.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/BannerSection4/NoomaBannerSection4.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaBannerSection4Entry.json";
3 |
4 | export const NoomaBannerSection4: Template = {
5 | id: "BannerSection4",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/6W4fwr5kLP90HbywlGTguE/f8ab0051f16ae8e3ac26ee771eafab1f/Screenshot_2023-10-16_at_15.26.32.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/BannerSection5/NoomaBannerSection5.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaBannerSection5Entry.json";
3 |
4 | export const NoomaBannerSection5: Template = {
5 | id: "BannerSection5",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/15nwuZM92JbQQywMCZV7VP/28683a534c5b935c689d8b4b527fe88b/Screenshot_2023-10-16_at_15.56.45.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/BasicCard1/NoomaBasicCard1.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaBasicCard1Entry.json";
3 |
4 | export const NoomaBasicCard1: Template = {
5 | id: "BasicCard1",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/3IFi8EhTHyZ4syRflhzpO/3964969a54a78d02b3075a07e0f4ebfe/Screenshot_2023-10-16_at_16.09.23.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/BasicCard2/NoomaBasicCard2.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaBasicCard2Entry.json";
3 |
4 | export const NoomaBasicCard2: Template = {
5 | id: "BasicCard2",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/4TKdp7GmUp7gOYPVKDR7Zj/c96e32d829798cf882b43199dc829c36/Screenshot_2023-10-16_at_16.13.57.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/BasicCard3/NoomaBasicCard3.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaBasicCard3Entry.json";
3 |
4 | export const NoomaBasicCard3: Template = {
5 | id: "BasicCard3",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/KpMpJxM64cBObZinCU5Of/61c787895bb51c3fa006a59cc12838ab/Screenshot_2023-10-16_at_16.17.47.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/BasicCard4/NoomaBasicCard4.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaBasicCard4Entry.json";
3 |
4 | export const NoomaBasicCard4: Template = {
5 | id: "BasicCard4",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/1iXsqbwod4yP2Ftw7E384f/ba37ec0536ee72d02f697b9fa91c84f0/Screenshot_2023-10-16_at_16.20.24.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/BasicCard5/NoomaBasicCard5.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaBasicCard5Entry.json";
3 |
4 | export const NoomaBasicCard5: Template = {
5 | id: "BasicCard5",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/aDSFdqEz6mIpxnrD4WD3G/5eafe264cad75f441b4721a1d6e42e56/Screenshot_2023-10-16_at_16.22.27.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/Grid1/NoomaGrid1.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaGrid1Entry.json";
3 |
4 | export const NoomaGrid1: Template = {
5 | id: "Grid1",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/4dsSRhhr5udchcZhEQ3Atr/b3918636d0ccf2091f35bbf252d17d2a/Screenshot_2023-10-16_at_14.53.42.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/Grid2/NoomaGrid2.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaGrid2Entry.json";
3 |
4 | export const NoomaGrid2: Template = {
5 | id: "Grid2",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/7EGShDCsJIzKF8VKAP5uR2/dcdab83b4dfd59c059c36a5c994e3ebe/Screenshot_2023-10-16_at_14.59.47.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/Grid3/NoomaGrid3.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaGrid3Entry.json";
3 |
4 | export const NoomaGrid3: Template = {
5 | id: "Grid3",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/1S3OvGb58O3yid9EGYxF6X/34f7a93b2adce5125ddf96a994efe5d7/Screenshot_2023-10-16_at_15.06.26.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/Grid4/NoomaGrid4.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaGrid4Entry.json";
3 |
4 | export const NoomaGrid4: Template = {
5 | id: "Grid4",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/2Cf0Od05keCKatpBXPZwHB/de03290cf7b22ae19a8e7cd642468faa/Screenshot_2023-10-16_at_15.11.11.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/Grid5/NoomaGrid5.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaGrid5Entry.json";
3 |
4 | export const NoomaGrid5: Template = {
5 | id: "Grid5",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/1ICEg2xesO0vZhIs21aQYI/49b3d52dcc5d5d95f16ce43bf164a8e1/Screenshot_2023-10-16_at_15.16.41.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/ProductCard1/NoomaProductCard1.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaProductCard1Entry.json";
3 |
4 | export const NoomaProductCard1: Template = {
5 | id: "ProductCard1",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/3gZE2gBjMmDppU9h0DISSp/62501a914805d235a364594c87c6845c/Screenshot_2023-10-16_at_16.05.26.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/ProductCard1/NoomaProductCard1Entry.json:
--------------------------------------------------------------------------------
1 | {
2 | "_id": "d72cebfd-ed3d-41a2-837f-3ec84c551d96",
3 | "_component": "ProductCard",
4 | "_itemProps": {
5 | "Grid": {
6 | "Cards": {
7 | "itemSize": {
8 | "$res": true,
9 | "xl": "1x1"
10 | },
11 | "verticalAlign": {
12 | "$res": true,
13 | "xl": "auto"
14 | }
15 | }
16 | }
17 | },
18 | "product": {
19 | "id": "gid://shopify/Product/7620416209108",
20 | "widgetId": "product",
21 | "key": "self"
22 | },
23 | "relatedProductsMode": "enabled",
24 | "withBackdrop": false
25 | }
26 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/Slider1/NoomaSlider1.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaSlider1Entry.json";
3 |
4 | export const NoomaSlider1: Template = {
5 | id: "Slider1",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/7puLkIVcgW4P7IIzwtdgv6/dfe2b76e28a5d4f1c2ade3ad04db709b/Screenshot_2023-10-16_at_15.20.26.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/Slider2/NoomaSlider2.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaSlider2Entry.json";
3 |
4 | export const NoomaSlider2: Template = {
5 | id: "Slider2",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/5UVmxfm7Fa7RGT09UIy5PP/4745a56f0bced3c3273a05a61a4dbefc/Screenshot_2023-10-16_at_15.22.51.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/TwoCards1/NoomaTwoCards1.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaTwoCards1Entry.json";
3 |
4 | export const NoomaTwoCards1: Template = {
5 | id: "TwoCards1",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/4MuzwPC1hqG9PgskCQNDsd/edb32f846dff36f1dc2f7fef0b3cfdc5/Screenshot_2023-10-16_at_13.45.44.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/TwoCards2/NoomaTwoCards2.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaTwoCards2Entry.json";
3 |
4 | export const NoomaTwoCards2: Template = {
5 | id: "TwoCards2",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/R2iiiCxFtsGsAvS81Oc1v/08a51a26c1d34d917157b59785c964d7/Screenshot_2023-10-16_at_14.01.33.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/TwoCards3/NoomaTwoCards3.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaTwoCards3Entry.json";
3 |
4 | export const NoomaTwoCards3: Template = {
5 | id: "TwoCards3",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/3TjTIsNy3aMEu7LG1KNK03/025242f17c066ccbe7949eeff0776e60/Screenshot_2023-10-16_at_14.11.06.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/templates/nooma/TwoCards4/NoomaTwoCards4.ts:
--------------------------------------------------------------------------------
1 | import { Template } from "@easyblocks/core";
2 | import entry from "./NoomaTwoCards4Entry.json";
3 |
4 | export const NoomaTwoCards4: Template = {
5 | id: "TwoCards4",
6 | entry: entry,
7 | thumbnail:
8 | "https://images.ctfassets.net/blh4anz05qu1/4arNLu2JXthVNUHvTIGVLt/eff0131168a9cdf4d8e9749c9c83a170/Screenshot_2023-10-16_at_14.19.24.png",
9 | };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/types/UrlWidget.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { InlineTypeWidgetComponentProps } from "@easyblocks/core";
3 | import { Input } from "@easyblocks/design-system";
4 | import { useState } from "react";
5 |
6 | function UrlWidget(props: InlineTypeWidgetComponentProps) {
7 | const [active, setActive] = useState(false);
8 | const [value, setValue] = useState(props.value);
9 |
10 | useEffect(() => {
11 | if (!active) {
12 | setValue(props.value);
13 | }
14 | });
15 |
16 | return (
17 | {
20 | setActive(true);
21 | setValue(event.target.value);
22 | }}
23 | onBlur={() => {
24 | setActive(false);
25 | props.onChange(value);
26 | }}
27 | align={"right"}
28 | />
29 | );
30 | }
31 |
32 | export { UrlWidget };
33 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/utils/assert.ts:
--------------------------------------------------------------------------------
1 | function assertDefined(value: T, message?: string): Exclude {
2 | if (value === undefined) {
3 | throw new Error(message ?? "Value is undefined");
4 | }
5 |
6 | return value as Exclude;
7 | }
8 |
9 | function assertNonNullable(value: T): Exclude {
10 | if (value === null) {
11 | throw new Error("Value is null");
12 | }
13 |
14 | return value as Exclude;
15 | }
16 |
17 | export { assertDefined, assertNonNullable };
18 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/utils/deepClone.ts:
--------------------------------------------------------------------------------
1 | function deepClone(source: T): T {
2 | return JSON.parse(JSON.stringify(source)) as T;
3 | }
4 |
5 | export { deepClone };
6 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/utils/last.ts:
--------------------------------------------------------------------------------
1 | function last>(collection: T): T[number] {
2 | return collection[collection.length - 1];
3 | }
4 |
5 | export { last };
6 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/utils/range.ts:
--------------------------------------------------------------------------------
1 | function range(start: number, end: number): Array {
2 | const itemsCount = start === end ? 1 : end - start + 1;
3 |
4 | return Array.from({ length: itemsCount }, (_, index) => {
5 | return start + index;
6 | });
7 | }
8 |
9 | export { range };
10 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/easyblocks/utils/useForceRerender.ts:
--------------------------------------------------------------------------------
1 | "use client";
2 | import { useRef, useState } from "react";
3 |
4 | function useForceRerender() {
5 | const [, setDummyState] = useState({});
6 |
7 | const forceRerender = useRef(() => {
8 | setDummyState({});
9 | }).current;
10 |
11 | return { forceRerender };
12 | }
13 |
14 | export { useForceRerender };
15 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easyblockshq/easyblocks/c97eaa1170131224644fd119bb61173b9c8d6e88/apps/page-builder-demo/src/app/favicon.ico
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/fonts/test-national-2-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easyblockshq/easyblocks/c97eaa1170131224644fd119bb61173b9c8d6e88/apps/page-builder-demo/src/app/fonts/test-national-2-bold.woff2
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/fonts/test-national-2-medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easyblockshq/easyblocks/c97eaa1170131224644fd119bb61173b9c8d6e88/apps/page-builder-demo/src/app/fonts/test-national-2-medium.woff2
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/fonts/test-national-2-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easyblockshq/easyblocks/c97eaa1170131224644fd119bb61173b9c8d6e88/apps/page-builder-demo/src/app/fonts/test-national-2-regular.woff2
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/fonts/test-soehne-mono-leicht.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/easyblockshq/easyblocks/c97eaa1170131224644fd119bb61173b9c8d6e88/apps/page-builder-demo/src/app/fonts/test-soehne-mono-leicht.woff2
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | body {
6 | -webkit-font-smoothing: antialiased;
7 | font-family: "Inter", sans-serif;
8 | }
9 |
10 | @font-face {
11 | font-family: "test-national-2";
12 | src: url("fonts/test-national-2-regular.woff2") format("woff2");
13 | font-display: block;
14 | font-weight: 400;
15 | }
16 |
17 | @font-face {
18 | font-family: "test-national-2";
19 | src: url("fonts/test-national-2-medium.woff2") format("woff2");
20 | font-display: block;
21 | font-weight: 600;
22 | }
23 |
24 | @font-face {
25 | font-family: "test-national-2";
26 | src: url("fonts/test-national-2-bold.woff2") format("woff2");
27 | font-display: block;
28 | font-weight: 700;
29 | }
30 |
31 | @font-face {
32 | font-family: "test-soehne-mono";
33 | src: url("fonts/test-soehne-mono-leicht.woff2") format("woff2");
34 | font-display: block;
35 | }
36 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/data/shopify/fetchProductById.ts:
--------------------------------------------------------------------------------
1 | import { fetchProductsByIds } from "./fetchProductsByIds";
2 |
3 | export async function fetchProductById(id: string) {
4 | return (await fetchProductsByIds([id]))[0];
5 | }
6 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/data/shopify/fetchProducts.ts:
--------------------------------------------------------------------------------
1 | import { mapProduct } from "./mapProduct";
2 | import { removeEdges } from "./removeEdges";
3 | import fetchShopify from "./fetchShopify";
4 | import { fetchProductsQuery } from "./graphql/fetchProductsQuery";
5 |
6 | const fetchProducts = async (query: string) => {
7 | const data: any = await fetchShopify(fetchProductsQuery, {
8 | query,
9 | sortKey: "CREATED_AT",
10 | sortIndex: 0,
11 | reverse: false,
12 | first: 250,
13 | });
14 |
15 | return removeEdges(data.products).map(mapProduct);
16 | };
17 |
18 | export { fetchProducts };
19 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/data/shopify/fetchShopify.ts:
--------------------------------------------------------------------------------
1 | import { GraphQLClient } from "graphql-request";
2 |
3 | const client = new GraphQLClient(
4 | "https://shopstory-demo.myshopify.com/api/2022-01/graphql.json",
5 | {
6 | headers: {
7 | "Content-Type": "application/json",
8 | "X-Shopify-Storefront-Access-Token": "f8b32eaae0d2dc7996bfc02f2dc33b56",
9 | },
10 | }
11 | );
12 |
13 | async function fetchShopify(query: string, variables: any) {
14 | try {
15 | const data = await client.request(query, variables);
16 | return data;
17 | } catch (error: any) {
18 | throw new Error(error);
19 | }
20 | }
21 |
22 | export default fetchShopify;
23 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/data/shopify/formatPrice.ts:
--------------------------------------------------------------------------------
1 | import { ShopifyPrice } from "./types";
2 |
3 | export const formatPrice = (price: ShopifyPrice) => {
4 | let _amount = price.amount.replace(".0", ".00");
5 |
6 | if (price.currencyCode === "USD") {
7 | return `$${_amount}`;
8 | }
9 |
10 | if (price.currencyCode === "EUR") {
11 | return `€${_amount}`;
12 | }
13 |
14 | if (price.currencyCode === "PLN") {
15 | return `${_amount}zł`;
16 | }
17 |
18 | if (price.currencyCode === "GBP") {
19 | return `£${_amount}`;
20 | }
21 |
22 | return `${price.currencyCode}${_amount}`;
23 | };
24 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/data/shopify/graphql/fetchProductsByIds.ts:
--------------------------------------------------------------------------------
1 | import { gql } from "graphql-request";
2 | import { PRODUCT_FRAGMENT_SLIM } from "./productFragment";
3 |
4 | export const fetchProductsByIdsQuery = gql`
5 | ${PRODUCT_FRAGMENT_SLIM}
6 | query ($ids: [ID!]!) {
7 | nodes(ids: $ids) {
8 | ... on Product {
9 | ...ProductFragmentSlim
10 | }
11 | }
12 | }
13 | `;
14 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/data/shopify/graphql/fetchProductsQuery.ts:
--------------------------------------------------------------------------------
1 | import { gql } from "graphql-request";
2 | import { PRODUCTS_FRAGMENT } from "./productFragment";
3 |
4 | export const fetchProductsQuery = gql`
5 | ${PRODUCTS_FRAGMENT}
6 | query products(
7 | $cursor: String
8 | $query: String!
9 | $sortKey: ProductSortKeys!
10 | $reverse: Boolean!
11 | $first: Int!
12 | ) {
13 | products(
14 | first: $first
15 | after: $cursor
16 | query: $query
17 | sortKey: $sortKey
18 | reverse: $reverse
19 | ) {
20 | ...ProductsFragment
21 | }
22 | }
23 | `;
24 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/data/shopify/graphql/variantFragment.ts:
--------------------------------------------------------------------------------
1 | import { gql } from "graphql-request";
2 |
3 | export const VariantFragment = gql`
4 | fragment VariantFragment on ProductVariant {
5 | availableForSale
6 | id
7 | title
8 | quantityAvailable
9 | currentlyNotInStock
10 | selectedOptions {
11 | name
12 | value
13 | }
14 | priceV2 {
15 | amount
16 | currencyCode
17 | }
18 | compareAtPriceV2 {
19 | amount
20 | currencyCode
21 | }
22 | product {
23 | id
24 | }
25 | sku
26 | }
27 | `;
28 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/data/shopify/index.ts:
--------------------------------------------------------------------------------
1 | import { fetchProductsByIds } from "./fetchProductsByIds";
2 | import { fetchProducts } from "./fetchProducts";
3 | import { fetchProductById } from "./fetchProductById";
4 | import type { ShopifyProduct } from "./types";
5 |
6 | export { fetchProducts, fetchProductsByIds, fetchProductById };
7 | export type { ShopifyProduct };
8 |
--------------------------------------------------------------------------------
/apps/page-builder-demo/src/data/shopify/removeEdges.ts:
--------------------------------------------------------------------------------
1 | export const removeEdges = (data: {
2 | edges: [{ node: Object }];
3 | }): Array