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")],