Skip to content

Commit

Permalink
templates: adds landing page to blank template (#10769)
Browse files Browse the repository at this point in the history
This addition enhances the `Blank` template by adding a simple front-end
to ensure a better out-of-the-box experience.

When deploying the template to platforms like `Payload Cloud`, `Vercel`,
or similar services, users would previously encounter a `404` or
`not-found` page on the front-end `/` route unless explicitly handled.

With this update, the template now includes a minimal front-end that
renders a basic page at route `/`.

### Notes

- The added front-end is entirely optional.

- If users prefer to use the `Blank` template as a starting point for a
back-end-only solution or plan to integrate with a different front-end
framework, they can simply delete the `(frontend)` folder and proceed as
before.

`Logged out`:

![Screenshot 2025-01-28 at 10 26
01 AM](https://github.com/user-attachments/assets/f6cd99bd-9746-4d0e-910f-2322a671c6b3)

`Logged in`:

![Screenshot 2025-01-28 at 10 25
42 AM](https://github.com/user-attachments/assets/27c0bbfb-bd94-4e3c-9bb9-332aa3ccc8cc)

`Mobile`:

![Screenshot 2025-01-28 at 10 25
14 AM](https://github.com/user-attachments/assets/370869b4-c5e5-4b17-bff6-3514e7baffc7)
  • Loading branch information
PatrikKozak authored Jan 28, 2025
1 parent 57f7218 commit e65a04a
Show file tree
Hide file tree
Showing 18 changed files with 1,516 additions and 0 deletions.
19 changes: 19 additions & 0 deletions templates/blank/src/app/(frontend)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react'
import './styles.css'

export const metadata = {
description: 'A blank template using Payload in a Next.js app.',
title: 'Payload Blank Template',
}

export default async function RootLayout(props: { children: React.ReactNode }) {
const { children } = props

return (
<html lang="en">
<body>
<main>{children}</main>
</body>
</html>
)
}
59 changes: 59 additions & 0 deletions templates/blank/src/app/(frontend)/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { headers as getHeaders } from 'next/headers.js'
import Image from 'next/image'
import { getPayload } from 'payload'
import React from 'react'
import { fileURLToPath } from 'url'

import config from '@/payload.config'
import './styles.css'

export default async function HomePage() {
const headers = await getHeaders()
const payloadConfig = await config
const payload = await getPayload({ config: payloadConfig })
const { user } = await payload.auth({ headers })

const fileURL = `vscode://file/${fileURLToPath(import.meta.url)}`

return (
<div className="home">
<div className="content">
<picture>
<source srcSet="https://raw.githubusercontent.com/payloadcms/payload/main/packages/ui/src/assets/payload-favicon.svg" />
<Image
alt="Payload Logo"
height={65}
src="https://raw.githubusercontent.com/payloadcms/payload/main/packages/ui/src/assets/payload-favicon.svg"
width={65}
/>
</picture>
{!user && <h1>Welcome to your new project.</h1>}
{user && <h1>Welcome back, {user.email}</h1>}
<div className="links">
<a
className="admin"
href={payloadConfig.routes.admin}
rel="noopener noreferrer"
target="_blank"
>
Go to admin panel
</a>
<a
className="docs"
href="https://payloadcms.com/docs"
rel="noopener noreferrer"
target="_blank"
>
Documentation
</a>
</div>
</div>
<div className="footer">
<p>Update this page by editing</p>
<a className="codeLink" href={fileURL}>
<code>app/(frontend)/page.tsx</code>
</a>
</div>
</div>
)
}
164 changes: 164 additions & 0 deletions templates/blank/src/app/(frontend)/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
:root {
--font-mono: 'Roboto Mono', monospace;
}

* {
box-sizing: border-box;
}

html {
font-size: 18px;
line-height: 32px;

background: rgb(0, 0, 0);
-webkit-font-smoothing: antialiased;
}

html,
body,
#app {
height: 100%;
}

body {
font-family: system-ui;
font-size: 18px;
line-height: 32px;

margin: 0;
color: rgb(1000, 1000, 1000);

@media (max-width: 1024px) {
font-size: 15px;
line-height: 24px;
}
}

img {
max-width: 100%;
height: auto;
display: block;
}

h1 {
margin: 40px 0;
font-size: 64px;
line-height: 70px;
font-weight: bold;

@media (max-width: 1024px) {
margin: 24px 0;
font-size: 42px;
line-height: 42px;
}

@media (max-width: 768px) {
font-size: 38px;
line-height: 38px;
}

@media (max-width: 400px) {
font-size: 32px;
line-height: 32px;
}
}

p {
margin: 24px 0;

@media (max-width: 1024px) {
margin: calc(var(--base) * 0.75) 0;
}
}

a {
color: currentColor;

&:focus {
opacity: 0.8;
outline: none;
}

&:active {
opacity: 0.7;
outline: none;
}
}

svg {
vertical-align: middle;
}

.home {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
height: 100vh;
padding: 45px;
max-width: 1024px;
margin: 0 auto;
overflow: hidden;

@media (max-width: 400px) {
padding: 24px;
}

.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex-grow: 1;

h1 {
text-align: center;
}
}

.links {
display: flex;
align-items: center;
gap: 12px;

a {
text-decoration: none;
padding: 0.25rem 0.5rem;
border-radius: 4px;
}

.admin {
color: rgb(0, 0, 0);
background: rgb(1000, 1000, 1000);
border: 1px solid rgb(0, 0, 0);
}

.docs {
color: rgb(1000, 1000, 1000);
background: rgb(0, 0, 0);
border: 1px solid rgb(1000, 1000, 1000);
}
}

.footer {
display: flex;
align-items: center;
gap: 8px;

@media (max-width: 1024px) {
flex-direction: column;
gap: 6px;
}

p {
margin: 0;
}

.codeLink {
text-decoration: none;
padding: 0 0.5rem;
background: rgb(60, 60, 60);
border-radius: 4px;
}
}
}
102 changes: 102 additions & 0 deletions templates/blank/src/payload-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,31 @@ export interface Config {
collections: {
users: User;
media: Media;
'payload-locked-documents': PayloadLockedDocument;
'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration;
};
collectionsJoins: {};
collectionsSelect: {
users: UsersSelect<false> | UsersSelect<true>;
media: MediaSelect<false> | MediaSelect<true>;
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
};
db: {
defaultIDType: string;
};
globals: {};
globalsSelect: {};
locale: null;
user: User & {
collection: 'users';
};
jobs: {
tasks: unknown;
workflows: unknown;
};
}
export interface UserAuthOperations {
forgotPassword: {
Expand Down Expand Up @@ -79,6 +93,29 @@ export interface Media {
focalX?: number | null;
focalY?: number | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents".
*/
export interface PayloadLockedDocument {
id: string;
document?:
| ({
relationTo: 'users';
value: string | User;
} | null)
| ({
relationTo: 'media';
value: string | Media;
} | null);
globalSlug?: string | null;
user: {
relationTo: 'users';
value: string | User;
};
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences".
Expand Down Expand Up @@ -113,6 +150,71 @@ export interface PayloadMigration {
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users_select".
*/
export interface UsersSelect<T extends boolean = true> {
updatedAt?: T;
createdAt?: T;
email?: T;
resetPasswordToken?: T;
resetPasswordExpiration?: T;
salt?: T;
hash?: T;
loginAttempts?: T;
lockUntil?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "media_select".
*/
export interface MediaSelect<T extends boolean = true> {
alt?: T;
updatedAt?: T;
createdAt?: T;
url?: T;
thumbnailURL?: T;
filename?: T;
mimeType?: T;
filesize?: T;
width?: T;
height?: T;
focalX?: T;
focalY?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents_select".
*/
export interface PayloadLockedDocumentsSelect<T extends boolean = true> {
document?: T;
globalSlug?: T;
user?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences_select".
*/
export interface PayloadPreferencesSelect<T extends boolean = true> {
user?: T;
key?: T;
value?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-migrations_select".
*/
export interface PayloadMigrationsSelect<T extends boolean = true> {
name?: T;
batch?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "auth".
Expand Down
19 changes: 19 additions & 0 deletions templates/with-payload-cloud/src/app/(frontend)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react'
import './styles.css'

export const metadata = {
description: 'A blank template using Payload in a Next.js app.',
title: 'Payload Blank Template',
}

export default async function RootLayout(props: { children: React.ReactNode }) {
const { children } = props

return (
<html lang="en">
<body>
<main>{children}</main>
</body>
</html>
)
}
Loading

0 comments on commit e65a04a

Please sign in to comment.