forked from schulze/bam
		
	basic site
This commit is contained in:
		
							
								
								
									
										3
									
								
								.eslintrc.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.eslintrc.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
{
 | 
			
		||||
  "extends": "next/core-web-vitals"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								.gitea/workflows/lint.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								.gitea/workflows/lint.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
name: Lint
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  pull_request:
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
      - "**" # matches every branch
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  eslint:
 | 
			
		||||
    name: Lint
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
 | 
			
		||||
 | 
			
		||||
      - uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
 | 
			
		||||
        with:
 | 
			
		||||
          node-version: 20
 | 
			
		||||
          cache: "npm"
 | 
			
		||||
      - run: npm i
 | 
			
		||||
      - uses: sibiraj-s/action-eslint@bcf41bb9abce43cdbad51ab9b3da2eddaa17eab3 # v3.0.1
 | 
			
		||||
        with:
 | 
			
		||||
          eslint-args: "--ignore-path=.gitignore --quiet"
 | 
			
		||||
          extensions: "js,jsx,ts,tsx"
 | 
			
		||||
          annotations: true
 | 
			
		||||
          all-files: true
 | 
			
		||||
							
								
								
									
										33
									
								
								.gitea/workflows/sonarqube.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								.gitea/workflows/sonarqube.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches:
 | 
			
		||||
      - main
 | 
			
		||||
      - dev
 | 
			
		||||
      - "!renovate/**"
 | 
			
		||||
  pull_request:
 | 
			
		||||
    types: [opened, synchronize, reopened]
 | 
			
		||||
 | 
			
		||||
name: SonarQube Scan
 | 
			
		||||
jobs:
 | 
			
		||||
  sonarqube:
 | 
			
		||||
    name: SonarQube Trigger
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checking out
 | 
			
		||||
        uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4
 | 
			
		||||
        with:
 | 
			
		||||
          # Disabling shallow clone is recommended for improving relevancy of reporting
 | 
			
		||||
          fetch-depth: 0
 | 
			
		||||
      - name: SonarQube Scan
 | 
			
		||||
        uses: SonarSource/sonarqube-scan-action@884b79409bbd464b2a59edc326a4b77dc56b2195 # v3.0.0
 | 
			
		||||
        env:
 | 
			
		||||
          SONAR_HOST_URL: ${{ secrets.SONARQUBE_HOST }}
 | 
			
		||||
          SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
 | 
			
		||||
 | 
			
		||||
      # Check the Quality Gate status.
 | 
			
		||||
      - name: SonarQube Quality Gate check
 | 
			
		||||
        uses: sonarsource/sonarqube-quality-gate-action@master
 | 
			
		||||
        timeout-minutes: 2
 | 
			
		||||
        env:
 | 
			
		||||
          SONAR_HOST_URL: ${{ secrets.SONARQUBE_HOST }}
 | 
			
		||||
          SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
 | 
			
		||||
							
								
								
									
										36
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
 | 
			
		||||
 | 
			
		||||
# dependencies
 | 
			
		||||
/node_modules
 | 
			
		||||
/.pnp
 | 
			
		||||
.pnp.js
 | 
			
		||||
.yarn/install-state.gz
 | 
			
		||||
 | 
			
		||||
# testing
 | 
			
		||||
/coverage
 | 
			
		||||
 | 
			
		||||
# next.js
 | 
			
		||||
/.next/
 | 
			
		||||
/out/
 | 
			
		||||
 | 
			
		||||
# production
 | 
			
		||||
/build
 | 
			
		||||
 | 
			
		||||
# misc
 | 
			
		||||
.DS_Store
 | 
			
		||||
*.pem
 | 
			
		||||
 | 
			
		||||
# debug
 | 
			
		||||
npm-debug.log*
 | 
			
		||||
yarn-debug.log*
 | 
			
		||||
yarn-error.log*
 | 
			
		||||
 | 
			
		||||
# local env files
 | 
			
		||||
.env*.local
 | 
			
		||||
 | 
			
		||||
# vercel
 | 
			
		||||
.vercel
 | 
			
		||||
 | 
			
		||||
# typescript
 | 
			
		||||
*.tsbuildinfo
 | 
			
		||||
next-env.d.ts
 | 
			
		||||
							
								
								
									
										6
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "sonarlint.connectedMode.project": {
 | 
			
		||||
    "connectionId": "https-sonarqube-schulze-network",
 | 
			
		||||
    "projectKey": "bangersandmashgbg.com"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										88
									
								
								app/globals.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								app/globals.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
@tailwind base;
 | 
			
		||||
@tailwind components;
 | 
			
		||||
@tailwind utilities;
 | 
			
		||||
 | 
			
		||||
:root {
 | 
			
		||||
  --foreground-rgb: 0, 0, 0;
 | 
			
		||||
  --background-start-rgb: 214, 219, 220;
 | 
			
		||||
  --background-end-rgb: 255, 255, 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (prefers-color-scheme: dark) {
 | 
			
		||||
  :root {
 | 
			
		||||
    --foreground-rgb: 255, 255, 255;
 | 
			
		||||
    --background-start-rgb: 0, 0, 0;
 | 
			
		||||
    --background-end-rgb: 0, 0, 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@layer utilities {
 | 
			
		||||
  .text-balance {
 | 
			
		||||
    text-wrap: balance;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@layer base {
 | 
			
		||||
  :root {
 | 
			
		||||
    --background: 0 0% 100%;
 | 
			
		||||
    --foreground: 240 10% 3.9%;
 | 
			
		||||
    --card: 0 0% 100%;
 | 
			
		||||
    --card-foreground: 240 10% 3.9%;
 | 
			
		||||
    --popover: 0 0% 100%;
 | 
			
		||||
    --popover-foreground: 240 10% 3.9%;
 | 
			
		||||
    --primary: 240 5.9% 10%;
 | 
			
		||||
    --primary-foreground: 0 0% 98%;
 | 
			
		||||
    --secondary: 240 4.8% 95.9%;
 | 
			
		||||
    --secondary-foreground: 240 5.9% 10%;
 | 
			
		||||
    --muted: 240 4.8% 95.9%;
 | 
			
		||||
    --muted-foreground: 240 3.8% 46.1%;
 | 
			
		||||
    --accent: 240 4.8% 95.9%;
 | 
			
		||||
    --accent-foreground: 240 5.9% 10%;
 | 
			
		||||
    --destructive: 0 84.2% 60.2%;
 | 
			
		||||
    --destructive-foreground: 0 0% 98%;
 | 
			
		||||
    --border: 240 5.9% 90%;
 | 
			
		||||
    --input: 240 5.9% 90%;
 | 
			
		||||
    --ring: 240 10% 3.9%;
 | 
			
		||||
    --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%;
 | 
			
		||||
    --radius: 0.5rem;
 | 
			
		||||
  }
 | 
			
		||||
  .dark {
 | 
			
		||||
    --background: 240 10% 3.9%;
 | 
			
		||||
    --foreground: 0 0% 98%;
 | 
			
		||||
    --card: 240 10% 3.9%;
 | 
			
		||||
    --card-foreground: 0 0% 98%;
 | 
			
		||||
    --popover: 240 10% 3.9%;
 | 
			
		||||
    --popover-foreground: 0 0% 98%;
 | 
			
		||||
    --primary: 0 0% 98%;
 | 
			
		||||
    --primary-foreground: 240 5.9% 10%;
 | 
			
		||||
    --secondary: 240 3.7% 15.9%;
 | 
			
		||||
    --secondary-foreground: 0 0% 98%;
 | 
			
		||||
    --muted: 240 3.7% 15.9%;
 | 
			
		||||
    --muted-foreground: 240 5% 64.9%;
 | 
			
		||||
    --accent: 240 3.7% 15.9%;
 | 
			
		||||
    --accent-foreground: 0 0% 98%;
 | 
			
		||||
    --destructive: 0 62.8% 30.6%;
 | 
			
		||||
    --destructive-foreground: 0 0% 98%;
 | 
			
		||||
    --border: 240 3.7% 15.9%;
 | 
			
		||||
    --input: 240 3.7% 15.9%;
 | 
			
		||||
    --ring: 240 4.9% 83.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%;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@layer base {
 | 
			
		||||
  * {
 | 
			
		||||
    @apply border-border;
 | 
			
		||||
  }
 | 
			
		||||
  body {
 | 
			
		||||
    @apply bg-background text-foreground;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								app/layout.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								app/layout.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
import type { Metadata, Viewport } from "next";
 | 
			
		||||
import { Inter } from "next/font/google";
 | 
			
		||||
import PlausibleProvider from "next-plausible";
 | 
			
		||||
import "./globals.css";
 | 
			
		||||
import { cn } from "@/lib/utils";
 | 
			
		||||
 | 
			
		||||
const inter = Inter({ subsets: ["latin"], variable: "--font-sans" });
 | 
			
		||||
 | 
			
		||||
export const viewport: Viewport = {
 | 
			
		||||
  colorScheme: "dark",
 | 
			
		||||
};
 | 
			
		||||
export const metadata: Metadata = {
 | 
			
		||||
  title: "Bangers and Mash GBG",
 | 
			
		||||
  description: "Sign up to the Bangers and Mash GBG guest list",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default function RootLayout({
 | 
			
		||||
  children,
 | 
			
		||||
}: Readonly<{
 | 
			
		||||
  children: React.ReactNode;
 | 
			
		||||
}>) {
 | 
			
		||||
  return (
 | 
			
		||||
    <html lang="en" className="scroll-smooth">
 | 
			
		||||
      <head>
 | 
			
		||||
        <PlausibleProvider
 | 
			
		||||
          domain="bangersandmashgbg.com"
 | 
			
		||||
          customDomain="https://analytics.schulze.network"
 | 
			
		||||
          selfHosted={true}
 | 
			
		||||
          enabled={true}
 | 
			
		||||
          trackOutboundLinks={true}
 | 
			
		||||
        />
 | 
			
		||||
      </head>
 | 
			
		||||
      <body className={cn("min-h-screen bg-background font-sans antialiased", inter.variable)}>
 | 
			
		||||
        {children}
 | 
			
		||||
      </body>
 | 
			
		||||
    </html>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								app/page.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								app/page.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
export default function Home() {
 | 
			
		||||
  return (
 | 
			
		||||
    <form
 | 
			
		||||
      method="post"
 | 
			
		||||
      action="https://listmonk.schulze.network/subscription/form"
 | 
			
		||||
      className="listmonk-form"
 | 
			
		||||
    >
 | 
			
		||||
      <div>
 | 
			
		||||
        <h3>Subscribe</h3>
 | 
			
		||||
        <input type="hidden" name="nonce" />
 | 
			
		||||
        <p>
 | 
			
		||||
          <input type="email" name="email" required placeholder="E-post" />
 | 
			
		||||
        </p>
 | 
			
		||||
        <p>
 | 
			
		||||
          <input type="text" name="name" placeholder="Namn (ej obligatorisk)" />
 | 
			
		||||
        </p>
 | 
			
		||||
 | 
			
		||||
        <p>
 | 
			
		||||
          <input
 | 
			
		||||
            id="c99ab"
 | 
			
		||||
            type="checkbox"
 | 
			
		||||
            name="l"
 | 
			
		||||
            checked
 | 
			
		||||
            value="c99ab65c-cd0a-4ccc-ba63-0c9f7de99ac3"
 | 
			
		||||
          />
 | 
			
		||||
          <label htmlFor="c99ab">Produktnyheter</label>
 | 
			
		||||
          <br />
 | 
			
		||||
          <span>Produktnyheter för Schulze Network</span>
 | 
			
		||||
        </p>
 | 
			
		||||
 | 
			
		||||
        <p>
 | 
			
		||||
          <input type="submit" value="Prenumerera" />
 | 
			
		||||
        </p>
 | 
			
		||||
      </div>
 | 
			
		||||
    </form>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								components.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								components.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
{
 | 
			
		||||
  "$schema": "https://ui.shadcn.com/schema.json",
 | 
			
		||||
  "style": "default",
 | 
			
		||||
  "rsc": true,
 | 
			
		||||
  "tsx": true,
 | 
			
		||||
  "tailwind": {
 | 
			
		||||
    "config": "tailwind.config.ts",
 | 
			
		||||
    "css": "app/globals.css",
 | 
			
		||||
    "baseColor": "zinc",
 | 
			
		||||
    "cssVariables": true,
 | 
			
		||||
    "prefix": ""
 | 
			
		||||
  },
 | 
			
		||||
  "aliases": {
 | 
			
		||||
    "components": "@/components",
 | 
			
		||||
    "utils": "@/lib/utils",
 | 
			
		||||
    "ui": "@/components/ui",
 | 
			
		||||
    "lib": "@/lib",
 | 
			
		||||
    "hooks": "@/hooks"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										56
									
								
								components/ui/button.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								components/ui/button.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
import * as React from "react"
 | 
			
		||||
import { Slot } from "@radix-ui/react-slot"
 | 
			
		||||
import { cva, type VariantProps } from "class-variance-authority"
 | 
			
		||||
 | 
			
		||||
import { cn } from "@/lib/utils"
 | 
			
		||||
 | 
			
		||||
const buttonVariants = cva(
 | 
			
		||||
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
 | 
			
		||||
  {
 | 
			
		||||
    variants: {
 | 
			
		||||
      variant: {
 | 
			
		||||
        default: "bg-primary text-primary-foreground hover:bg-primary/90",
 | 
			
		||||
        destructive:
 | 
			
		||||
          "bg-destructive text-destructive-foreground hover:bg-destructive/90",
 | 
			
		||||
        outline:
 | 
			
		||||
          "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
 | 
			
		||||
        secondary:
 | 
			
		||||
          "bg-secondary text-secondary-foreground hover:bg-secondary/80",
 | 
			
		||||
        ghost: "hover:bg-accent hover:text-accent-foreground",
 | 
			
		||||
        link: "text-primary underline-offset-4 hover:underline",
 | 
			
		||||
      },
 | 
			
		||||
      size: {
 | 
			
		||||
        default: "h-10 px-4 py-2",
 | 
			
		||||
        sm: "h-9 rounded-md px-3",
 | 
			
		||||
        lg: "h-11 rounded-md px-8",
 | 
			
		||||
        icon: "h-10 w-10",
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    defaultVariants: {
 | 
			
		||||
      variant: "default",
 | 
			
		||||
      size: "default",
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
export interface ButtonProps
 | 
			
		||||
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
 | 
			
		||||
    VariantProps<typeof buttonVariants> {
 | 
			
		||||
  asChild?: boolean
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
 | 
			
		||||
  ({ className, variant, size, asChild = false, ...props }, ref) => {
 | 
			
		||||
    const Comp = asChild ? Slot : "button"
 | 
			
		||||
    return (
 | 
			
		||||
      <Comp
 | 
			
		||||
        className={cn(buttonVariants({ variant, size, className }))}
 | 
			
		||||
        ref={ref}
 | 
			
		||||
        {...props}
 | 
			
		||||
      />
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
)
 | 
			
		||||
Button.displayName = "Button"
 | 
			
		||||
 | 
			
		||||
export { Button, buttonVariants }
 | 
			
		||||
							
								
								
									
										178
									
								
								components/ui/form.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								components/ui/form.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
			
		||||
"use client"
 | 
			
		||||
 | 
			
		||||
import * as React from "react"
 | 
			
		||||
import * as LabelPrimitive from "@radix-ui/react-label"
 | 
			
		||||
import { Slot } from "@radix-ui/react-slot"
 | 
			
		||||
import {
 | 
			
		||||
  Controller,
 | 
			
		||||
  ControllerProps,
 | 
			
		||||
  FieldPath,
 | 
			
		||||
  FieldValues,
 | 
			
		||||
  FormProvider,
 | 
			
		||||
  useFormContext,
 | 
			
		||||
} from "react-hook-form"
 | 
			
		||||
 | 
			
		||||
import { cn } from "@/lib/utils"
 | 
			
		||||
import { Label } from "@/components/ui/label"
 | 
			
		||||
 | 
			
		||||
const Form = FormProvider
 | 
			
		||||
 | 
			
		||||
type FormFieldContextValue<
 | 
			
		||||
  TFieldValues extends FieldValues = FieldValues,
 | 
			
		||||
  TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
 | 
			
		||||
> = {
 | 
			
		||||
  name: TName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const FormFieldContext = React.createContext<FormFieldContextValue>(
 | 
			
		||||
  {} as FormFieldContextValue
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const FormField = <
 | 
			
		||||
  TFieldValues extends FieldValues = FieldValues,
 | 
			
		||||
  TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
 | 
			
		||||
>({
 | 
			
		||||
  ...props
 | 
			
		||||
}: ControllerProps<TFieldValues, TName>) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <FormFieldContext.Provider value={{ name: props.name }}>
 | 
			
		||||
      <Controller {...props} />
 | 
			
		||||
    </FormFieldContext.Provider>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const useFormField = () => {
 | 
			
		||||
  const fieldContext = React.useContext(FormFieldContext)
 | 
			
		||||
  const itemContext = React.useContext(FormItemContext)
 | 
			
		||||
  const { getFieldState, formState } = useFormContext()
 | 
			
		||||
 | 
			
		||||
  const fieldState = getFieldState(fieldContext.name, formState)
 | 
			
		||||
 | 
			
		||||
  if (!fieldContext) {
 | 
			
		||||
    throw new Error("useFormField should be used within <FormField>")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const { id } = itemContext
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    id,
 | 
			
		||||
    name: fieldContext.name,
 | 
			
		||||
    formItemId: `${id}-form-item`,
 | 
			
		||||
    formDescriptionId: `${id}-form-item-description`,
 | 
			
		||||
    formMessageId: `${id}-form-item-message`,
 | 
			
		||||
    ...fieldState,
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FormItemContextValue = {
 | 
			
		||||
  id: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const FormItemContext = React.createContext<FormItemContextValue>(
 | 
			
		||||
  {} as FormItemContextValue
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const FormItem = React.forwardRef<
 | 
			
		||||
  HTMLDivElement,
 | 
			
		||||
  React.HTMLAttributes<HTMLDivElement>
 | 
			
		||||
>(({ className, ...props }, ref) => {
 | 
			
		||||
  const id = React.useId()
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <FormItemContext.Provider value={{ id }}>
 | 
			
		||||
      <div ref={ref} className={cn("space-y-2", className)} {...props} />
 | 
			
		||||
    </FormItemContext.Provider>
 | 
			
		||||
  )
 | 
			
		||||
})
 | 
			
		||||
FormItem.displayName = "FormItem"
 | 
			
		||||
 | 
			
		||||
const FormLabel = React.forwardRef<
 | 
			
		||||
  React.ElementRef<typeof LabelPrimitive.Root>,
 | 
			
		||||
  React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
 | 
			
		||||
>(({ className, ...props }, ref) => {
 | 
			
		||||
  const { error, formItemId } = useFormField()
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Label
 | 
			
		||||
      ref={ref}
 | 
			
		||||
      className={cn(error && "text-destructive", className)}
 | 
			
		||||
      htmlFor={formItemId}
 | 
			
		||||
      {...props}
 | 
			
		||||
    />
 | 
			
		||||
  )
 | 
			
		||||
})
 | 
			
		||||
FormLabel.displayName = "FormLabel"
 | 
			
		||||
 | 
			
		||||
const FormControl = React.forwardRef<
 | 
			
		||||
  React.ElementRef<typeof Slot>,
 | 
			
		||||
  React.ComponentPropsWithoutRef<typeof Slot>
 | 
			
		||||
>(({ ...props }, ref) => {
 | 
			
		||||
  const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Slot
 | 
			
		||||
      ref={ref}
 | 
			
		||||
      id={formItemId}
 | 
			
		||||
      aria-describedby={
 | 
			
		||||
        !error
 | 
			
		||||
          ? `${formDescriptionId}`
 | 
			
		||||
          : `${formDescriptionId} ${formMessageId}`
 | 
			
		||||
      }
 | 
			
		||||
      aria-invalid={!!error}
 | 
			
		||||
      {...props}
 | 
			
		||||
    />
 | 
			
		||||
  )
 | 
			
		||||
})
 | 
			
		||||
FormControl.displayName = "FormControl"
 | 
			
		||||
 | 
			
		||||
const FormDescription = React.forwardRef<
 | 
			
		||||
  HTMLParagraphElement,
 | 
			
		||||
  React.HTMLAttributes<HTMLParagraphElement>
 | 
			
		||||
>(({ className, ...props }, ref) => {
 | 
			
		||||
  const { formDescriptionId } = useFormField()
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <p
 | 
			
		||||
      ref={ref}
 | 
			
		||||
      id={formDescriptionId}
 | 
			
		||||
      className={cn("text-sm text-muted-foreground", className)}
 | 
			
		||||
      {...props}
 | 
			
		||||
    />
 | 
			
		||||
  )
 | 
			
		||||
})
 | 
			
		||||
FormDescription.displayName = "FormDescription"
 | 
			
		||||
 | 
			
		||||
const FormMessage = React.forwardRef<
 | 
			
		||||
  HTMLParagraphElement,
 | 
			
		||||
  React.HTMLAttributes<HTMLParagraphElement>
 | 
			
		||||
>(({ className, children, ...props }, ref) => {
 | 
			
		||||
  const { error, formMessageId } = useFormField()
 | 
			
		||||
  const body = error ? String(error?.message) : children
 | 
			
		||||
 | 
			
		||||
  if (!body) {
 | 
			
		||||
    return null
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <p
 | 
			
		||||
      ref={ref}
 | 
			
		||||
      id={formMessageId}
 | 
			
		||||
      className={cn("text-sm font-medium text-destructive", className)}
 | 
			
		||||
      {...props}
 | 
			
		||||
    >
 | 
			
		||||
      {body}
 | 
			
		||||
    </p>
 | 
			
		||||
  )
 | 
			
		||||
})
 | 
			
		||||
FormMessage.displayName = "FormMessage"
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
  useFormField,
 | 
			
		||||
  Form,
 | 
			
		||||
  FormItem,
 | 
			
		||||
  FormLabel,
 | 
			
		||||
  FormControl,
 | 
			
		||||
  FormDescription,
 | 
			
		||||
  FormMessage,
 | 
			
		||||
  FormField,
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								components/ui/label.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								components/ui/label.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
"use client"
 | 
			
		||||
 | 
			
		||||
import * as React from "react"
 | 
			
		||||
import * as LabelPrimitive from "@radix-ui/react-label"
 | 
			
		||||
import { cva, type VariantProps } from "class-variance-authority"
 | 
			
		||||
 | 
			
		||||
import { cn } from "@/lib/utils"
 | 
			
		||||
 | 
			
		||||
const labelVariants = cva(
 | 
			
		||||
  "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const Label = React.forwardRef<
 | 
			
		||||
  React.ElementRef<typeof LabelPrimitive.Root>,
 | 
			
		||||
  React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
 | 
			
		||||
    VariantProps<typeof labelVariants>
 | 
			
		||||
>(({ className, ...props }, ref) => (
 | 
			
		||||
  <LabelPrimitive.Root
 | 
			
		||||
    ref={ref}
 | 
			
		||||
    className={cn(labelVariants(), className)}
 | 
			
		||||
    {...props}
 | 
			
		||||
  />
 | 
			
		||||
))
 | 
			
		||||
Label.displayName = LabelPrimitive.Root.displayName
 | 
			
		||||
 | 
			
		||||
export { Label }
 | 
			
		||||
							
								
								
									
										6
									
								
								lib/utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								lib/utils.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
import { clsx, type ClassValue } from "clsx"
 | 
			
		||||
import { twMerge } from "tailwind-merge"
 | 
			
		||||
 | 
			
		||||
export function cn(...inputs: ClassValue[]) {
 | 
			
		||||
  return twMerge(clsx(inputs))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4
									
								
								next.config.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								next.config.mjs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
/** @type {import('next').NextConfig} */
 | 
			
		||||
const nextConfig = {};
 | 
			
		||||
 | 
			
		||||
export default nextConfig;
 | 
			
		||||
							
								
								
									
										8250
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										8250
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										43
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "bam",
 | 
			
		||||
  "version": "0.1.0",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "dev": "next dev --turbo",
 | 
			
		||||
    "build": "next build",
 | 
			
		||||
    "start": "next start",
 | 
			
		||||
    "lint": "next lint"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@hookform/resolvers": "^3.9.0",
 | 
			
		||||
    "@radix-ui/react-label": "^2.1.0",
 | 
			
		||||
    "@radix-ui/react-slot": "^1.1.0",
 | 
			
		||||
    "autoprefixer": "^10.4.19",
 | 
			
		||||
    "class-variance-authority": "^0.7.0",
 | 
			
		||||
    "clsx": "^2.1.1",
 | 
			
		||||
    "cssnano": "^7.0.1",
 | 
			
		||||
    "lucide-react": "^0.452.0",
 | 
			
		||||
    "next": "14.2.15",
 | 
			
		||||
    "next-plausible": "^3.12.0",
 | 
			
		||||
    "postcss-flexbugs-fixes": "^5.0.2",
 | 
			
		||||
    "postcss-preset-env": "^10.0.0",
 | 
			
		||||
    "react": "^18",
 | 
			
		||||
    "react-dom": "^18",
 | 
			
		||||
    "react-hook-form": "^7.53.0",
 | 
			
		||||
    "sharp": "^0.33.4",
 | 
			
		||||
    "tailwind-merge": "^2.5.2",
 | 
			
		||||
    "tailwindcss-animate": "^1.0.7",
 | 
			
		||||
    "zod": "^3.23.8"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@types/node": "20.16.11",
 | 
			
		||||
    "@types/react": "18.3.11",
 | 
			
		||||
    "@types/react-dom": "18.3.1",
 | 
			
		||||
    "eslint": "8.57.1",
 | 
			
		||||
    "eslint-config-next": "14.2.15",
 | 
			
		||||
    "postcss": "8.4.47",
 | 
			
		||||
    "tailwindcss": "3.4.13",
 | 
			
		||||
    "turbo": "2.1.3",
 | 
			
		||||
    "typescript": "5.6.3"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								postcss.config.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								postcss.config.mjs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
/** @type {import('postcss-load-config').Config} */
 | 
			
		||||
const config = {
 | 
			
		||||
  plugins: {
 | 
			
		||||
    tailwindcss: {},
 | 
			
		||||
 | 
			
		||||
    autoprefixer: {},
 | 
			
		||||
    "postcss-flexbugs-fixes": {
 | 
			
		||||
      "postcss-preset-env": {
 | 
			
		||||
        autoprefixer: {
 | 
			
		||||
          flexbox: "no-2009",
 | 
			
		||||
        },
 | 
			
		||||
        stage: 3,
 | 
			
		||||
        features: {
 | 
			
		||||
          "custom-properties": false,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      "@fullhuman/postcss-purgecss": {
 | 
			
		||||
        content: [
 | 
			
		||||
          "./pages/**/*.{js,jsx,ts,tsx}",
 | 
			
		||||
          "./components/**/*.{js,jsx,ts,tsx}",
 | 
			
		||||
        ],
 | 
			
		||||
        defaultExtractor: (content) => content.match(/[\w-/:]+(?<!:)/g) || [],
 | 
			
		||||
        safelist: ["html", "body"],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    cssnano: {},
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default config;
 | 
			
		||||
							
								
								
									
										11
									
								
								renovate.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								renovate.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
{
 | 
			
		||||
  "extends": ["config:best-practices", ":semanticCommits"],
 | 
			
		||||
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
 | 
			
		||||
  "packageRules": [
 | 
			
		||||
    {
 | 
			
		||||
      "matchUpdateTypes": ["minor", "patch", "pin", "digest"],
 | 
			
		||||
      "automerge": true,
 | 
			
		||||
      "automergeType": "branch"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								sonar-project.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								sonar-project.properties
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
sonar.projectKey=bangersandmashgbg.com
 | 
			
		||||
 | 
			
		||||
# relative paths to source directories. More details and properties are described
 | 
			
		||||
# at https://docs.sonarqube.org/latest/project-administration/narrowing-the-focus/ 
 | 
			
		||||
sonar.sources=. 
 | 
			
		||||
							
								
								
									
										70
									
								
								tailwind.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								tailwind.config.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
import type { Config } from "tailwindcss";
 | 
			
		||||
 | 
			
		||||
const config: Config = {
 | 
			
		||||
    darkMode: ["class"],
 | 
			
		||||
    content: [
 | 
			
		||||
    "./lib/**/*.{ts,tsx,js,jsx}",
 | 
			
		||||
    "./components/**/*.{js,ts,jsx,tsx,mdx}",
 | 
			
		||||
    "./app/**/*.{js,ts,jsx,tsx,mdx}",
 | 
			
		||||
  ],
 | 
			
		||||
  theme: {
 | 
			
		||||
  	extend: {
 | 
			
		||||
  		fontFamily: {
 | 
			
		||||
  			sans: ["var(--font-sans)"]
 | 
			
		||||
  		},
 | 
			
		||||
  		backgroundImage: {
 | 
			
		||||
  			'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
 | 
			
		||||
  			'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))'
 | 
			
		||||
  		},
 | 
			
		||||
  		borderRadius: {
 | 
			
		||||
  			lg: 'var(--radius)',
 | 
			
		||||
  			md: 'calc(var(--radius) - 2px)',
 | 
			
		||||
  			sm: 'calc(var(--radius) - 4px)'
 | 
			
		||||
  		},
 | 
			
		||||
  		colors: {
 | 
			
		||||
  			background: 'hsl(var(--background))',
 | 
			
		||||
  			foreground: 'hsl(var(--foreground))',
 | 
			
		||||
  			card: {
 | 
			
		||||
  				DEFAULT: 'hsl(var(--card))',
 | 
			
		||||
  				foreground: 'hsl(var(--card-foreground))'
 | 
			
		||||
  			},
 | 
			
		||||
  			popover: {
 | 
			
		||||
  				DEFAULT: 'hsl(var(--popover))',
 | 
			
		||||
  				foreground: 'hsl(var(--popover-foreground))'
 | 
			
		||||
  			},
 | 
			
		||||
  			primary: {
 | 
			
		||||
  				DEFAULT: 'hsl(var(--primary))',
 | 
			
		||||
  				foreground: 'hsl(var(--primary-foreground))'
 | 
			
		||||
  			},
 | 
			
		||||
  			secondary: {
 | 
			
		||||
  				DEFAULT: 'hsl(var(--secondary))',
 | 
			
		||||
  				foreground: 'hsl(var(--secondary-foreground))'
 | 
			
		||||
  			},
 | 
			
		||||
  			muted: {
 | 
			
		||||
  				DEFAULT: 'hsl(var(--muted))',
 | 
			
		||||
  				foreground: 'hsl(var(--muted-foreground))'
 | 
			
		||||
  			},
 | 
			
		||||
  			accent: {
 | 
			
		||||
  				DEFAULT: 'hsl(var(--accent))',
 | 
			
		||||
  				foreground: 'hsl(var(--accent-foreground))'
 | 
			
		||||
  			},
 | 
			
		||||
  			destructive: {
 | 
			
		||||
  				DEFAULT: 'hsl(var(--destructive))',
 | 
			
		||||
  				foreground: 'hsl(var(--destructive-foreground))'
 | 
			
		||||
  			},
 | 
			
		||||
  			border: 'hsl(var(--border))',
 | 
			
		||||
  			input: 'hsl(var(--input))',
 | 
			
		||||
  			ring: 'hsl(var(--ring))',
 | 
			
		||||
  			chart: {
 | 
			
		||||
  				'1': 'hsl(var(--chart-1))',
 | 
			
		||||
  				'2': 'hsl(var(--chart-2))',
 | 
			
		||||
  				'3': 'hsl(var(--chart-3))',
 | 
			
		||||
  				'4': 'hsl(var(--chart-4))',
 | 
			
		||||
  				'5': 'hsl(var(--chart-5))'
 | 
			
		||||
  			}
 | 
			
		||||
  		}
 | 
			
		||||
  	}
 | 
			
		||||
  },
 | 
			
		||||
  plugins: [require("tailwindcss-animate")],
 | 
			
		||||
};
 | 
			
		||||
export default config;
 | 
			
		||||
							
								
								
									
										26
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
{
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "lib": ["dom", "dom.iterable", "esnext"],
 | 
			
		||||
    "allowJs": true,
 | 
			
		||||
    "skipLibCheck": true,
 | 
			
		||||
    "strict": true,
 | 
			
		||||
    "noEmit": true,
 | 
			
		||||
    "esModuleInterop": true,
 | 
			
		||||
    "module": "esnext",
 | 
			
		||||
    "moduleResolution": "bundler",
 | 
			
		||||
    "resolveJsonModule": true,
 | 
			
		||||
    "isolatedModules": true,
 | 
			
		||||
    "jsx": "preserve",
 | 
			
		||||
    "incremental": true,
 | 
			
		||||
    "plugins": [
 | 
			
		||||
      {
 | 
			
		||||
        "name": "next"
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "paths": {
 | 
			
		||||
      "@/*": ["./*"]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
 | 
			
		||||
  "exclude": ["node_modules"]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								turbo.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								turbo.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
{
 | 
			
		||||
  "$schema": "https://turbo.build/schema.json",
 | 
			
		||||
  "tasks": {
 | 
			
		||||
    "build": {
 | 
			
		||||
      "outputs": [
 | 
			
		||||
        ".next/**",
 | 
			
		||||
        "!.next/cache/**"
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    "type-check": {}
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user