added tons of features
This commit is contained in:
19
app/(protected)/admin/category/[...slug]/page.tsx
Normal file
19
app/(protected)/admin/category/[...slug]/page.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import {auth} from '@/auth'
|
||||
import {CreateForm} from '@/components/(protected)/admin/category/create-form'
|
||||
import {dump} from '@/lib/utils'
|
||||
|
||||
export default async function Page({
|
||||
params
|
||||
}: {
|
||||
params: Promise<{slug?: string[]}>
|
||||
}) {
|
||||
const session = await auth()
|
||||
const {slug} = await params
|
||||
|
||||
switch ((slug || [])[0]) {
|
||||
case 'create':
|
||||
return <CreateForm />
|
||||
}
|
||||
|
||||
return <div>{dump(slug)}</div>
|
||||
}
|
||||
14
app/(protected)/admin/category/page.tsx
Normal file
14
app/(protected)/admin/category/page.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
import AdminPermission from '@/components/(protected)/admin/auth/permission'
|
||||
|
||||
export default function AdminCategoryPage() {
|
||||
return (
|
||||
<div>
|
||||
<AdminPermission />
|
||||
<p>
|
||||
<Link href='/admin/category/create'>Створити</Link>
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
65
app/(protected)/admin/layout.tsx
Normal file
65
app/(protected)/admin/layout.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import {cookies} from 'next/headers'
|
||||
import {ReactNode} from 'react'
|
||||
|
||||
import {auth} from '@/auth'
|
||||
import AdminPermission from '@/components/(protected)/admin/auth/permission'
|
||||
import {AdminSidebar} from '@/components/(protected)/admin/sidebar'
|
||||
import {
|
||||
SidebarInset,
|
||||
SidebarProvider,
|
||||
SidebarTrigger
|
||||
} from '@/components/ui/sidebar'
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator
|
||||
} from '@/ui/breadcrumb'
|
||||
import {Separator} from '@/ui/separator'
|
||||
|
||||
export default async function AdminLayout({children}: {children: ReactNode}) {
|
||||
//const session = await auth()
|
||||
if (!(await auth())) return <AdminPermission />
|
||||
|
||||
const cookieStore = await cookies()
|
||||
const defaultOpen = cookieStore.get('sidebar:state')?.value === 'true'
|
||||
|
||||
return (
|
||||
<SidebarProvider
|
||||
defaultOpen={defaultOpen}
|
||||
style={{
|
||||
// @ts-ignore
|
||||
'--sidebar-width': '16rem',
|
||||
'--sidebar-width-mobile': '18rem'
|
||||
}}
|
||||
>
|
||||
<AdminSidebar />
|
||||
<SidebarInset>
|
||||
<header className='flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12'>
|
||||
<div className='flex items-center gap-2 px-4'>
|
||||
<SidebarTrigger className='-ml-1' />
|
||||
<Separator orientation='vertical' className='mr-2 h-4' />
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem className='hidden md:block'>
|
||||
<BreadcrumbLink href='#'>
|
||||
Building Your Application
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator className='hidden md:block' />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Data Fetching</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
</header>
|
||||
<main id='admin-bw-panel' className='container'>
|
||||
{children}
|
||||
</main>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
)
|
||||
}
|
||||
5
app/(protected)/admin/page.tsx
Normal file
5
app/(protected)/admin/page.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import AdminPermission from '@/components/(protected)/admin/auth/permission'
|
||||
|
||||
export default async function AdminPage() {
|
||||
return <AdminPermission />
|
||||
}
|
||||
30
app/(protected)/admin/product/[...slug]/page.tsx
Normal file
30
app/(protected)/admin/product/[...slug]/page.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import ProductCreateEditForm from '@/components/(protected)/admin/product/create-edit-form'
|
||||
import {getProductById} from '@/lib/data/models/product'
|
||||
import {dump} from '@/lib/utils'
|
||||
|
||||
export default async function Page({
|
||||
params
|
||||
}: {
|
||||
params: Promise<{slug?: string[]}>
|
||||
}) {
|
||||
const {slug} = await params
|
||||
const [method, id] = slug || []
|
||||
|
||||
let data = null
|
||||
|
||||
if (id) {
|
||||
data = await getProductById(parseInt(id))
|
||||
if (data) {
|
||||
data = JSON.parse(JSON.stringify(data))
|
||||
}
|
||||
}
|
||||
|
||||
switch (method) {
|
||||
case 'create':
|
||||
return <ProductCreateEditForm />
|
||||
case 'update':
|
||||
return <ProductCreateEditForm data={data} />
|
||||
default:
|
||||
return <div>{dump(slug)}</div>
|
||||
}
|
||||
}
|
||||
34
app/(protected)/admin/product/page.tsx
Normal file
34
app/(protected)/admin/product/page.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import {Product} from '@prisma/client'
|
||||
import {LayoutList} from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
|
||||
import AdminPermission from '@/components/(protected)/admin/auth/permission'
|
||||
import dayjs from '@/lib/config/dayjs'
|
||||
import {getProducts} from '@/lib/data/models/product'
|
||||
import {dump} from '@/lib/utils'
|
||||
|
||||
//const products = await getProducts()
|
||||
|
||||
export default async function AdminProductPage() {
|
||||
return (
|
||||
<>
|
||||
<AdminPermission />
|
||||
<p>
|
||||
<Link href='/admin/product/create'>Створити</Link>
|
||||
</p>
|
||||
{/*<section className={'mt-12'}>
|
||||
{products
|
||||
? products.map((product: Product) => (
|
||||
<article
|
||||
key={product.id}
|
||||
className={'flex flex-row items-center justify-evenly'}
|
||||
>
|
||||
<LayoutList />
|
||||
{product.locales[0].headingTitle || product.locales[0].title}
|
||||
</article>
|
||||
))
|
||||
: null}
|
||||
</section>*/}
|
||||
</>
|
||||
)
|
||||
}
|
||||
16
app/[locale]/(auth)/layout.tsx
Normal file
16
app/[locale]/(auth)/layout.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from 'react'
|
||||
|
||||
export default async function AuthLayout({
|
||||
children
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<section className='relative w-full'>
|
||||
<div className='flex h-screen items-center justify-center bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-brand-violet-400 to-brand-yellow-200'>
|
||||
{/**/}
|
||||
{children}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
5
app/[locale]/(auth)/login/page.tsx
Normal file
5
app/[locale]/(auth)/login/page.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import LoginForm from '@/components/auth/forms/login-form'
|
||||
|
||||
export default function LoginPage() {
|
||||
return <LoginForm />
|
||||
}
|
||||
5
app/[locale]/(auth)/register/page.tsx
Normal file
5
app/[locale]/(auth)/register/page.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import RegisterForm from '@/components/auth/forms/register-form'
|
||||
|
||||
export default function RegisterPage() {
|
||||
return <RegisterForm />
|
||||
}
|
||||
26
app/[locale]/(root)/(cabinet)/cabinet/[[...slug]]/page.tsx
Normal file
26
app/[locale]/(root)/(cabinet)/cabinet/[[...slug]]/page.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import can, {CanAccessResponse} from '@/actions/permission'
|
||||
import LoginForm from '@/components/auth/forms/login-form'
|
||||
import CabinetIndex from '@/components/cabinet'
|
||||
import {Access} from '@/lib/permission'
|
||||
|
||||
export default async function CabinetPage({
|
||||
params
|
||||
}: {
|
||||
params: Promise<{slug?: string[]}>
|
||||
}) {
|
||||
const user = (await can(Access.Cabinet)) as CanAccessResponse
|
||||
|
||||
if (!user.can || !user.session) {
|
||||
return (
|
||||
<div className='my-8'>
|
||||
<div className='container flex flex-col sm:flex-row'>
|
||||
<LoginForm />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
const {slug} = await params
|
||||
|
||||
return <CabinetIndex slug={slug} session={user.session} />
|
||||
}
|
||||
}
|
||||
12
app/[locale]/(root)/(shop)/checkout/page.tsx
Normal file
12
app/[locale]/(root)/(shop)/checkout/page.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import {Metadata} from 'next'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Checkout'
|
||||
}
|
||||
|
||||
export default function CheckoutPage() {
|
||||
//throw new Error('NOT IMPLEMENTED')
|
||||
|
||||
//const session = await auth()
|
||||
return <div>CheckoutPage</div>
|
||||
}
|
||||
17
app/[locale]/(root)/layout.tsx
Normal file
17
app/[locale]/(root)/layout.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import {ReactNode} from 'react'
|
||||
|
||||
import Above from '@/components/shared/above'
|
||||
import Footer from '@/components/shared/footer'
|
||||
import Header from '@/components/shared/header'
|
||||
|
||||
export default async function HomeLayout({children}: {children: ReactNode}) {
|
||||
return (
|
||||
<>
|
||||
<Above />
|
||||
<Header />
|
||||
{/*<Above />*/}
|
||||
{children}
|
||||
<Footer />
|
||||
</>
|
||||
)
|
||||
}
|
||||
69
app/[locale]/(root)/page.tsx
Normal file
69
app/[locale]/(root)/page.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
import FeatureCards from '@/components/shared/home/feature-cards'
|
||||
import {HomeCarousel} from '@/components/shared/home/home-carousel'
|
||||
import AppCatalog from '@/components/shared/sidebar/app-catalog'
|
||||
import {carousels} from '@/lib/data'
|
||||
import {db} from '@/lib/db/prisma/client'
|
||||
import {dump} from '@/lib/utils'
|
||||
import image from '@/public/uploads/products/IMG_6572.jpg'
|
||||
|
||||
// const storeModel = async (id: any) => {
|
||||
// return db.store.findFirst({
|
||||
// where: {id},
|
||||
// include: {
|
||||
// storeLocale: {
|
||||
// include: {
|
||||
// meta: {
|
||||
// include: {
|
||||
// openGraph: true
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
export default async function HomePage() {
|
||||
return (
|
||||
<>
|
||||
<div className='mt-1'>
|
||||
<div className='container flex flex-col sm:flex-row'>
|
||||
<section className='bw-layout-col-left pt-3'>
|
||||
<AppCatalog />
|
||||
</section>
|
||||
<div className='bw-layout-col-right pt-3'>
|
||||
{/*<pre>{dump(await storeModel(1))}</pre>*/}
|
||||
<section className='w-full'>
|
||||
<HomeCarousel items={carousels}></HomeCarousel>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/*<pre>{JSON.stringify(session)}</pre>*/}
|
||||
|
||||
<section className='relative mx-auto mt-8 h-[640px] w-[840px] bg-brand-violet-200'>
|
||||
<Image
|
||||
src={'/uploads/products/IMG_6572.jpg'}
|
||||
//fill
|
||||
//sizes='(min-width: 808px) 50vw, 100vw'
|
||||
width={1280}
|
||||
height={1280}
|
||||
alt=''
|
||||
title=''
|
||||
priority
|
||||
style={{
|
||||
objectFit: 'contain' // cover, contain, none
|
||||
}}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section className='mb-4 mt-[128px]'>
|
||||
<div className='container'>
|
||||
<FeatureCards />
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
}
|
||||
34
app/[locale]/error.tsx
Normal file
34
app/[locale]/error.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
'use client'
|
||||
|
||||
import {useTranslations} from 'next-intl'
|
||||
import React from 'react'
|
||||
|
||||
import {Button} from '@/components/ui/button'
|
||||
|
||||
export default function ErrorPage({
|
||||
error,
|
||||
reset
|
||||
}: {
|
||||
error: Error
|
||||
reset: () => void
|
||||
}) {
|
||||
const t = useTranslations('Error')
|
||||
return (
|
||||
<div className='flex min-h-screen flex-col items-center justify-center'>
|
||||
<div className='w-1/3 rounded-lg p-6 text-center shadow-md'>
|
||||
<h1 className='mb-4 text-3xl font-bold'>{t('title')}</h1>
|
||||
<p className='text-destructive'>{error.message}</p>
|
||||
<Button variant='outline' className='mt-4' onClick={() => reset()}>
|
||||
{t('try-again')}
|
||||
</Button>
|
||||
<Button
|
||||
variant='outline'
|
||||
className='ml-2 mt-4'
|
||||
onClick={() => (window.location.href = '/')}
|
||||
>
|
||||
{t('back-to-home')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
33
app/[locale]/layout.tsx
Normal file
33
app/[locale]/layout.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import {NextIntlClientProvider} from 'next-intl'
|
||||
import {getMessages} from 'next-intl/server'
|
||||
import {notFound} from 'next/navigation'
|
||||
import {ReactNode} from 'react'
|
||||
|
||||
import {routing} from '@/i18n/routing'
|
||||
import {TIMEZONE} from '@/lib/constants'
|
||||
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
params
|
||||
}: Readonly<{
|
||||
children: ReactNode
|
||||
params: Promise<{locale: string}>
|
||||
}>) {
|
||||
const {locale} = await params
|
||||
if (!routing.locales.includes(locale as any)) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
const messages = await getMessages()
|
||||
//const queryClient = new QueryClient()
|
||||
|
||||
return (
|
||||
<NextIntlClientProvider
|
||||
messages={messages}
|
||||
timeZone={TIMEZONE}
|
||||
now={new Date()}
|
||||
>
|
||||
{children}
|
||||
</NextIntlClientProvider>
|
||||
)
|
||||
}
|
||||
1
app/api/auth/[...nextauth]/route.ts
Normal file
1
app/api/auth/[...nextauth]/route.ts
Normal file
@@ -0,0 +1 @@
|
||||
export {GET, POST} from '@/auth'
|
||||
0
app/api/uploads/[...filestore]/route.ts
Normal file
0
app/api/uploads/[...filestore]/route.ts
Normal file
BIN
app/favicon.ico
BIN
app/favicon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 11 KiB |
215
app/globals.css
215
app/globals.css
@@ -2,20 +2,215 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
@layer base {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 0 4.615% 12.75%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 20 14.3% 4.1%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 20 14.3% 4.1%;
|
||||
--primary: 47.9 95.8% 53.1%;
|
||||
--primary-foreground: 26 83.3% 14.1%;
|
||||
--secondary: 60 4.8% 95.9%;
|
||||
--secondary-foreground: 24 9.8% 10%;
|
||||
--muted: 60 4.8% 95.9%;
|
||||
--muted-foreground: 25 5.3% 44.7%;
|
||||
--accent: 60 4.8% 95.9%;
|
||||
--accent-foreground: 24 9.8% 10%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 60 9.1% 97.8%;
|
||||
--border: 20 5.9% 90%;
|
||||
--input: 20 5.9% 90%;
|
||||
--ring: 20 14.3% 4.1%;
|
||||
--radius: 0.5rem;
|
||||
--chart-1: 12 76% 61%;
|
||||
--chart-2: 173 58% 39%;
|
||||
--chart-3: 197 37% 24%;
|
||||
--chart-4: 43 74% 66%;
|
||||
--chart-5: 27 87% 67%;
|
||||
--sidebar-background: 0 0% 98%;
|
||||
--sidebar-foreground: 240 5.3% 26.1%;
|
||||
--sidebar-primary: 240 5.9% 10%;
|
||||
--sidebar-primary-foreground: 0 0% 98%;
|
||||
--sidebar-accent: 240 4.8% 95.9%;
|
||||
--sidebar-accent-foreground: 240 5.9% 10%;
|
||||
--sidebar-border: 220 13% 91%;
|
||||
|
||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 20 14.3% 4.1%;
|
||||
--foreground: 60 9.1% 97.8%;
|
||||
--card: 20 14.3% 4.1%;
|
||||
--card-foreground: 60 9.1% 97.8%;
|
||||
--popover: 20 14.3% 4.1%;
|
||||
--popover-foreground: 60 9.1% 97.8%;
|
||||
--primary: 47.9 95.8% 53.1%;
|
||||
--primary-foreground: 26 83.3% 14.1%;
|
||||
--secondary: 12 6.5% 15.1%;
|
||||
--secondary-foreground: 60 9.1% 97.8%;
|
||||
--muted: 12 6.5% 15.1%;
|
||||
--muted-foreground: 24 5.4% 63.9%;
|
||||
--accent: 12 6.5% 15.1%;
|
||||
--accent-foreground: 60 9.1% 97.8%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 60 9.1% 97.8%;
|
||||
--border: 12 6.5% 15.1%;
|
||||
--input: 12 6.5% 15.1%;
|
||||
--ring: 35.5 91.7% 32.9%;
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
--sidebar-background: 240 5.9% 10%;
|
||||
--sidebar-foreground: 240 4.8% 95.9%;
|
||||
--sidebar-primary: 224.3 76.3% 48%;
|
||||
--sidebar-primary-foreground: 0 0% 100%;
|
||||
--sidebar-accent: 240 3.7% 15.9%;
|
||||
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
||||
--sidebar-border: 240 3.7% 15.9%;
|
||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
color: var(--foreground);
|
||||
background: var(--background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@layer utilities {
|
||||
/* .no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none; !* IE and Edge *!
|
||||
scrollbar-width: none; !* Firefox *!
|
||||
}*/
|
||||
|
||||
.bw-app-catalog-collapse {
|
||||
@apply absolute scale-0 z-20
|
||||
}
|
||||
|
||||
.header-button {
|
||||
@apply cursor-pointer p-1 border border-transparent rounded-[2px];
|
||||
}
|
||||
.h1-bold {
|
||||
@apply font-bold text-2xl lg:text-3xl;
|
||||
}
|
||||
|
||||
.bw-layout-col-left {
|
||||
@apply flex-1 sm:w-7/12 md:w-5/12 xl:w-4/12 lg:flex-col
|
||||
}
|
||||
|
||||
.bw-layout-col-right {
|
||||
@apply sm:w-5/12 md:w-7/12 xl:w-8/12 flex-1 sm:flex-auto sm:pl-4 md:pl-7 xl:pl-9
|
||||
}
|
||||
|
||||
.bw-header-col-left {
|
||||
@apply w-[9/12] flex-auto
|
||||
}
|
||||
|
||||
.bw-header-col-right {
|
||||
@apply flex-grow-0 flex-shrink-0 md:basis-[272px]
|
||||
}
|
||||
|
||||
.bw-border-color {
|
||||
@apply border-brand-violet-100;
|
||||
}
|
||||
|
||||
.bw-separator-color {
|
||||
@apply bg-brand-violet-100;
|
||||
}
|
||||
}
|
||||
|
||||
.bw-dd-menu {
|
||||
/* since nested groupes are not supported we have to use
|
||||
regular css for the nested dropdowns
|
||||
*/
|
||||
li>ul { transform: translatex(100%) scale(0) }
|
||||
li:hover>ul { transform: translatex(101%) scale(1) }
|
||||
li > button svg { transform: rotate(-90deg) }
|
||||
li:hover > button svg { transform: rotate(-270deg) }
|
||||
|
||||
/* Below styles fake what can be achieved with the tailwind config
|
||||
you need to add the group-hover variant to scale and define your custom
|
||||
min width style.
|
||||
See https://codesandbox.io/s/tailwindcss-multilevel-dropdown-y91j7?file=/index.html
|
||||
for implementation with config file
|
||||
*/
|
||||
.group:hover .group-hover\:scale-100 { transform: scale(1) }
|
||||
.group:hover .group-hover\:-rotate-180 { transform: rotate(180deg) }
|
||||
}
|
||||
|
||||
|
||||
.jodit-wysiwyg > * {
|
||||
all: revert;
|
||||
color: #262626 !important;
|
||||
}
|
||||
|
||||
.jodit-wysiwyg {
|
||||
padding: 0 16px !important;
|
||||
/*font-family: Consolas, Monaco, sans-serif;*/
|
||||
|
||||
/*p {
|
||||
font-size: 17px !important;
|
||||
}*/
|
||||
}
|
||||
|
||||
#admin-bw-panel form {
|
||||
input {
|
||||
@apply bg-white outline-0 text-[16px] leading-none;
|
||||
}
|
||||
|
||||
[role="tablist"] {
|
||||
@apply bg-brand-violet ;
|
||||
|
||||
[data-state=active] {
|
||||
@apply bg-brand-yellow text-brand-violet;
|
||||
}
|
||||
[data-state=inactive] {
|
||||
@apply text-brand-yellow bg-brand-violet;
|
||||
}
|
||||
|
||||
/*@apply bg-brand-yellow-100;*/
|
||||
|
||||
/*[id$='trigger-uk' i][data-state=active] {
|
||||
@apply bg-brand-yellow-100;
|
||||
}
|
||||
[id$='trigger-ru' i][data-state=active] {
|
||||
@apply bg-brand-violet-100;
|
||||
}*/
|
||||
}
|
||||
|
||||
label{
|
||||
@apply uppercase text-brand-violet-950 flex items-center justify-between leading-none ml-1 mt-4;
|
||||
|
||||
}
|
||||
|
||||
#form-tab-uk label {
|
||||
&:after {
|
||||
content: ' ';
|
||||
display: inline-block;
|
||||
width: 18px;
|
||||
height: 0;
|
||||
border-top: solid #0066cc 6px;
|
||||
border-bottom: solid #ffcc00 6px;
|
||||
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,32 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import type {Metadata} from 'next'
|
||||
import {headers} from 'next/headers'
|
||||
import {ReactNode} from 'react'
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
import './globals.css'
|
||||
import {Toaster} from '@/components/ui/toaster'
|
||||
import {routing} from '@/i18n/routing'
|
||||
import {APP_DESCRIPTION, APP_NAME, APP_SLOGAN} from '@/lib/constants'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
title: {
|
||||
template: `%s | ${APP_NAME}`,
|
||||
default: `${APP_NAME}. ${APP_SLOGAN}`
|
||||
},
|
||||
description: APP_DESCRIPTION
|
||||
}
|
||||
|
||||
export default async function RootLayout({
|
||||
children
|
||||
}: Readonly<{children: ReactNode}>) {
|
||||
const headersList = await headers()
|
||||
const locale = headersList.get('x-site-locale') ?? routing.defaultLocale
|
||||
|
||||
return (
|
||||
<html lang={locale} suppressHydrationWarning>
|
||||
<body className='min-h-screen antialiased'>
|
||||
{children}
|
||||
<Toaster />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
||||
101
app/page.tsx
101
app/page.tsx
@@ -1,101 +0,0 @@
|
||||
import Image from "next/image";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
|
||||
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js logo"
|
||||
width={180}
|
||||
height={38}
|
||||
priority
|
||||
/>
|
||||
<ol className="list-inside list-decimal text-sm text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
|
||||
<li className="mb-2">
|
||||
Get started by editing{" "}
|
||||
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-semibold">
|
||||
app/page.tsx
|
||||
</code>
|
||||
.
|
||||
</li>
|
||||
<li>Save and see your changes instantly.</li>
|
||||
</ol>
|
||||
|
||||
<div className="flex gap-4 items-center flex-col sm:flex-row">
|
||||
<a
|
||||
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5"
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/vercel.svg"
|
||||
alt="Vercel logomark"
|
||||
width={20}
|
||||
height={20}
|
||||
/>
|
||||
Deploy now
|
||||
</a>
|
||||
<a
|
||||
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44"
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Read our docs
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
<footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center">
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/file.svg"
|
||||
alt="File icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Learn
|
||||
</a>
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/window.svg"
|
||||
alt="Window icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Examples
|
||||
</a>
|
||||
<a
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
aria-hidden
|
||||
src="/globe.svg"
|
||||
alt="Globe icon"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Go to nextjs.org →
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user