diff --git a/README.md b/README.md index d463ed2..3c35ae9 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The architecture of this project revolves around a streamlined development and d - [x] Deploy the application to Vercel - [x] Add app configuration -- [ ] Setup home page +- [x] Add landing page - [ ] Add auth and more diff --git a/docker-compose.yml b/docker-compose.yml index b30aff7..c8f7db1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,7 +9,6 @@ services: - DATABASE_URL=postgresql://postgres:postgres@db:5432/byte volumes: - .:/app - - /app/node_modules depends_on: - db diff --git a/package.json b/package.json index d05ab19..520184f 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ }, "dependencies": { "@loglib/tracker": "^0.8.0", + "@radix-ui/react-slot": "^1.0.2", "@t3-oss/env-nextjs": "^0.10.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", @@ -28,6 +29,7 @@ "next-themes": "^0.3.0", "react": "^18", "react-dom": "^18", + "react-wrap-balancer": "^1.1.0", "tailwind-merge": "^2.3.0", "tailwindcss-animate": "^1.0.7", "zod": "^3.23.6" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d481221..f89aa86 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@loglib/tracker': specifier: ^0.8.0 version: 0.8.0(react@18.3.1) + '@radix-ui/react-slot': + specifier: ^1.0.2 + version: 1.0.2(@types/react@18.3.1)(react@18.3.1) '@t3-oss/env-nextjs': specifier: ^0.10.1 version: 0.10.1(typescript@5.4.5)(zod@3.23.6) @@ -38,6 +41,9 @@ importers: react-dom: specifier: ^18 version: 18.3.1(react@18.3.1) + react-wrap-balancer: + specifier: ^1.1.0 + version: 1.1.0(react@18.3.1) tailwind-merge: specifier: ^2.3.0 version: 2.3.0 @@ -342,6 +348,24 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@radix-ui/react-compose-refs@1.0.1': + resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-slot@1.0.2': + resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@rushstack/eslint-patch@1.10.2': resolution: {integrity: sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==} @@ -1618,6 +1642,11 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-wrap-balancer@1.1.0: + resolution: {integrity: sha512-EhF3jOZm5Fjx+Cx41e423qOv2c2aOvXAtym2OHqrGeMUnwERIyNsRBgnfT3plB170JmuYvts8K2KSPEIerKr5A==} + peerDependencies: + react: '>=16.8.0 || ^17.0.0 || ^18' + react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -2209,6 +2238,21 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.1)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.24.4 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.1 + + '@radix-ui/react-slot@1.0.2(@types/react@18.3.1)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.1)(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.1 + '@rushstack/eslint-patch@1.10.2': {} '@swc/counter@0.1.3': {} @@ -3626,6 +3670,10 @@ snapshots: react-is@16.13.1: {} + react-wrap-balancer@1.1.0(react@18.3.1): + dependencies: + react: 18.3.1 + react@18.3.1: dependencies: loose-envify: 1.4.0 diff --git a/public/images/dot.svg b/public/images/dot.svg new file mode 100644 index 0000000..e1ae378 --- /dev/null +++ b/public/images/dot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/(landing)/layout.tsx b/src/app/(landing)/layout.tsx new file mode 100644 index 0000000..7bfe23f --- /dev/null +++ b/src/app/(landing)/layout.tsx @@ -0,0 +1,7 @@ +export default function LandingLayout({ children }: React.PropsWithChildren) { + return ( +
+
{children}
+
+ ) +} diff --git a/src/app/(landing)/page.tsx b/src/app/(landing)/page.tsx new file mode 100644 index 0000000..30abb66 --- /dev/null +++ b/src/app/(landing)/page.tsx @@ -0,0 +1,66 @@ +import type { Viewport } from "next" +import Link from "next/link" +import Balancer from "react-wrap-balancer" + +import { siteConfig } from "@/config/site" +import { cn } from "@/lib/utils" +import { badgeVariants } from "@/components/ui/badge" +import { buttonVariants } from "@/components/ui/button" + +export const viewport: Viewport = { + colorScheme: "dark", +} + +export default function HomePage() { + return ( +
+
+ + + Star on Github + + -> + + + +

+ One Platform for Virtual Learning +

+ +

+ Plan, organize, and manage virtual workshop sessions +

+ + + Get Started + + -> + + +
+ ) +} diff --git a/src/app/page.tsx b/src/app/page.tsx deleted file mode 100644 index 3c7ec17..0000000 --- a/src/app/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function HomePage() { - return

Welcome to Byte

-} diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx new file mode 100644 index 0000000..f000e3e --- /dev/null +++ b/src/components/ui/badge.tsx @@ -0,0 +1,36 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", + secondary: + "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: + "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + outline: "text-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +export interface BadgeProps + extends React.HTMLAttributes, + VariantProps {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return ( +
+ ) +} + +export { Badge, badgeVariants } diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 0000000..0770266 --- /dev/null +++ b/src/components/ui/button.tsx @@ -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 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", + { + 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: "size-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button" + return ( + + ) + } +) +Button.displayName = "Button" + +export { Button, buttonVariants } diff --git a/src/config/site.ts b/src/config/site.ts index 2622cb5..a942e73 100644 --- a/src/config/site.ts +++ b/src/config/site.ts @@ -2,5 +2,5 @@ export const siteConfig = { title: "Byte", description: "A platform for developers to plan and manage virtual workshops", url: "https://byte.raphico.tech", - github: "https://github.com/raphico/byte", + githubLink: "https://github.com/raphico/byte", } diff --git a/tailwind.config.ts b/tailwind.config.ts index 024a4fe..c518976 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -60,6 +60,23 @@ const config = { sm: "calc(var(--radius) - 4px)", }, keyframes: { + /** + * Original source: + * @see https://github.com/juliusmarminge/acme-corp/blob/main/tooling/tailwind/index.ts + */ + "fade-up": { + "0%": { + opacity: "0", + transform: "translateY(10px)", + }, + "75%": { + opacity: "0.6", + }, + "100%": { + opacity: "1", + transform: "translateY(0)", + }, + }, "accordion-down": { from: { height: "0" }, to: { height: "var(--radix-accordion-content-height)" }, @@ -72,11 +89,15 @@ const config = { animation: { "accordion-down": "accordion-down 0.2s ease-out", "accordion-up": "accordion-up 0.2s ease-out", + "fade-up": "fade-up 0.5s", }, fontFamily: { sans: ["var(--font-geist-sans)", ...fontFamily.sans], heading: ["var(--font-heading)", ...fontFamily.sans], }, + backgroundImage: { + dot: "url('/images/dot.svg')", + }, }, }, plugins: [require("tailwindcss-animate")],