kofi-stack-template-generator 2.1.27 → 2.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/index.js +336 -9
  2. package/package.json +8 -8
  3. package/src/templates.generated.ts +70 -11
  4. package/templates/marketing/payload/src/Footer/config.ts.hbs +178 -0
  5. package/templates/marketing/payload/src/Footer/hooks/revalidateFooter.ts.hbs +13 -0
  6. package/templates/marketing/payload/src/Footer/index.ts.hbs +1 -0
  7. package/templates/marketing/payload/src/Header/RowLabel.tsx.hbs +21 -0
  8. package/templates/marketing/payload/src/Header/config.ts.hbs +208 -0
  9. package/templates/marketing/payload/src/Header/hooks/revalidateHeader.ts.hbs +13 -0
  10. package/templates/marketing/payload/src/Header/index.ts.hbs +1 -0
  11. package/templates/marketing/payload/src/access/anyone.ts.hbs +3 -0
  12. package/templates/marketing/payload/src/access/authenticated.ts.hbs +9 -0
  13. package/templates/marketing/payload/src/access/authenticatedOrPublished.ts.hbs +13 -0
  14. package/templates/marketing/payload/src/access/index.ts.hbs +3 -0
  15. package/templates/marketing/payload/src/app/(frontend)/next/seed/route.ts.hbs +31 -0
  16. package/templates/marketing/payload/src/collections/Categories/index.ts.hbs +28 -0
  17. package/templates/marketing/payload/src/collections/FAQs/index.ts.hbs +100 -0
  18. package/templates/marketing/payload/src/collections/Media.ts.hbs +148 -28
  19. package/templates/marketing/payload/src/collections/Pages/hooks/revalidatePage.ts.hbs +43 -0
  20. package/templates/marketing/payload/src/collections/Pages/index.ts.hbs +142 -0
  21. package/templates/marketing/payload/src/collections/Posts/hooks/populateAuthors.ts.hbs +41 -0
  22. package/templates/marketing/payload/src/collections/Posts/hooks/revalidatePost.ts.hbs +44 -0
  23. package/templates/marketing/payload/src/collections/Posts/index.ts.hbs +244 -0
  24. package/templates/marketing/payload/src/collections/Users/index.ts.hbs +26 -0
  25. package/templates/marketing/payload/src/collections/index.ts.hbs +6 -4
  26. package/templates/marketing/payload/src/components/BeforeDashboard/SeedButton/index.scss.hbs +12 -0
  27. package/templates/marketing/payload/src/components/BeforeDashboard/SeedButton/index.tsx.hbs +89 -0
  28. package/templates/marketing/payload/src/components/BeforeDashboard/index.scss.hbs +24 -0
  29. package/templates/marketing/payload/src/components/BeforeDashboard/index.tsx.hbs +69 -0
  30. package/templates/marketing/payload/src/components/BeforeLogin/index.tsx.hbs +14 -0
  31. package/templates/marketing/payload/src/components/Link/index.tsx.hbs +79 -0
  32. package/templates/marketing/payload/src/components/Media/index.tsx.hbs +67 -0
  33. package/templates/marketing/payload/src/components/RichText/index.tsx.hbs +44 -0
  34. package/templates/marketing/payload/src/endpoints/seed/home.ts.hbs +76 -0
  35. package/templates/marketing/payload/src/endpoints/seed/image-1.ts.hbs +5 -0
  36. package/templates/marketing/payload/src/endpoints/seed/image-2.ts.hbs +5 -0
  37. package/templates/marketing/payload/src/endpoints/seed/image-hero.ts.hbs +5 -0
  38. package/templates/marketing/payload/src/endpoints/seed/index.ts.hbs +235 -0
  39. package/templates/marketing/payload/src/endpoints/seed/post-1.ts.hbs +252 -0
  40. package/templates/marketing/payload/src/fields/defaultLexical.ts.hbs +73 -0
  41. package/templates/marketing/payload/src/fields/index.ts.hbs +3 -0
  42. package/templates/marketing/payload/src/fields/link.ts.hbs +139 -0
  43. package/templates/marketing/payload/src/fields/linkGroup.ts.hbs +28 -0
  44. package/templates/marketing/payload/src/globals/index.ts.hbs +2 -2
  45. package/templates/marketing/payload/src/heros/HighImpact/index.tsx.hbs +53 -0
  46. package/templates/marketing/payload/src/heros/LowImpact/index.tsx.hbs +48 -0
  47. package/templates/marketing/payload/src/heros/MediumImpact/index.tsx.hbs +46 -0
  48. package/templates/marketing/payload/src/heros/PostHero/index.tsx.hbs +68 -0
  49. package/templates/marketing/payload/src/heros/ProductShowcase/index.tsx.hbs +88 -0
  50. package/templates/marketing/payload/src/heros/RenderHero.tsx.hbs +27 -0
  51. package/templates/marketing/payload/src/heros/config.ts.hbs +112 -0
  52. package/templates/marketing/payload/src/heros/index.ts.hbs +7 -0
  53. package/templates/marketing/payload/src/hooks/index.ts.hbs +2 -0
  54. package/templates/marketing/payload/src/hooks/populatePublishedAt.ts.hbs +15 -0
  55. package/templates/marketing/payload/src/hooks/revalidateRedirects.ts.hbs +11 -0
  56. package/templates/marketing/payload/src/payload.config.ts.hbs +32 -8
  57. package/templates/marketing/payload/src/providers/HeaderTheme/index.tsx.hbs +34 -0
  58. package/templates/marketing/payload/src/providers/Theme/InitTheme/index.tsx.hbs +44 -0
  59. package/templates/marketing/payload/src/providers/Theme/index.tsx.hbs +60 -0
  60. package/templates/marketing/payload/src/providers/Theme/shared.ts.hbs +17 -0
  61. package/templates/marketing/payload/src/providers/Theme/types.ts.hbs +10 -0
  62. package/templates/marketing/payload/src/providers/index.tsx.hbs +18 -0
  63. package/templates/marketing/payload/src/utilities/canUseDOM.ts.hbs +1 -0
  64. package/templates/marketing/payload/src/utilities/deepMerge.ts.hbs +35 -0
  65. package/templates/marketing/payload/src/utilities/formatAuthors.ts.hbs +24 -0
  66. package/templates/marketing/payload/src/utilities/formatDateTime.ts.hbs +13 -0
  67. package/templates/marketing/payload/src/utilities/generateMeta.ts.hbs +87 -0
  68. package/templates/marketing/payload/src/utilities/generatePreviewPath.ts.hbs +33 -0
  69. package/templates/marketing/payload/src/utilities/getURL.ts.hbs +26 -0
  70. package/templates/marketing/payload/src/utilities/index.ts.hbs +8 -0
  71. package/templates/marketing/payload/src/utilities/mergeOpenGraph.ts.hbs +26 -0
  72. package/templates/marketing/payload/src/collections/Pages.ts.hbs +0 -66
  73. package/templates/marketing/payload/src/collections/Posts.ts.hbs +0 -65
  74. package/templates/marketing/payload/src/collections/Users.ts.hbs +0 -25
  75. package/templates/marketing/payload/src/globals/Navigation.ts.hbs +0 -51
  76. package/templates/marketing/payload/src/globals/SiteSettings.ts.hbs +0 -49
