diff --git a/.eslintrc.json b/.eslintrc.json
index 3722418..33f6e02 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,3 +1,10 @@
{
- "extends": ["next/core-web-vitals", "next/typescript"]
+ "extends": [
+ "next/core-web-vitals",
+ "next/typescript"
+ ],
+ "rules": {
+ "@typescript-eslint/no-unused-vars": "off",
+ "@typescript-eslint/no-explicit-any": "off"
+ }
}
diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml
index b895836..c3d7767 100644
--- a/.gitea/workflows/deploy.yml
+++ b/.gitea/workflows/deploy.yml
@@ -1,4 +1,4 @@
-name: Deploy Site
+name: Deploy
on:
push:
@@ -9,7 +9,7 @@ on:
- docker-compose.yml
jobs:
- docker:
+ deploy:
strategy:
matrix:
arch: [ "ubuntu-latest" ]
@@ -28,5 +28,5 @@ jobs:
- name: Deploy to Dokku
uses: dokku/github-action@master
with:
- git_remote_url: "ssh://dokku@10.10.3.28:22/rainnny-club"
+ git_remote_url: "ssh://dokku@10.10.3.28:22/pulseapp-www"
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
diff --git a/.gitignore b/.gitignore
index fd3dbb5..acaf3a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,36 +1,13 @@
-# 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
+node_modules
+.idea/
+.vscode/
+.VSCodeCounter/
+.next/
.env*.local
-
-# vercel
-.vercel
-
-# typescript
-*.tsbuildinfo
next-env.d.ts
+.sentryclirc
+.env
+sw.*
+workbox-*
+swe-worker-*
+dist/
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index ac8aa26..50899a3 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -15,8 +15,6 @@ COPY --from=depends /usr/src/app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED 1
-RUN --mount=type=bind,target=/config,from=korben-splash cp /config/.env ./.env
-
RUN bun run build
@@ -35,7 +33,6 @@ COPY --from=builder --chown=nextjs:nextjs /usr/src/app/.next ./.next
COPY --from=builder --chown=nextjs:nextjs /usr/src/app/public ./public
COPY --from=builder --chown=nextjs:nextjs /usr/src/app/next.config.mjs ./next.config.mjs
COPY --from=builder --chown=nextjs:nextjs /usr/src/app/package.json ./package.json
-COPY --from=builder --chown=nextjs:nextjs /usr/src/app/.env ./.env
ENV NODE_ENV production
diff --git a/README.md b/README.md
index e69de29..6f8872e 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,3 @@
+# www
+
+The frontend for PulseApp.
\ No newline at end of file
diff --git a/bun.lockb b/bun.lockb
index 3bae941..54e9519 100644
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/next.config.mjs b/next.config.mjs
index 4678774..608f1be 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -1,4 +1,6 @@
/** @type {import('next').NextConfig} */
-const nextConfig = {};
+const nextConfig = {
+ output: "standalone",
+};
export default nextConfig;
diff --git a/package.json b/package.json
index b24cdd0..f906e7a 100644
--- a/package.json
+++ b/package.json
@@ -9,9 +9,18 @@
"lint": "next lint"
},
"dependencies": {
+ "@radix-ui/react-icons": "^1.3.0",
+ "@radix-ui/react-slot": "^1.1.0",
+ "class-variance-authority": "^0.7.0",
+ "clsx": "^2.1.1",
+ "lucide-react": "^0.441.0",
+ "next": "14.2.8",
+ "next-themes": "^0.3.0",
"react": "^18",
"react-dom": "^18",
- "next": "14.2.8"
+ "sharp": "^0.33.5",
+ "tailwind-merge": "^2.5.2",
+ "tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"typescript": "^5",
diff --git a/postcss.config.mjs b/postcss.config.mjs
index 1a69fd2..6f94347 100644
--- a/postcss.config.mjs
+++ b/postcss.config.mjs
@@ -1,8 +1,8 @@
/** @type {import('postcss-load-config').Config} */
const config = {
- plugins: {
- tailwindcss: {},
- },
+ plugins: {
+ tailwindcss: {},
+ },
};
export default config;
diff --git a/public/favicon.ico b/public/favicon.ico
index 718d6fe..009fca4 100644
Binary files a/public/favicon.ico and b/public/favicon.ico differ
diff --git a/src/app/(pages)/layout.tsx b/src/app/(pages)/layout.tsx
index a36cde0..ea2c22b 100644
--- a/src/app/(pages)/layout.tsx
+++ b/src/app/(pages)/layout.tsx
@@ -1,35 +1,56 @@
-import type { Metadata } from "next";
-import localFont from "next/font/local";
-import "./globals.css";
+import type { Metadata, Viewport } from "next";
+import { Inter } from "next/font/google";
+import "../style/globals.css";
+import { ReactElement, ReactNode } from "react";
+import { cn } from "@/lib/utils";
+import { NextFont } from "next/dist/compiled/@next/font";
+import { ThemeProvider } from "@/components/theme-provider";
-const geistSans = localFont({
- src: "./fonts/GeistVF.woff",
- variable: "--font-geist-sans",
- weight: "100 900",
-});
-const geistMono = localFont({
- src: "./fonts/GeistMonoVF.woff",
- variable: "--font-geist-mono",
- weight: "100 900",
-});
+const inter: NextFont = Inter({ subsets: ["latin"] });
+/**
+ * The metadata for this app.
+ */
export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
+ title: "PulseApp",
+ description:
+ "A lightweight service monitoring solution for tracking the availability of whatever service your heart desires!",
+ openGraph: {
+ images: [
+ {
+ url: "https://pulseapp.cc/logo.png",
+ width: 128,
+ height: 128,
+ },
+ ],
+ },
+ twitter: {
+ card: "summary",
+ },
+};
+export const viewport: Viewport = {
+ themeColor: "#DC2626",
};
-export default function RootLayout({
- children,
+/**
+ * The primary layout for this app.
+ */
+const RootLayout = ({
+ children,
}: Readonly<{
- children: React.ReactNode;
-}>) {
- return (
+ children: ReactNode;
+}>): ReactElement => (
-
- {children}
-
+
+
+ {children}
+
+
- );
-}
+);
+export default RootLayout;
diff --git a/src/app/(pages)/page.tsx b/src/app/(pages)/page.tsx
index 6fe62d1..e32a542 100644
--- a/src/app/(pages)/page.tsx
+++ b/src/app/(pages)/page.tsx
@@ -1,101 +1,9 @@
-import Image from "next/image";
+import { ReactElement } from "react";
+import Greeting from "@/components/landing/greeting";
-export default function Home() {
- return (
-
-
-
-
- -
- Get started by editing{" "}
-
- src/app/page.tsx
-
- .
-
- - Save and see your changes instantly.
-
-
-
-
-
-
- );
-}
+const LandingPage = (): ReactElement => (
+
+
+
+);
+export default LandingPage;
diff --git a/src/app/style/globals.css b/src/app/style/globals.css
index 13d40b8..f20e5ca 100644
--- a/src/app/style/globals.css
+++ b/src/app/style/globals.css
@@ -3,25 +3,92 @@
@tailwind utilities;
:root {
- --background: #ffffff;
- --foreground: #171717;
+ --background: #ffffff;
+ --foreground: #171717;
}
@media (prefers-color-scheme: dark) {
- :root {
- --background: #0a0a0a;
- --foreground: #ededed;
- }
+ :root {
+ --background: #0a0a0a;
+ --foreground: #ededed;
+ }
}
body {
- color: var(--foreground);
- background: var(--background);
- font-family: Arial, Helvetica, sans-serif;
+ color: var(--foreground);
+ background: var(--background);
+ font-family: Arial, Helvetica, sans-serif;
}
@layer utilities {
- .text-balance {
- text-wrap: balance;
- }
+ .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;
+ }
+}
\ No newline at end of file
diff --git a/src/components/landing/greeting.tsx b/src/components/landing/greeting.tsx
index e69de29..49c4706 100644
--- a/src/components/landing/greeting.tsx
+++ b/src/components/landing/greeting.tsx
@@ -0,0 +1,44 @@
+import { ReactElement } from "react";
+import Image from "next/image";
+import Link from "next/link";
+import { Button } from "@/components/ui/button";
+
+const Greeting = (): ReactElement => (
+
+
+ {/* Logo */}
+
+
+ {/* Greeting */}
+
Pulse App
+
+ A lightweight service monitoring solution for tracking the
+ availability of whatever service your heart desires!
+
+
Coming Soon...
+
+
+ {/* GitHub */}
+
+
+
+
+);
+export default Greeting;
diff --git a/src/components/theme-provider.tsx b/src/components/theme-provider.tsx
index e69de29..a95c5bc 100644
--- a/src/components/theme-provider.tsx
+++ b/src/components/theme-provider.tsx
@@ -0,0 +1,9 @@
+"use client";
+
+import * as React from "react";
+import { ThemeProvider as NextThemesProvider } from "next-themes";
+import { type ThemeProviderProps } from "next-themes/dist/types";
+
+export const ThemeProvider = ({ children, ...props }: ThemeProviderProps) => (
+ {children}
+);
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
index 0270f64..d401551 100644
--- a/src/components/ui/button.tsx
+++ b/src/components/ui/button.tsx
@@ -1,57 +1,57 @@
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { cva, type VariantProps } from "class-variance-authority"
+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"
+import { cn } from "@/lib/utils";
const buttonVariants = cva(
- "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
- {
- variants: {
- variant: {
- default:
- "bg-primary text-primary-foreground shadow hover:bg-primary/90",
- destructive:
- "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
- outline:
- "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
- secondary:
- "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
- ghost: "hover:bg-accent hover:text-accent-foreground",
- link: "text-primary underline-offset-4 hover:underline",
- },
- size: {
- default: "h-9 px-4 py-2",
- sm: "h-8 rounded-md px-3 text-xs",
- lg: "h-10 rounded-md px-8",
- icon: "h-9 w-9",
- },
- },
- defaultVariants: {
- variant: "default",
- size: "default",
- },
- }
-)
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
+ {
+ variants: {
+ variant: {
+ default:
+ "bg-primary text-primary-foreground shadow hover:bg-primary/90",
+ destructive:
+ "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
+ outline:
+ "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
+ secondary:
+ "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
+ ghost: "hover:bg-accent hover:text-accent-foreground",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ size: {
+ default: "h-9 px-4 py-2",
+ sm: "h-8 rounded-md px-3 text-xs",
+ lg: "h-10 rounded-md px-8",
+ icon: "h-9 w-9",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+);
export interface ButtonProps
- extends React.ButtonHTMLAttributes,
- VariantProps {
- asChild?: boolean
+ 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"
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
+ const Comp = asChild ? Slot : "button";
+ return (
+
+ );
+ }
+);
+Button.displayName = "Button";
-export { Button, buttonVariants }
+export { Button, buttonVariants };
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index bd0c391..e644794 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -1,6 +1,6 @@
-import { clsx, type ClassValue } from "clsx"
-import { twMerge } from "tailwind-merge"
+import { type ClassValue, clsx } from "clsx";
+import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
- return twMerge(clsx(inputs))
+ return twMerge(clsx(inputs));
}
diff --git a/tailwind.config.ts b/tailwind.config.ts
index 021c393..51403e2 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -1,19 +1,63 @@
import type { Config } from "tailwindcss";
const config: Config = {
- content: [
- "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
- "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
- "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
- ],
- theme: {
- extend: {
- colors: {
- background: "var(--background)",
- foreground: "var(--foreground)",
- },
+ darkMode: ["class"],
+ content: [
+ "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
+ "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
+ "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
+ ],
+ theme: {
+ extend: {
+ 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))",
+ },
+ },
+ borderRadius: {
+ lg: "var(--radius)",
+ md: "calc(var(--radius) - 2px)",
+ sm: "calc(var(--radius) - 4px)",
+ },
+ },
},
- },
- plugins: [],
+ plugins: [require("tailwindcss-animate")],
};
export default config;
diff --git a/tsconfig.json b/tsconfig.json
index 7b28589..af0efb2 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,10 @@
{
"compilerOptions": {
- "lib": ["dom", "dom.iterable", "esnext"],
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -18,9 +22,18 @@
}
],
"paths": {
- "@/*": ["./src/*"]
+ "@/*": [
+ "./src/*"
+ ]
}
},
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
- "exclude": ["node_modules"]
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
}