added adminbar to layout
This commit is contained in:
6
bun.lock
6
bun.lock
@@ -3,6 +3,7 @@
|
|||||||
"workspaces": {
|
"workspaces": {
|
||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@payloadcms/admin-bar": "^3.59.1",
|
||||||
"@payloadcms/db-postgres": "3.59.1",
|
"@payloadcms/db-postgres": "3.59.1",
|
||||||
"@payloadcms/next": "3.59.1",
|
"@payloadcms/next": "3.59.1",
|
||||||
"@payloadcms/payload-cloud": "3.59.1",
|
"@payloadcms/payload-cloud": "3.59.1",
|
||||||
@@ -16,6 +17,7 @@
|
|||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"sharp": "0.34.2",
|
"sharp": "0.34.2",
|
||||||
|
"tailwind-merge": "^3.3.1",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "1.54.1",
|
"@playwright/test": "1.54.1",
|
||||||
@@ -455,6 +457,8 @@
|
|||||||
|
|
||||||
"@nolyfill/is-core-module": ["@nolyfill/is-core-module@1.0.39", "", {}, "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA=="],
|
"@nolyfill/is-core-module": ["@nolyfill/is-core-module@1.0.39", "", {}, "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA=="],
|
||||||
|
|
||||||
|
"@payloadcms/admin-bar": ["@payloadcms/admin-bar@3.59.1", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-gaOP7fWypaNHUfxLhdgmKV9qfrKmRUOjy32deBE/75lOSTtrZfOgMbq6W5cVLYl0yjV7xlSFoINIWmawmkQCjA=="],
|
||||||
|
|
||||||
"@payloadcms/db-postgres": ["@payloadcms/db-postgres@3.59.1", "", { "dependencies": { "@payloadcms/drizzle": "3.59.1", "@types/pg": "8.10.2", "console-table-printer": "2.12.1", "drizzle-kit": "0.31.4", "drizzle-orm": "0.44.2", "pg": "8.16.3", "prompts": "2.4.2", "to-snake-case": "1.0.0", "uuid": "10.0.0" }, "peerDependencies": { "payload": "3.59.1" } }, "sha512-lTxItMJ8wDt9gQ19zFRV2XJBsuoMtQiEOtHNBxULu4SVdee0vdcuRFZmjQYB5tZ0VOUEp96sCx+aMUh7RwRmzw=="],
|
"@payloadcms/db-postgres": ["@payloadcms/db-postgres@3.59.1", "", { "dependencies": { "@payloadcms/drizzle": "3.59.1", "@types/pg": "8.10.2", "console-table-printer": "2.12.1", "drizzle-kit": "0.31.4", "drizzle-orm": "0.44.2", "pg": "8.16.3", "prompts": "2.4.2", "to-snake-case": "1.0.0", "uuid": "10.0.0" }, "peerDependencies": { "payload": "3.59.1" } }, "sha512-lTxItMJ8wDt9gQ19zFRV2XJBsuoMtQiEOtHNBxULu4SVdee0vdcuRFZmjQYB5tZ0VOUEp96sCx+aMUh7RwRmzw=="],
|
||||||
|
|
||||||
"@payloadcms/drizzle": ["@payloadcms/drizzle@3.59.1", "", { "dependencies": { "console-table-printer": "2.12.1", "dequal": "2.0.3", "drizzle-orm": "0.44.2", "prompts": "2.4.2", "to-snake-case": "1.0.0", "uuid": "9.0.0" }, "peerDependencies": { "payload": "3.59.1" } }, "sha512-2n25PQfbFJ7uIlQxLilf8lrdbIGJ9p56ZNtViHl57DCq8SYGcB7Rz+5MSNdGwMnK28oYMAObJ4bBI5JG9DhR/g=="],
|
"@payloadcms/drizzle": ["@payloadcms/drizzle@3.59.1", "", { "dependencies": { "console-table-printer": "2.12.1", "dequal": "2.0.3", "drizzle-orm": "0.44.2", "prompts": "2.4.2", "to-snake-case": "1.0.0", "uuid": "9.0.0" }, "peerDependencies": { "payload": "3.59.1" } }, "sha512-2n25PQfbFJ7uIlQxLilf8lrdbIGJ9p56ZNtViHl57DCq8SYGcB7Rz+5MSNdGwMnK28oYMAObJ4bBI5JG9DhR/g=="],
|
||||||
@@ -1707,6 +1711,8 @@
|
|||||||
|
|
||||||
"tabbable": ["tabbable@6.2.0", "", {}, "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="],
|
"tabbable": ["tabbable@6.2.0", "", {}, "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="],
|
||||||
|
|
||||||
|
"tailwind-merge": ["tailwind-merge@3.3.1", "", {}, "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g=="],
|
||||||
|
|
||||||
"thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="],
|
"thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="],
|
||||||
|
|
||||||
"tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="],
|
"tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="],
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
"test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts"
|
"test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@payloadcms/admin-bar": "^3.59.1",
|
||||||
|
"@payloadcms/db-postgres": "3.59.1",
|
||||||
"@payloadcms/next": "3.59.1",
|
"@payloadcms/next": "3.59.1",
|
||||||
"@payloadcms/payload-cloud": "3.59.1",
|
"@payloadcms/payload-cloud": "3.59.1",
|
||||||
"@payloadcms/richtext-lexical": "3.59.1",
|
"@payloadcms/richtext-lexical": "3.59.1",
|
||||||
@@ -30,7 +32,7 @@
|
|||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"sharp": "0.34.2",
|
"sharp": "0.34.2",
|
||||||
"@payloadcms/db-postgres": "3.59.1"
|
"tailwind-merge": "^3.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "1.54.1",
|
"@playwright/test": "1.54.1",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import './styles.css'
|
import './styles.css'
|
||||||
|
import { AdminBar } from '@/src/components/AdminBar'
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
description: 'A blank template using Payload in a Next.js app.',
|
description: 'A blank template using Payload in a Next.js app.',
|
||||||
@@ -12,6 +13,7 @@ export default async function RootLayout(props: { children: React.ReactNode }) {
|
|||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body>
|
<body>
|
||||||
|
<AdminBar />
|
||||||
<main>{children}</main>
|
<main>{children}</main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ import Image from 'next/image'
|
|||||||
import { getPayload } from 'payload'
|
import { getPayload } from 'payload'
|
||||||
import type { Payload } from 'payload'
|
import type { Payload } from 'payload'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { fileURLToPath } from 'url'
|
|
||||||
|
|
||||||
import config from '@/payload.config'
|
import config from '@/src/payload.config'
|
||||||
import './styles.css'
|
import './styles.css'
|
||||||
import { RichText } from '@payloadcms/richtext-lexical/react'
|
import { RichText } from '@payloadcms/richtext-lexical/react'
|
||||||
|
|
||||||
@@ -15,8 +14,6 @@ export default async function HomePage() {
|
|||||||
const payload = await getPayload({ config: payloadConfig })
|
const payload = await getPayload({ config: payloadConfig })
|
||||||
const { user } = await payload.auth({ headers })
|
const { user } = await payload.auth({ headers })
|
||||||
|
|
||||||
const fileURL = `vscode://file/${fileURLToPath(import.meta.url)}`
|
|
||||||
|
|
||||||
const homePage = await payload.find({
|
const homePage = await payload.find({
|
||||||
collection: 'pages',
|
collection: 'pages',
|
||||||
where: {
|
where: {
|
||||||
@@ -28,8 +25,6 @@ export default async function HomePage() {
|
|||||||
|
|
||||||
const page = homePage.docs?.[0]
|
const page = homePage.docs?.[0]
|
||||||
|
|
||||||
console.log(page)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="home">
|
<div className="home">
|
||||||
<div className="content">
|
<div className="content">
|
||||||
@@ -53,7 +48,7 @@ export default async function HomePage() {
|
|||||||
/>
|
/>
|
||||||
</picture>
|
</picture>
|
||||||
{!user && <h1>Welcome to your new project.</h1>}
|
{!user && <h1>Welcome to your new project.</h1>}
|
||||||
{user && <h1>Welcome back, {user.email}</h1>}
|
{user && <h1>Welcome back, {user.name}</h1>}
|
||||||
<div className="links">
|
<div className="links">
|
||||||
<a
|
<a
|
||||||
className="admin"
|
className="admin"
|
||||||
@@ -75,9 +70,7 @@ export default async function HomePage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="footer">
|
<div className="footer">
|
||||||
<p>Update this page by editing</p>
|
<p>Update this page by editing</p>
|
||||||
<a className="codeLink" href={fileURL}>
|
|
||||||
<code>app/(frontend)/page.tsx</code>
|
<code>app/(frontend)/page.tsx</code>
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { StrikethroughFeatureClient as StrikethroughFeatureClient_e70f5e05f09f93
|
|||||||
import { UnderlineFeatureClient as UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
import { UnderlineFeatureClient as UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
import { BoldFeatureClient as BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
import { BoldFeatureClient as BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
import { ItalicFeatureClient as ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
import { ItalicFeatureClient as ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||||
|
import { SlugField as SlugField_3817bf644402e67bfe6577f60ef982de } from '@payloadcms/ui'
|
||||||
|
|
||||||
export const importMap = {
|
export const importMap = {
|
||||||
"@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell": RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e,
|
"@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell": RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e,
|
||||||
@@ -47,5 +48,6 @@ export const importMap = {
|
|||||||
"@payloadcms/richtext-lexical/client#StrikethroughFeatureClient": StrikethroughFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
"@payloadcms/richtext-lexical/client#StrikethroughFeatureClient": StrikethroughFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
"@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
"@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
"@payloadcms/richtext-lexical/client#BoldFeatureClient": BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
"@payloadcms/richtext-lexical/client#BoldFeatureClient": BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
"@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864
|
"@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||||
|
"@payloadcms/ui#SlugField": SlugField_3817bf644402e67bfe6577f60ef982de
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { lexicalEditor } from '@payloadcms/richtext-lexical'
|
import { lexicalEditor } from '@payloadcms/richtext-lexical'
|
||||||
import type { CollectionConfig } from 'payload'
|
import type { CollectionConfig } from 'payload'
|
||||||
|
import { slugField } from 'payload'
|
||||||
|
|
||||||
export const Page: CollectionConfig = {
|
export const Page: CollectionConfig = {
|
||||||
slug: 'pages',
|
slug: 'pages',
|
||||||
@@ -7,9 +8,6 @@ export const Page: CollectionConfig = {
|
|||||||
title: true,
|
title: true,
|
||||||
slug: true,
|
slug: true,
|
||||||
},
|
},
|
||||||
access: {
|
|
||||||
read: () => true,
|
|
||||||
},
|
|
||||||
admin: {
|
admin: {
|
||||||
defaultColumns: ['title', 'slug', 'updatedAt',],
|
defaultColumns: ['title', 'slug', 'updatedAt',],
|
||||||
},
|
},
|
||||||
@@ -22,6 +20,7 @@ export const Page: CollectionConfig = {
|
|||||||
{
|
{
|
||||||
name: 'richText',
|
name: 'richText',
|
||||||
type: 'richText'
|
type: 'richText'
|
||||||
}
|
},
|
||||||
|
slugField(),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
7
src/components/AdminBar/index.scss
Normal file
7
src/components/AdminBar/index.scss
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
@import '~@payloadcms/ui/scss';
|
||||||
|
|
||||||
|
.admin-bar {
|
||||||
|
@include small-break {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
89
src/components/AdminBar/index.tsx
Normal file
89
src/components/AdminBar/index.tsx
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import type { PayloadAdminBarProps, PayloadMeUser } from '@payloadcms/admin-bar'
|
||||||
|
|
||||||
|
import { cn } from '@/utilities/ui'
|
||||||
|
import { useSelectedLayoutSegments } from 'next/navigation'
|
||||||
|
import { PayloadAdminBar } from '@payloadcms/admin-bar'
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
|
import { getClientSideURL } from '@/utilities/getURL'
|
||||||
|
|
||||||
|
const baseClass = 'admin-bar'
|
||||||
|
|
||||||
|
const collectionLabels = {
|
||||||
|
pages: {
|
||||||
|
plural: 'Pages',
|
||||||
|
singular: 'Page',
|
||||||
|
},
|
||||||
|
posts: {
|
||||||
|
plural: 'Posts',
|
||||||
|
singular: 'Post',
|
||||||
|
},
|
||||||
|
projects: {
|
||||||
|
plural: 'Projects',
|
||||||
|
singular: 'Project',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const Title: React.FC = () => <span>Dashboard</span>
|
||||||
|
|
||||||
|
export const AdminBar: React.FC<{
|
||||||
|
adminBarProps?: PayloadAdminBarProps
|
||||||
|
}> = (props) => {
|
||||||
|
const { adminBarProps } = props || {}
|
||||||
|
const segments = useSelectedLayoutSegments()
|
||||||
|
const [show, setShow] = useState(false)
|
||||||
|
const collection = (
|
||||||
|
collectionLabels[segments?.[1] as keyof typeof collectionLabels] ? segments[1] : 'pages'
|
||||||
|
) as keyof typeof collectionLabels
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const onAuthChange = React.useCallback((user: PayloadMeUser) => {
|
||||||
|
setShow(Boolean(user?.id))
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn(baseClass, 'py-2 bg-black text-white', {
|
||||||
|
block: show,
|
||||||
|
hidden: !show,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<div className="container">
|
||||||
|
<PayloadAdminBar
|
||||||
|
{...adminBarProps}
|
||||||
|
className="py-2 text-white"
|
||||||
|
classNames={{
|
||||||
|
controls: 'font-medium text-white',
|
||||||
|
logo: 'text-white',
|
||||||
|
user: 'text-white',
|
||||||
|
}}
|
||||||
|
cmsURL={getClientSideURL()}
|
||||||
|
collectionSlug={collection}
|
||||||
|
collectionLabels={{
|
||||||
|
plural: collectionLabels[collection]?.plural || 'Pages',
|
||||||
|
singular: collectionLabels[collection]?.singular || 'Page',
|
||||||
|
}}
|
||||||
|
logo={<Title />}
|
||||||
|
onAuthChange={onAuthChange}
|
||||||
|
onPreviewExit={() => {
|
||||||
|
fetch('/next/exit-preview').then(() => {
|
||||||
|
router.push('/')
|
||||||
|
router.refresh()
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
padding: 0,
|
||||||
|
position: 'relative',
|
||||||
|
zIndex: 'unset',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -182,6 +182,11 @@ export interface Page {
|
|||||||
};
|
};
|
||||||
[k: string]: unknown;
|
[k: string]: unknown;
|
||||||
} | null;
|
} | null;
|
||||||
|
/**
|
||||||
|
* When enabled, the slug will auto-generate from the title field on save and autosave.
|
||||||
|
*/
|
||||||
|
generateSlug?: boolean | null;
|
||||||
|
slug: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
@@ -295,6 +300,8 @@ export interface MediaSelect<T extends boolean = true> {
|
|||||||
export interface PagesSelect<T extends boolean = true> {
|
export interface PagesSelect<T extends boolean = true> {
|
||||||
title?: T;
|
title?: T;
|
||||||
richText?: T;
|
richText?: T;
|
||||||
|
generateSlug?: T;
|
||||||
|
slug?: T;
|
||||||
updatedAt?: T;
|
updatedAt?: T;
|
||||||
createdAt?: T;
|
createdAt?: T;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": [
|
"@/*": [
|
||||||
"./src/*"
|
"./*"
|
||||||
],
|
],
|
||||||
"@payload-config": [
|
"@payload-config": [
|
||||||
"./src/payload.config.ts"
|
"./src/payload.config.ts"
|
||||||
|
|||||||
1
utilities/canUseDOM.ts
Normal file
1
utilities/canUseDOM.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export default !!(typeof window !== 'undefined' && window.document && window.document.createElement)
|
||||||
26
utilities/getURL.ts
Normal file
26
utilities/getURL.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import canUseDOM from './canUseDOM'
|
||||||
|
|
||||||
|
export const getServerSideURL = () => {
|
||||||
|
return (
|
||||||
|
process.env.NEXT_PUBLIC_SERVER_URL ||
|
||||||
|
(process.env.VERCEL_PROJECT_PRODUCTION_URL
|
||||||
|
? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}`
|
||||||
|
: 'http://localhost:3000')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getClientSideURL = () => {
|
||||||
|
if (canUseDOM) {
|
||||||
|
const protocol = window.location.protocol
|
||||||
|
const domain = window.location.hostname
|
||||||
|
const port = window.location.port
|
||||||
|
|
||||||
|
return `${protocol}//${domain}${port ? `:${port}` : ''}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.VERCEL_PROJECT_PRODUCTION_URL) {
|
||||||
|
return `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return process.env.NEXT_PUBLIC_SERVER_URL || ''
|
||||||
|
}
|
||||||
6
utilities/ui.ts
Normal file
6
utilities/ui.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { type ClassValue, clsx } from 'clsx'
|
||||||
|
import { twMerge } from 'tailwind-merge'
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user