diff --git a/templates/mantine/component/component/template.json5 b/templates/mantine/component/component/template.json5 index 2d126f75..3fc19d46 100644 --- a/templates/mantine/component/component/template.json5 +++ b/templates/mantine/component/component/template.json5 @@ -33,7 +33,8 @@ "description": "The type of the component.", "choices": [ "component", - "block" + "block", + "template" ], "required": true }, diff --git a/templates/mantine/template/marketing-page/README.md b/templates/mantine/template/marketing-page/README.md new file mode 100644 index 00000000..1eca17c5 --- /dev/null +++ b/templates/mantine/template/marketing-page/README.md @@ -0,0 +1,36 @@ +# Introduction + +This template adds the +entire Mantine marketing page template to your project. + +It comes fully integrated with Croct, giving you CMS, AB testing, and personalization out of the box. + +> [!NOTE Forever-free] +> This template is compatible with features available on the forever-free plan. + +## Usage + +To create a new project using this template, run: + +```croct-cmd +croct use mantine://template/marketing-page +``` + +You can customize the template by specifying options, like defining which sections should be integrated with Croct +slots: + +```croct-cmd +croct use mantine://template/marketing-page --slots='["hero-section","stats-section"]' +``` + +## Options + +The following options are available for this template: + +| Option | Description | Required | Default | +|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|----------------------------------------| +| `projectName` | The name of the project. | No | `my-app` | +| `version` | The Next.js version to use. | No | `latest` | +| `router` | The router to use (`app` or `page`). | No | `app` | +| `javascript` | Whether to use JavaScript instead of TypeScript. | No | `false` | +| `slots` | Tha list of slots to use (`header`, `hero-section`, `features-cards-section`, `features-title-section`, and `stats-group-section`). | No | `["hero-section", "features-cards-section"]` | diff --git a/templates/mantine/template/marketing-page/code/components/Footer/index.module.css b/templates/mantine/template/marketing-page/code/components/Footer/index.module.css new file mode 100644 index 00000000..8f7f4f05 --- /dev/null +++ b/templates/mantine/template/marketing-page/code/components/Footer/index.module.css @@ -0,0 +1,89 @@ +.footer { + margin-top: 120px; + padding-top: calc(var(--mantine-spacing-xl) * 2); + padding-bottom: calc(var(--mantine-spacing-xl) * 2); + background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6)); + border-top: 1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-5)); +} + +.logo { + max-width: 200px; + + @media (max-width: $mantine-breakpoint-sm) { + display: flex; + flex-direction: column; + align-items: center; + } +} + +.description { + margin-top: 5px; + + @media (max-width: $mantine-breakpoint-sm) { + margin-top: var(--mantine-spacing-xs); + text-align: center; + } +} + +.inner { + display: flex; + justify-content: space-between; + + @media (max-width: $mantine-breakpoint-sm) { + flex-direction: column; + align-items: center; + } +} + +.groups { + display: flex; + flex-wrap: wrap; + + @media (max-width: $mantine-breakpoint-sm) { + display: none; + } +} + +.wrapper { + width: 160px; +} + +.link { + display: block; + color: light-dark(var(--mantine-color-gray-6), var(--mantine-color-dark-1)); + font-size: var(--mantine-font-size-sm); + padding-top: 3px; + padding-bottom: 3px; + + &:hover { + text-decoration: underline; + } +} + +.title { + font-size: var(--mantine-font-size-lg); + font-weight: 500; + font-family: Outfit, var(--mantine-font-family); + margin-bottom: calc(var(--mantine-spacing-xs) / 2); + color: light-dark(var(--mantine-color-black), var(--mantine-color-white)); +} + +.afterFooter { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: var(--mantine-spacing-xl); + padding-top: var(--mantine-spacing-xl); + padding-bottom: var(--mantine-spacing-xl); + border-top: 1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-4)); + + @media (max-width: $mantine-breakpoint-sm) { + flex-direction: column; + } +} + +.social { + @media (max-width: $mantine-breakpoint-sm) { + margin-top: var(--mantine-spacing-xs); + } +} \ No newline at end of file diff --git a/templates/mantine/template/marketing-page/code/components/Footer/index.tsx b/templates/mantine/template/marketing-page/code/components/Footer/index.tsx new file mode 100644 index 00000000..88faae5f --- /dev/null +++ b/templates/mantine/template/marketing-page/code/components/Footer/index.tsx @@ -0,0 +1,90 @@ +'use client'; + +import { IconBrandInstagram, IconBrandTwitter, IconBrandYoutube } from '@tabler/icons-react'; +import { ActionIcon, Container, Group, Text } from '@mantine/core'; +import { MantineLogo } from '@mantinex/mantine-logo'; +import classes from '?/./index.module.css'; + +const data = [ + { + title: 'About', + links: [ + { label: 'Features', link: '#' }, + { label: 'Pricing', link: '#' }, + { label: 'Support', link: '#' }, + { label: 'Forums', link: '#' }, + ], + }, + { + title: 'Project', + links: [ + { label: 'Contribute', link: '#' }, + { label: 'Media assets', link: '#' }, + { label: 'Changelog', link: '#' }, + { label: 'Releases', link: '#' }, + ], + }, + { + title: 'Community', + links: [ + { label: 'Join Discord', link: '#' }, + { label: 'Follow on Twitter', link: '#' }, + { label: 'Email newsletter', link: '#' }, + { label: 'GitHub discussions', link: '#' }, + ], + }, +]; + +export function FooterLinks() { + const groups = data.map((group) => { + const links = group.links.map((link, index) => ( + + key={index} + className={classes.link} + component="a" + href={link.link} + onClick={(event) => event.preventDefault()} + > + {link.label} + + )); + + return ( +
+ {group.title} + {links} +
+ ); + }); + + return ( + + ); +} \ No newline at end of file diff --git a/templates/mantine/template/marketing-page/code/components/MarketingPage/index.module.css b/templates/mantine/template/marketing-page/code/components/MarketingPage/index.module.css new file mode 100644 index 00000000..8f7f4f05 --- /dev/null +++ b/templates/mantine/template/marketing-page/code/components/MarketingPage/index.module.css @@ -0,0 +1,89 @@ +.footer { + margin-top: 120px; + padding-top: calc(var(--mantine-spacing-xl) * 2); + padding-bottom: calc(var(--mantine-spacing-xl) * 2); + background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6)); + border-top: 1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-5)); +} + +.logo { + max-width: 200px; + + @media (max-width: $mantine-breakpoint-sm) { + display: flex; + flex-direction: column; + align-items: center; + } +} + +.description { + margin-top: 5px; + + @media (max-width: $mantine-breakpoint-sm) { + margin-top: var(--mantine-spacing-xs); + text-align: center; + } +} + +.inner { + display: flex; + justify-content: space-between; + + @media (max-width: $mantine-breakpoint-sm) { + flex-direction: column; + align-items: center; + } +} + +.groups { + display: flex; + flex-wrap: wrap; + + @media (max-width: $mantine-breakpoint-sm) { + display: none; + } +} + +.wrapper { + width: 160px; +} + +.link { + display: block; + color: light-dark(var(--mantine-color-gray-6), var(--mantine-color-dark-1)); + font-size: var(--mantine-font-size-sm); + padding-top: 3px; + padding-bottom: 3px; + + &:hover { + text-decoration: underline; + } +} + +.title { + font-size: var(--mantine-font-size-lg); + font-weight: 500; + font-family: Outfit, var(--mantine-font-family); + margin-bottom: calc(var(--mantine-spacing-xs) / 2); + color: light-dark(var(--mantine-color-black), var(--mantine-color-white)); +} + +.afterFooter { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: var(--mantine-spacing-xl); + padding-top: var(--mantine-spacing-xl); + padding-bottom: var(--mantine-spacing-xl); + border-top: 1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-4)); + + @media (max-width: $mantine-breakpoint-sm) { + flex-direction: column; + } +} + +.social { + @media (max-width: $mantine-breakpoint-sm) { + margin-top: var(--mantine-spacing-xs); + } +} \ No newline at end of file diff --git a/templates/mantine/template/marketing-page/code/components/MarketingPage/index.tsx b/templates/mantine/template/marketing-page/code/components/MarketingPage/index.tsx new file mode 100644 index 00000000..37903302 --- /dev/null +++ b/templates/mantine/template/marketing-page/code/components/MarketingPage/index.tsx @@ -0,0 +1,152 @@ +'use client'; + +import { HeaderSimple, type HeaderSimpleProps } from "?/./HeaderSimple.{js,jsx,ts,tsx}"; +import { HeroBullets, type HeroBulletsProps } from "?/./HeroBullets.{js,jsx,ts,tsx}"; +import { FeaturesCards, type FeaturesCardsProps } from "?/./FeaturesCards.{js,jsx,ts,tsx}"; +import { FeaturesTitle, type FeaturesTitleProps } from "?/./FeaturesTitle.{js,jsx,ts,tsx}"; +import { StatsGroup, type StatsGroupProps } from "?/./StatsGroup.{js,jsx,ts,tsx}"; +import { FooterLinks } from "?/./Footer.{js,jsx,ts,tsx}"; + +export type PageSectionsProps = { + header: HeaderSimpleProps, + hero: HeroBulletsProps, + featuresCards: FeaturesCardsProps, + featuresTitle: FeaturesTitleProps, + stats: StatsGroupProps, +} + +export function MarketingPage(props: PageSectionsProps) { + const sectionProps = {...defaultContent, ...props}; + + return ( +
+ + + + + + +
+ ) +} + +const defaultContent: PageSectionsProps = { + "header": { + "items": [ + { + "link": "#features", + "label": "Features" + }, + { + "link": "#pricing", + "label": "Pricing" + }, + { + "link": "#learn", + "label": "Learn" + }, + { + "link": "#community", + "label": "Community" + } + ] + }, + "hero": { + "heading": "A **modern** React components library", + "tagline": "Build fully functional accessible web applications faster than ever – Mantine includes more than 120 customizable components and hooks to cover you in any situation", + "bullets": [ + { + "title": "TypeScript based", + "description": "build type safe applications, all components and hooks export types", + }, + { + "title": "Free and open source", + "description": "all packages have MIT license, you can use Mantine in any project", + }, + { + "title": "No annoying focus ring", + "description": "focus ring will appear only when user navigates with keyboard", + } + ], + "primaryCta": { + "label": "Get started", + "link": "#" + }, + "secondaryCta": { + "label": "Source code", + "link": "#" + }, + "image": "https://cdn.croct.io/workspace/customer-assets/bac910ff-a18e-4ca5-bdd0-155139967ea4/d6e0cf03-1bd4-4f52-9f0e-fd632fc7cd47" + }, + "featuresCards": { + "preTitle": "BEST COMPANY EVER", + "title": "Integrate effortlessly with any technology stack", + "description": "Every once in a while, you’ll see a Golbat that’s missing some fangs. This happens when hunger drives it to try biting a Steel-type Pokémon.", + "features": [ + { + "icon": "gauge", + "title": "Extreme performance", + "description": "This dust is actually a powerful poison that will even make a pro wrestler sick, Regice cloaks itself with frigid air of -328 degrees Fahrenheit" + }, + { + "icon": "user", + "title": "Privacy focused", + "description": "People say it can run at the same speed as lightning striking, Its icy body is so cold, it will not melt even if it is immersed in magma" + }, + { + "icon": "cookie", + "title": "No third parties", + "description": "They’re popular, but they’re rare. Trainers who show them off recklessly may be targeted by thieves" + } + ] + }, + "featuresTitle": { + "title": "A fully featured React components library for your next project", + "description": "Build fully functional accessible web applications faster than ever – Mantine includes more than 120 customizable components and hooks to cover you in any situation", + "cta": { + "label": "Get started", + "link": "#" + }, + "features": [ + { + "icon": "receipt", + "title": "Free and open source", + "description": "All packages are published under MIT license, you can use Mantine in any project" + }, + { + "icon": "file", + "title": "TypeScript based", + "description": "Build type safe applications, all components and hooks export types" + }, + { + "icon": "cicle", + "title": "No annoying focus ring", + "description": "With new :focus-visible selector focus ring will appear only when user navigates with keyboard" + }, + { + "icon": "flame", + "title": "Flexible", + "description": "Customize colors, spacing, shadows, fonts and many other settings with global theme object" + } + ] + }, + "stats": { + "statistic": [ + { + "stats": "456,133", + "title": "Page views", + "description": "24% more than in the same month last year, 33% more that two years ago" + }, + { + "stats": "2,175", + "title": "New users", + "description": "13% less compared to last month, new user engagement up by 6%" + }, + { + "stats": "1,994", + "title": "Completed orders", + "description": "1994 orders were completed this month, 97% satisfaction rate" + } + ] + } +} \ No newline at end of file diff --git a/templates/mantine/template/marketing-page/code/page/nextjs/index.tsx b/templates/mantine/template/marketing-page/code/page/nextjs/index.tsx new file mode 100644 index 00000000..7bc6d974 --- /dev/null +++ b/templates/mantine/template/marketing-page/code/page/nextjs/index.tsx @@ -0,0 +1,51 @@ +import type { GetServerSideProps } from "next" +import { MarketingPage, type MarketingPageProps } from "?/**/*/MarketingPage.{js,jsx,ts,tsx}" +import { LinkButton } from "@croct/template-ui/react" +import { fetchContent } from "@croct/plug-next/server" + +export type PageProps = { + content: MarketingPageProps +} + +export const getServerSideProps: GetServerSideProps = async context => { + const [ + /*header*/{content: header}/*header*/, + /*hero*/{content: hero}/*hero*/, + /*featuresCards*/{content: featuresCards}/*featuresCards*/, + /*featuresTitle*/{content: featuresTitle}/*featuresTitle*/, + /*stats*/{content: stats}/*stats*/, + ] = await Promise.all([ + /*header*/fetchContent('%headerSlotId%@%headerSlotVersion%', {route: context})/*header*/, + /*hero*/fetchContent('%heroSlotId%@%heroSlotVersion%', {route: context})/*hero*/, + /*featuresCards*/fetchContent('%featuresCardsSlotId%@%featuresCardsSlotVersion%', {route: context})/*featuresCards*/, + /*featuresTitle*/fetchContent('%featuresTitleSlotId%@%featuresTitleSlotVersion%', {route: context})/*featuresTitle*/, + /*stats*/fetchContent('%statsSlotId%@%statsSlotVersion%', {route: context})/*stats*/, + ]); + + return { + props: { + content: { + /*header*/header/*header*/, + /*hero*/hero/*hero*/, + /*featuresCards*/featuresCards/*featuresCards*/, + /*featuresTitle*/featuresTitle/*featuresTitle*/, + /*stats*/stats/*stats*/, + } + } + } +} + +export default function Page({content}: PageProps) { + return ( + <> + + + + ); +} diff --git a/templates/mantine/template/marketing-page/code/page/nextjs/page.tsx b/templates/mantine/template/marketing-page/code/page/nextjs/page.tsx new file mode 100644 index 00000000..d9489652 --- /dev/null +++ b/templates/mantine/template/marketing-page/code/page/nextjs/page.tsx @@ -0,0 +1,40 @@ +import { MarketingPage } from "?/**/*/MarketingPage.{js,jsx,ts,tsx}" +import { LinkButton } from "@croct/template-ui/react" +import { fetchContent } from "@croct/plug-next/server" + +export default async function Page() { + const [ + /*header*/{content: header}/*header*/, + /*hero*/{content: hero}/*hero*/, + /*featuresCards*/{content: featuresCards}/*featuresCards*/, + /*featuresTitle*/{content: featuresTitle}/*featuresTitle*/, + /*stats*/{content: stats}/*stats*/, + ] = await Promise.all([ + /*header*/fetchContent('%headerSlotId%@%headerSlotVersion%')/*header*/, + /*hero*/fetchContent('%heroSlotId%@%heroSlotVersion%')/*hero*/, + /*featuresCards*/fetchContent('%featuresCardsSlotId%@%featuresCardsSlotVersion%')/*featuresCards*/, + /*featuresTitle*/fetchContent('%featuresTitleSlotId%@%featuresTitleSlotVersion%')/*featuresTitle*/, + /*stats*/fetchContent('%statsSlotId%@%statsSlotVersion%')/*stats*/, + ]); + + const content = { + /*header*/header/*header*/, + /*hero*/hero/*hero*/, + /*featuresCards*/featuresCards/*featuresCards*/, + /*featuresTitle*/featuresTitle/*featuresTitle*/, + /*stats*/stats/*stats*/, + }; + + return ( + <> + + + + ); +} diff --git a/templates/mantine/template/marketing-page/code/page/react/page.tsx b/templates/mantine/template/marketing-page/code/page/react/page.tsx new file mode 100644 index 00000000..985f7c5b --- /dev/null +++ b/templates/mantine/template/marketing-page/code/page/react/page.tsx @@ -0,0 +1,31 @@ +import { MarketingPage } from "?/**/*/MarketingPage.{js,jsx,ts,tsx}" +import { LinkButton } from "@croct/template-ui/react" +import { useContent } from "@croct/plug-react" +import { useColorScheme } from "@mui/material/styles"; + +export default function Page() { + const content = { + /*header*/header: useContent('%headerSlotId%@%headerSlotVersion%')/*header*/, + /*hero*/hero: useContent('%heroSlotId%@%heroSlotVersion%')/*hero*/, + /*featuresCards*/featuresCards: useContent('%featuresCardsSlotId%@%featuresCardsSlotVersion%')/*featuresCards*/, + /*featuresTitle*/featuresTitle: useContent('%featuresTitleSlotId%@%featuresTitleSlotVersion%')/*featuresTitle*/, + /*stats*/stats: useContent('%statsSlotId%@%statsSlotVersion%')/*stats*/, + } + + const theme = useColorScheme(); + + return ( + <> + + + + ); +} + diff --git a/templates/mantine/template/marketing-page/code/utils/markdown.tsx b/templates/mantine/template/marketing-page/code/utils/markdown.tsx new file mode 100644 index 00000000..8edfa92e --- /dev/null +++ b/templates/mantine/template/marketing-page/code/utils/markdown.tsx @@ -0,0 +1,28 @@ +import type {ReactNode} from "react" +import { render } from "@croct/md-lite" +import Image from "next/image" +import Typography, { type TypographyProps } from "@mui/material/Typography" +import Link, { type LinkProps } from "@mui/material/Link" + +export type MarkdownStyles = { + bold?: TypographyProps; + italic?: TypographyProps; + strike?: TypographyProps; + code?: TypographyProps; + link?: LinkProps; + paragraph?: TypographyProps; +} + +export function renderMarkdown(content: string, styles: MarkdownStyles = {}): ReactNode { + return render(content, { + fragment: node => node.children, + text: node => node.content, + bold: node => {node.children}, + italic: node => {node.children}, + strike: node => {node.children}, + code: node => {node.source}, + link: node => ({node.children}), + image: node => {node.alt}/, + paragraph: node => {node.children}, + }); +} diff --git a/templates/mantine/template/marketing-page/extension.json5 b/templates/mantine/template/marketing-page/extension.json5 new file mode 100644 index 00000000..7a1bb74c --- /dev/null +++ b/templates/mantine/template/marketing-page/extension.json5 @@ -0,0 +1,321 @@ +{ + "$schema": "https://schema.croct.com/json/v1/template.json", + "title": "Marketing page customization", + "description": "A customization template for the marketing page template.", + "options": { + "exampleDirectory": { + "type": "string", + "description": "The path to the example directory.", + "required": true + }, + "exampleFile": { + "type": "string", + "description": "The name of the example file.", + "required": true + }, + "reactExtension": { + "type": "string", + "description": "The file extension for React files.", + "required": true + }, + "codeExtension": { + "type": "string", + "description": "The file extension for the code files.", + "required": true + }, + "slots": { + "type": "array", + "description": "The list of slots to use in the page.", + "required": true + } + }, + "actions": [ + { + "name": "define", + "variables": { + "headerSlotId": "", + "headerSlotVersion": "", + "heroSlotId": "", + "heroSlotVersion": "", + "featuresCardsSlotId": "", + "featuresCardsSlotVersion": "", + "featuresTitleSlotId": "", + "featuresTitleSlotVersion": "", + "statsSlotId": "", + "statsSlotVersion": "", + "components": {}, + "slots": {}, + "fetchCalls": [] + } + }, + { + "name": "test", + "condition": "${options.slots.includes('header')}", + "then": [ + { + "name": "define", + "variables": { + "component": { + "name": "Mantine - Simple header", + "description": "The navbar section at the top of a page", + "schema": "${import('mantine://component/header-simple/configuration/header-simple-schema.json')}" + }, + "slot": { + "name": "Mantine - Simple header", + "component": "mantine-header-simple", + "content": { + "en": "${import('mantine://component/header-simple/configuration/header-simple-content.en.json')}" + } + } + } + }, + { + "name": "define", + "variables": { + "components": "${{...this.components, 'mantine-header-simple': this.component}}", + "slots": "${{...this.slots, 'mantine-home-header': this.slot}}", + "fetchCalls": "${[...this.fetchCalls, 'fetchContent(\\'%headerSlotId%@%headerSlotVersion%\\').then(({content}) => [\\'header\\', content])']}" + } + } + ] + }, + { + "name": "test", + "condition": "${options.slots.includes('hero-section')}", + "then": [ + { + "name": "define", + "variables": { + "component": { + "name": "Mantine - Hero section", + "description": "The big section featured at the top of a page with optional bullets", + "schema": "${import('mantine://block/hero-bullets/configuration/hero-section-schema.json')}" + }, + "slot": { + "name": "Mantine - Home hero", + "component": "mantine-hero-section", + "content": { + "en": "${import(''mantine://block/hero-bullets/configuration/hero-section-content.en.json')}" + } + } + } + }, + { + "name": "define", + "variables": { + "components": "${{...this.components, 'mantine-hero-section': this.component}}", + "slots": "${{...this.slots, 'mantine-home-hero': this.slot}}", + "fetchCalls": "${[...this.fetchCalls, 'fetchContent(\\'%heroSlotId%@%heroSlotVersion%\\').then(({content}) => [\\'hero\\', content])']}" + } + } + ] + }, + { + "name": "test", + "condition": "${options.slots.includes('features-cards-section')}", + "then": [ + { + "name": "define", + "variables": { + "component": { + "name": "Mantine - Features cards section", + "description": "A section of features.", + "schema": "${import('mantine://block/features-cards/configuration/features-section-schema.json')}" + }, + "slot": { + "name": "Mantine - Features cards section", + "component": "mantine-features-cards-section", + "content": { + "en": "${import('mantine://block/features-cards/configuration/features-section-content.en.json')}" + } + } + } + }, + { + "name": "define", + "variables": { + "components": "${{...this.components, 'mantine-features-cards-section': this.component}}", + "slots": "${{...this.slots, 'mantine-home-features-cards': this.slot}}", + "fetchCalls": "${[...this.fetchCalls, 'fetchContent(\\'%featuresCardsSlotId%@%featuresCardsSlotVersion%\\').then(({content}) => [\\'featuresCards\\', content])']}" + } + } + ] + }, + { + "name": "test", + "condition": "${options.slots.includes('features-title-section')}", + "then": [ + { + "name": "define", + "variables": { + "component": { + "name": "Mantine - Features with title", + "description": "A section of features with title", + "schema": "${import('mantine://block/features-title/configuration/features-title-schema.json')}" + }, + "slot": { + "name": "Material UI - Home highlights", + "component": "mantine-features-title-section", + "content": { + "en": "${import('mantine://block/features-title/configuration/features-title-content.en.json')}" + } + } + } + }, + { + "name": "define", + "variables": { + "components": "${{...this.components, 'mantine-features-title-section': this.component}}", + "slots": "${{...this.slots, 'mantine-home-features-title': this.slot}}", + "fetchCalls": "${[...this.fetchCalls, 'fetchContent(\\'%featuresTitleSlotId%@%featuresTitleSlotVersion%\\').then(({content}) => [\\'featuresTitle\\', content])']}" + } + } + ] + }, + { + "name": "test", + "condition": "${options.slots.includes('stats-group-section')}", + "then": [ + { + "name": "define", + "variables": { + "component": { + "name": "Mantine - Stats section", + "description": "A statistic section component", + "schema": "${import('mantine://block/stats-group/configuration/stats-group-schema.json')}" + }, + "slot": { + "name": "Mantine - Stats section", + "component": "mantine-stats-group", + "content": { + "en": "${import('mantine://block/stats-group/configuration/stats-group-content.en.json')}" + } + } + } + }, + { + "name": "define", + "variables": { + "components": "${{...this.components, 'mantine-stats-group': this.component}}", + "slots": "${{...this.slots, 'mantine-home-stats': this.slot}}", + "fetchCalls": "${[...this.fetchCalls, 'fetchContent(\\'%statsSlotId%@%statsSlotVersion%\\').then(({content}) => [\\'stats\\', content])']}" + } + } + ] + }, + { + "name": "create-resource", + "resources": { + "components": "${this.components}", + "slots": "${this.slots}" + }, + "result": { + "slots": { + "mantine-home-header": { + "id": "headerSlotId", + "version": "headerSlotVersion" + }, + "mantine-home-hero": { + "id": "heroSlotId", + "version": "heroSlotVersion" + }, + "mantine-home-features-cards": { + "id": "featuresCardsSlotId", + "version": "featuresCardsSlotVersion" + }, + "mantine-home-features-title": { + "id": "featuresTitleSlotId", + "version": "featuresTitleSlotVersion" + }, + "mantine-home-stats": { + "id": "statsSlotId", + "version": "statsSlotVersion" + } + } + } + }, + { + "name": "add-slot", + "slots": "${[...(this.headerSlotId ? [this.headerSlotId] : []), ...(this.heroSlotId ? [this.heroSlotId] : []), ...(this.featuresCardsSlotId ? [this.featuresCardsSlotId] : []), ...(this.featuresTitleSlotId ? [this.featuresTitleSlotId] : []), ...(this.statsSlotId ? [this.statsSlotId] : [])]}" + }, + { + "name": "replace-file-content", + "files": [ + { + "path": "${options.exampleDirectory}/${options.exampleFile}", + "replacements": [ + { + "pattern": "// %fetchCalls%", + "value": "${this.fetchCalls.join(',\n ')}" + } + ] + }, + { + "path": "${options.exampleDirectory}/${options.exampleFile}", + "replacements": [ + { + "pattern": "(\\s*)/\\*header\\*/(.+?)/\\*header\\*/(\\s*,)", + "value": "${this.headerSlotId ? '$1$2$3' : ''}" + }, + { + "pattern": "%headerSlotId%", + "value": "${this.headerSlotId}" + }, + { + "pattern": "%headerSlotVersion%", + "value": "${this.headerSlotVersion}" + }, + { + "pattern": "(\\s*)/\\*hero\\*/(.+?)/\\*hero\\*/(\\s*,)", + "value": "${this.heroSlotId ? '$1$2$3' : ''}" + }, + { + "pattern": "%heroSlotId%", + "value": "${this.heroSlotId}" + }, + { + "pattern": "%heroSlotVersion%", + "value": "${this.heroSlotVersion}" + }, + { + "pattern": "(\\s*)/\\*featuresCards\\*/(.+?)/\\*featuresCards\\*/(\\s*,)", + "value": "${this.featuresCardsSlotId ? '$1$2$3' : ''}" + }, + { + "pattern": "%featuresCardsSlotId%", + "value": "${this.featuresCardsSlotId}" + }, + { + "pattern": "%featuresCardsSlotVersion%", + "value": "${this.featuresCardsSlotVersion}" + }, + { + "pattern": "(\\s*)/\\*featuresTitle\\*/(.+?)/\\*featuresTitle\\*/(\\s*,)", + "value": "${this.featuresTitleSlotId ? '$1$2$3' : ''}" + }, + { + "pattern": "%featuresTitleSlotId%", + "value": "${this.featuresTitleSlotId}" + }, + { + "pattern": "%featuresTitleSlotVersion%", + "value": "${this.featuresTitleSlotVersion}" + }, + { + "pattern": "(\\s*)/\\*stats\\*/(.+?)/\\*stats\\*/(\\s*,)", + "value": "${this.statsSlotId ? '$1$2$3' : ''}" + }, + { + "pattern": "%statsSlotId%", + "value": "${this.statsSlotId}" + }, + { + "pattern": "%statsSlotVersion%", + "value": "${this.statsSlotVersion}" + } + ] + } + ] + } + ] +} diff --git a/templates/mantine/template/marketing-page/template.json5 b/templates/mantine/template/marketing-page/template.json5 new file mode 100644 index 00000000..4b14880f --- /dev/null +++ b/templates/mantine/template/marketing-page/template.json5 @@ -0,0 +1,174 @@ +{ + "$schema": "https://schema.croct.com/json/v1/catalog-template.json", + "title": "Marketing page template", + "description": "A marketing page template using Mantine and Croct.", + "metadata": { + "id": "library/mantine/marketing-page", + "ecosystem": { + "name": "Mantine", + "avatarUrl": "https://github.com/mantinedev.png", + "websiteUrl": "https://ui.mantine.dev?utm_source=croct" + }, + "documentationUrl": "https://github.com/croct-tech/templates/blob/master/templates/mantine/template/marketing-page/README.md", + "sourceUrl": "https://github.com/croct-tech/templates/blob/master/templates/mantine/template/marketing-page/template.json5", + "coverImageUrl": "https://github.com/croct-tech/templates/blob/master/templates/mantine/template/marketing-page/cover.png", + "installationUrl": "mantine://template/marketing-page", + "categories": [ + "framework/nextjs", + "framework/react", + "interface/marketing", + "language/javascript", + "language/typescript", + "library/mantine", + "use-case/saas" + ] + }, + "options": { + "version": { + "type": "string", + "description": "The version of Next.js to use.", + "choices": [ + "13", + "14", + "15", + "latest" + ] + }, + "router": { + "type": "string", + "description": "The router to use.", + "choices": [ + "app", + "page" + ], + "default": "app" + }, + "javascript": { + "type": "boolean", + "description": "Whether to use JavaScript instead of TypeScript.", + "default": false + }, + "slots": { + "type": "array", + "description": "The slots to use.", + "default": [] + } + }, + "actions": [ + { + "name": "define", + "variables": { + "slots": "${options.slots}", + "components": [], + "availableSlots": [ + "header", + "hero-section", + "features-cards-section", + "features-title-section", + "stats-group-section" + ] + } + }, + { + "name": "test", + "condition": "${this.slots.length === 0}", + "then": [ + { + "name": "prompt", + "message": "Which slots would you like to include in the marketing page?", + "type": "multi-choice", + "min": 1, + "options": [ + { + "label": "Header", + "value": "header" + }, + { + "label": "Hero section", + "value": "hero-section", + "selected": true + }, + { + "label": "Features cards section", + "value": "features-cards-section", + "selected": true + }, + { + "label": "Features title section", + "value": "features-title-section" + }, + { + "label": "Stats group section", + "value": "stats-group-section" + } + ], + "result": "slots" + } + ] + }, + { + "name": "define", + "variables": { + "componentIndex": 0 + } + }, + { + "name": "repeat", + "condition": "${this.componentIndex < this.slots.length}", + "actions": [ + { + "name": "define", + "variables": { + "slot": "${this.slots[this.componentIndex]}" + } + }, + { + "name": "test", + "condition": "${!this.availableSlots.includes(this.slot)}", + "then": [ + { + "name": "fail", + "message": "The slot '${this.slot}' specified in `slots` option is not available." + } + ] + }, + { + "name": "define", + "variables": { + "components": "${[...this.components, 'mantine://block/' + this.slot + '/code/components/' + this.slot + '.tsx']}", + "componentIndex": "${this.componentIndex + 1}" + } + } + ] + }, + { + "name": "import", + "template": "mantine://component/component", + "options": { + "id": "marketing-page", + "type": "template", + "version": "${options.version}", + "router": "${options.router}", + "javascript": "${options.javascript}", + "dependencies": [ + "@tabler/icons-react", + "@mantinex/mantine-logo" + ], + "components": [ + "mantine://component/header-simple/code/components/HeaderSimple/index.tsx", + "mantine://block/hero-bullets/code/components/HeroBullets/index.tsx", + "mantine://block/features-cards/code/components/FeaturesCards/index.tsx", + "mantine://block/features-title/code/components/FeaturesTitle/index.tsx", + "mantine://block/stats-group/code/components/StatsGroup/index.tsx", + "Footer/index.tsx", + "MarketingPage/index.tsx" + ], + "utils": [ + "markdown.tsx" + ], + "extension": "mantine://template/marketing-page/extension.json5", + "slots": "${this.slots}" + } + } + ] +}