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 => ,
+ 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}"
+ }
+ }
+ ]
+}