@@ -0,0 +1,26 @@
1
+ import type { CollectionConfig } from "payload"
2
+
3
+ import { authenticated } from "../../access/authenticated"
4
+
5
+ export const Users: CollectionConfig = {
6
+ slug: "users",
7
+ access: {
8
+ admin: authenticated,
9
+ create: authenticated,
10
+ delete: authenticated,
11
+ read: authenticated,
12
+ update: authenticated,
13
+ },
14
+ admin: {
15
+ defaultColumns: ["name", "email"],
16
+ useAsTitle: "name",
17
+ },
18
+ auth: true,
19
+ fields: [
20
+ {
21
+ name: "name",
22
+ type: "text",
23
+ },
24
+ ],
25
+ timestamps: true,
26
+ }
@@ -1,4 +1,6 @@
1
- export { Users } from './Users'
2
- export { Media } from './Media'
3
- export { Pages } from './Pages'
4
- export { Posts } from './Posts'
1
+ export { Users } from "./Users"
2
+ export { Media } from "./Media"
3
+ export { Pages } from "./Pages"
4
+ export { Posts } from "./Posts"
5
+ export { Categories } from "./Categories"
6
+ export { FAQs } from "./FAQs"
@@ -0,0 +1,12 @@
1
+ .seedButton {
2
+ appearance: none;
3
+ background: none;
4
+ border: none;
5
+ padding: 0;
6
+ text-decoration: underline;
7
+
8
+ &:hover {
9
+ cursor: pointer;
10
+ opacity: 0.85;
11
+ }
12
+ }
@@ -0,0 +1,89 @@
1
+ "use client"
2
+
3
+ import { toast } from "@payloadcms/ui"
4
+ import type React from "react"
5
+ import { Fragment, useCallback, useState } from "react"
6
+
7
+ import "./index.scss"
8
+
9
+ const SuccessMessage: React.FC = () => (
10
+ <div>
11
+ Database seeded! You can now{" "}
12
+ <a target="_blank" href="/" rel="noreferrer">
13
+ visit your website
14
+ </a>
15
+ </div>
16
+ )
17
+
18
+ export const SeedButton: React.FC = () => {
19
+ const [loading, setLoading] = useState(false)
20
+ const [seeded, setSeeded] = useState(false)
21
+ const [error, setError] = useState<null | string>(null)
22
+
23
+ const handleClick = useCallback(
24
+ async (e: React.MouseEvent<HTMLButtonElement>) => {
25
+ e.preventDefault()
26
+
27
+ if (seeded) {
28
+ toast.info("Database already seeded.")
29
+ return
30
+ }
31
+ if (loading) {
32
+ toast.info("Seeding already in progress.")
33
+ return
34
+ }
35
+ if (error) {
36
+ toast.error(`An error occurred, please refresh and try again.`)
37
+ return
38
+ }
39
+
40
+ setLoading(true)
41
+
42
+ try {
43
+ toast.promise(
44
+ new Promise((resolve, reject) => {
45
+ try {
46
+ fetch("/next/seed", { method: "POST", credentials: "include" })
47
+ .then((res) => {
48
+ if (res.ok) {
49
+ resolve(true)
50
+ setSeeded(true)
51
+ } else {
52
+ reject("An error occurred while seeding.")
53
+ }
54
+ })
55
+ .catch((error) => {
56
+ reject(error)
57
+ })
58
+ } catch (error) {
59
+ reject(error)
60
+ }
61
+ }),
62
+ {
63
+ loading: "Seeding with data....",
64
+ success: <SuccessMessage />,
65
+ error: "An error occurred while seeding.",
66
+ },
67
+ )
68
+ } catch (err) {
69
+ const error = err instanceof Error ? err.message : String(err)
70
+ setError(error)
71
+ }
72
+ },
73
+ [loading, seeded, error],
74
+ )
75
+
76
+ let message = ""
77
+ if (loading) message = " (seeding...)"
78
+ if (seeded) message = " (done!)"
79
+ if (error) message = ` (error: ${error})`
80
+
81
+ return (
82
+ <Fragment>
83
+ <button className="seedButton" onClick={handleClick}>
84
+ Seed your database
85
+ </button>
86
+ {message}
87
+ </Fragment>
88
+ )
89
+ }
@@ -0,0 +1,24 @@
1
+ @import '~@payloadcms/ui/scss';
2
+
3
+ .dashboard .before-dashboard {
4
+ margin-bottom: base(1.5);
5
+
6
+ &__banner {
7
+ & h4 {
8
+ margin: 0;
9
+ }
10
+ }
11
+
12
+ &__instructions {
13
+ list-style: decimal;
14
+ margin-bottom: base(0.5);
15
+
16
+ & li {
17
+ width: 100%;
18
+ }
19
+ }
20
+
21
+ & a:hover {
22
+ opacity: 0.85;
23
+ }
24
+ }
@@ -0,0 +1,69 @@
1
+ import { Banner } from "@payloadcms/ui/elements/Banner"
2
+ import type React from "react"
3
+
4
+ import { SeedButton } from "./SeedButton"
5
+ import "./index.scss"
6
+
7
+ const baseClass = "before-dashboard"
8
+
9
+ const BeforeDashboard: React.FC = () => {
10
+ return (
11
+ <div className={baseClass}>
12
+ <Banner className={`${baseClass}__banner`} type="success">
13
+ <h4>Welcome to your dashboard!</h4>
14
+ </Banner>
15
+ Here&apos;s what to do next:
16
+ <ul className={`${baseClass}__instructions`}>
17
+ <li>
18
+ <SeedButton />
19
+ {" with a few pages and posts to jump-start your new site, then "}
20
+ <a href="/" target="_blank" rel="noreferrer">
21
+ visit your website
22
+ </a>
23
+ {" to see the results."}
24
+ </li>
25
+ <li>
26
+ {"Modify your "}
27
+ <a
28
+ href="https://payloadcms.com/docs/configuration/collections"
29
+ rel="noopener noreferrer"
30
+ target="_blank"
31
+ >
32
+ collections
33
+ </a>
34
+ {" and add more "}
35
+ <a
36
+ href="https://payloadcms.com/docs/fields/overview"
37
+ rel="noopener noreferrer"
38
+ target="_blank"
39
+ >
40
+ fields
41
+ </a>
42
+ {" as needed. If you are new to Payload, we also recommend you check out the "}
43
+ <a
44
+ href="https://payloadcms.com/docs/getting-started/what-is-payload"
45
+ rel="noopener noreferrer"
46
+ target="_blank"
47
+ >
48
+ Getting Started
49
+ </a>
50
+ {" docs."}
51
+ </li>
52
+ <li>
53
+ Commit and push your changes to the repository to trigger a redeployment of your project.
54
+ </li>
55
+ </ul>
56
+ {"Pro Tip: This block is a "}
57
+ <a
58
+ href="https://payloadcms.com/docs/custom-components/overview"
59
+ rel="noopener noreferrer"
60
+ target="_blank"
61
+ >
62
+ custom component
63
+ </a>
64
+ , you can remove it at any time by updating your <strong>payload.config</strong>.
65
+ </div>
66
+ )
67
+ }
68
+
69
+ export default BeforeDashboard
@@ -0,0 +1,14 @@
1
+ import type React from "react"
2
+
3
+ const BeforeLogin: React.FC = () => {
4
+ return (
5
+ <div>
6
+ <p>
7
+ <b>Welcome to your dashboard!</b>
8
+ {" This is where site admins will log in to manage your website."}
9
+ </p>
10
+ </div>
11
+ )
12
+ }
13
+
14
+ export default BeforeLogin
@@ -0,0 +1,79 @@
1
+ import { cn } from "@/lib/utils"
2
+ import Link from "next/link"
3
+ import type React from "react"
4
+
5
+ import type { Page, Post } from "@/payload-types"
6
+
7
+ type CMSLinkType = {
8
+ appearance?: "inline" | "default" | "outline" | "link"
9
+ children?: React.ReactNode
10
+ className?: string
11
+ label?: string | null
12
+ newTab?: boolean | null
13
+ reference?: {
14
+ relationTo: "pages" | "posts"
15
+ value: Page | Post | string | number
16
+ } | null
17
+ size?: "default" | "sm" | "lg" | null
18
+ type?: "custom" | "reference" | null
19
+ url?: string | null
20
+ }
21
+
22
+ export const CMSLink: React.FC<CMSLinkType> = (props) => {
23
+ const {
24
+ type,
25
+ appearance = "inline",
26
+ children,
27
+ className,
28
+ label,
29
+ newTab,
30
+ reference,
31
+ size = "default",
32
+ url,
33
+ } = props
34
+
35
+ const href =
36
+ type === "reference" && typeof reference?.value === "object" && reference.value.slug
37
+ ? `${reference?.relationTo !== "pages" ? `/${reference?.relationTo}` : ""}/${
38
+ reference.value.slug
39
+ }`
40
+ : url
41
+
42
+ if (!href) return null
43
+
44
+ const newTabProps = newTab ? { rel: "noopener noreferrer", target: "_blank" } : {}
45
+
46
+ // Size classes
47
+ const sizeClasses = {
48
+ default: "px-4 py-2",
49
+ sm: "px-3 py-1 text-sm",
50
+ lg: "px-6 py-3 text-lg",
51
+ }
52
+
53
+ // Appearance classes
54
+ const appearanceClasses = {
55
+ inline: "",
56
+ default: cn(
57
+ "inline-flex items-center justify-center rounded-md font-medium transition-colors",
58
+ "bg-primary text-primary-foreground hover:bg-primary/90",
59
+ sizeClasses[size || "default"]
60
+ ),
61
+ outline: cn(
62
+ "inline-flex items-center justify-center rounded-md font-medium transition-colors",
63
+ "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
64
+ sizeClasses[size || "default"]
65
+ ),
66
+ link: "underline-offset-4 hover:underline",
67
+ }
68
+
69
+ return (
70
+ <Link
71
+ className={cn(appearanceClasses[appearance], className)}
72
+ href={href || url || ""}
73
+ {...newTabProps}
74
+ >
75
+ {label && label}
76
+ {children && children}
77
+ </Link>
78
+ )
79
+ }
@@ -0,0 +1,67 @@
1
+ "use client"
2
+
3
+ import { cn } from "@/lib/utils"
4
+ import Image from "next/image"
5
+ import type React from "react"
6
+
7
+ import type { Media as MediaType } from "@/payload-types"
8
+
9
+ export interface MediaProps {
10
+ resource?: MediaType | string | number | null
11
+ alt?: string
12
+ className?: string
13
+ imgClassName?: string
14
+ fill?: boolean
15
+ priority?: boolean
16
+ size?: string
17
+ }
18
+
19
+ export const Media: React.FC<MediaProps> = ({
20
+ resource,
21
+ alt: altFromProps,
22
+ className,
23
+ imgClassName,
24
+ fill = false,
25
+ priority = false,
26
+ size,
27
+ }) => {
28
+ // If resource is not an object or is null/undefined, return null
29
+ if (!resource || typeof resource !== "object") {
30
+ return null
31
+ }
32
+
33
+ const { url, alt: altFromResource, width, height } = resource
34
+
35
+ const alt = altFromProps ?? altFromResource ?? ""
36
+
37
+ if (!url) return null
38
+
39
+ // Handle fill mode
40
+ if (fill) {
41
+ return (
42
+ <div className={cn("relative", className)}>
43
+ <Image
44
+ src={url}
45
+ alt={alt}
46
+ fill
47
+ className={cn("object-cover", imgClassName)}
48
+ priority={priority}
49
+ sizes={size || "100vw"}
50
+ />
51
+ </div>
52
+ )
53
+ }
54
+
55
+ // Handle normal mode with width/height
56
+ return (
57
+ <Image
58
+ src={url}
59
+ alt={alt}
60
+ width={width || 800}
61
+ height={height || 600}
62
+ className={cn(className, imgClassName)}
63
+ priority={priority}
64
+ sizes={size}
65
+ />
66
+ )
67
+ }
@@ -0,0 +1,44 @@
1
+ import type { DefaultTypedEditorState } from "@payloadcms/richtext-lexical"
2
+ import {
3
+ RichText as ConvertRichText,
4
+ type JSXConvertersFunction,
5
+ LinkJSXConverter,
6
+ } from "@payloadcms/richtext-lexical/react"
7
+ import { cn } from "@/lib/utils"
8
+ import type React from "react"
9
+
10
+ const jsxConverters: JSXConvertersFunction = ({ defaultConverters }) => ({
11
+ ...defaultConverters,
12
+ ...LinkJSXConverter({ internalDocToHref: ({ linkNode }) => {
13
+ const { value, relationTo } = linkNode.fields.doc || {}
14
+ if (typeof value !== "object" || !value) return "/"
15
+ const slug = value.slug
16
+ return relationTo === "posts" ? `/posts/${slug}` : `/${slug}`
17
+ }}),
18
+ })
19
+
20
+ type Props = {
21
+ data: DefaultTypedEditorState
22
+ enableGutter?: boolean
23
+ enableProse?: boolean
24
+ } & React.HTMLAttributes<HTMLDivElement>
25
+
26
+ export default function RichText(props: Props) {
27
+ const { className, enableProse = true, enableGutter = true, ...rest } = props
28
+ return (
29
+ <ConvertRichText
30
+ converters={jsxConverters}
31
+ className={cn(
32
+ "payload-richtext",
33
+ {
34
+ container: enableGutter,
35
+ "prose prose-lg dark:prose-invert prose-headings:font-bold prose-headings:tracking-tight prose-a:text-primary prose-a:no-underline hover:prose-a:underline prose-blockquote:border-l-primary prose-blockquote:not-italic prose-li:marker:text-muted-foreground":
36
+ enableProse,
37
+ },
38
+ !enableGutter && "max-w-none",
39
+ className,
40
+ )}
41
+ {...rest}
42
+ />
43
+ )
44
+ }
@@ -0,0 +1,76 @@
1
+ import type { Media } from "@/payload-types"
2
+ import type { RequiredDataFromCollectionSlug } from "payload"
3
+
4
+ type HomeArgs = {
5
+ heroImage: Media
6
+ }
7
+
8
+ export const home: (args: HomeArgs) => RequiredDataFromCollectionSlug<"pages"> = ({
9
+ heroImage,
10
+ }) => {
11
+ return {
12
+ slug: "home",
13
+ _status: "published",
14
+ title: "Home",
15
+ layout: [
16
+ {
17
+ blockType: "hero",
18
+ heading: "Welcome to {{projectName}}",
19
+ subheading: "Build something amazing with Payload CMS and Next.js",
20
+ primaryCta: {
21
+ label: "Get Started",
22
+ url: "/posts",
23
+ },
24
+ secondaryCta: {
25
+ label: "Learn More",
26
+ url: "/contact",
27
+ },
28
+ },
29
+ {
30
+ blockType: "features",
31
+ heading: "Core Features",
32
+ subheading: "Everything you need to build modern websites",
33
+ features: [
34
+ {
35
+ icon: "layout",
36
+ title: "Page Builder",
37
+ description: "Create beautiful pages with our flexible block-based editor.",
38
+ },
39
+ {
40
+ icon: "zap",
41
+ title: "Lightning Fast",
42
+ description: "Optimized for performance with Next.js and React Server Components.",
43
+ },
44
+ {
45
+ icon: "shield",
46
+ title: "Secure by Default",
47
+ description: "Built-in authentication and role-based access control.",
48
+ },
49
+ {
50
+ icon: "database",
51
+ title: "Flexible Database",
52
+ description: "Works with MongoDB, PostgreSQL, and other databases.",
53
+ },
54
+ ],
55
+ },
56
+ {
57
+ blockType: "cta",
58
+ heading: "Ready to get started?",
59
+ subheading: "Start building your next project today.",
60
+ primaryCta: {
61
+ label: "View Posts",
62
+ url: "/posts",
63
+ },
64
+ secondaryCta: {
65
+ label: "Contact Us",
66
+ url: "/contact",
67
+ },
68
+ },
69
+ ],
70
+ meta: {
71
+ description: "Welcome to {{projectName}} - Built with Payload CMS and Next.js",
72
+ image: heroImage.id,
73
+ title: "{{projectName}}",
74
+ },
75
+ }
76
+ }
@@ -0,0 +1,5 @@
1
+ import type { Media } from "@/payload-types"
2
+
3
+ export const image1: Omit<Media, "createdAt" | "id" | "updatedAt"> = {
4
+ alt: "Curving abstract shapes with an orange and blue gradient",
5
+ }
@@ -0,0 +1,5 @@
1
+ import type { Media } from "@/payload-types"
2
+
3
+ export const image2: Omit<Media, "createdAt" | "id" | "updatedAt"> = {
4
+ alt: "Stylized 3D rendering of a dark, abstract cosmic landscape",
5
+ }
@@ -0,0 +1,5 @@
1
+ import type { Media } from "@/payload-types"
2
+
3
+ export const imageHero: Omit<Media, "createdAt" | "id" | "updatedAt"> = {
4
+ alt: "Abstract hero image with gradient",
5
+ }