first commit

This commit is contained in:
Xe Iaso 2024-07-01 11:11:56 -04:00
parent 99c18f8b42
commit 69d650606f
14 changed files with 871 additions and 123 deletions

36
.dockerignore Normal file
View 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

45
Dockerfile Normal file
View File

@ -0,0 +1,45 @@
# syntax = docker/dockerfile:1
# Adjust NODE_VERSION as desired
ARG NODE_VERSION=22.3.0
FROM node:${NODE_VERSION}-slim as base
LABEL fly_launch_runtime="Next.js"
# Next.js app lives here
WORKDIR /app
# Set production environment
ENV NODE_ENV="production"
# Throw-away build stage to reduce size of final image
FROM base as build
# Install packages needed to build node modules
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3
# Install node modules
COPY --link package-lock.json package.json ./
RUN npm ci --include=dev
# Copy application code
COPY --link . .
# Build application
RUN npm run build
# Remove development dependencies
RUN npm prune --omit=dev
# Final stage for app image
FROM base
# Copy built application
COPY --from=build /app /app
# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD [ "npm", "run", "start" ]

103
app/about/page.jsx Normal file
View File

@ -0,0 +1,103 @@
import React from 'react';
import { User, Award, Globe } from 'lucide-react';
import { Button } from '@/components/ui/Button';
const TeamMember = ({ name, role, image }) => (
<div className="text-center">
<img className="mx-auto h-40 w-40 rounded-full" src={image} alt={name} />
<div className="mt-4">
<h3 className="text-lg font-medium text-gray-900">{name}</h3>
<p className="text-sm text-gray-500">{role}</p>
</div>
</div>
);
const AboutPage = () => {
const teamMembers = [
{ name: "Jane Doe", role: "CEO & Founder", image: "/api/placeholder/150/150" },
{ name: "John Smith", role: "CTO", image: "/api/placeholder/150/150" },
{ name: "Emily Brown", role: "Head of AI", image: "/api/placeholder/150/150" },
];
return (
<div className="bg-gray-100 min-h-screen">
<header className="bg-white shadow">
<div className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
<h1 className="text-3xl font-bold text-gray-900">About Us</h1>
</div>
</header>
<main>
<div className="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
<div className="px-4 py-6 sm:px-0">
<div className="text-center mb-12">
<h2 className="text-3xl font-extrabold text-gray-900 sm:text-4xl">
Empowering Canadian Businesses with Innovative Technology
</h2>
<p className="mt-4 text-xl text-gray-500">
Techaro Computing Canada is at the forefront of digital transformation, helping businesses across the country leverage cutting-edge technology to drive growth and innovation.
</p>
</div>
<div className="bg-white shadow overflow-hidden sm:rounded-lg mb-12">
<div className="px-4 py-5 sm:px-6">
<h3 className="text-lg leading-6 font-medium text-gray-900">Our Mission</h3>
</div>
<div className="border-t border-gray-200">
<dl>
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt className="text-sm font-medium text-gray-500 flex items-center">
<User className="h-5 w-5 mr-2 text-blue-500" />
Client Focus
</dt>
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
We are dedicated to understanding and meeting the unique needs of each client, ensuring their success in the digital landscape.
</dd>
</div>
<div className="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt className="text-sm font-medium text-gray-500 flex items-center">
<Award className="h-5 w-5 mr-2 text-blue-500" />
Innovation
</dt>
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
We continuously explore and implement the latest technologies to provide cutting-edge solutions for our clients.
</dd>
</div>
<div className="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt className="text-sm font-medium text-gray-500 flex items-center">
<Globe className="h-5 w-5 mr-2 text-blue-500" />
Canadian Focus
</dt>
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
We are committed to strengthening the Canadian tech ecosystem and helping local businesses compete on a global scale.
</dd>
</div>
</dl>
</div>
</div>
<div className="text-center mb-12">
<h3 className="text-2xl font-bold text-gray-900">Our Leadership Team</h3>
<div className="mt-10 grid grid-cols-1 gap-10 sm:grid-cols-2 lg:grid-cols-3">
{teamMembers.map((member, index) => (
<TeamMember key={index} {...member} />
))}
</div>
</div>
<div className="bg-blue-700 rounded-lg shadow-xl overflow-hidden">
<div className="px-4 py-5 sm:p-6 text-center">
<h3 className="text-2xl font-semibold text-white mb-4">Ready to Transform Your Business?</h3>
<p className="text-blue-100 mb-6">Let{"'"}s discuss how Techaro Computing Canada can help you achieve your technology goals.</p>
<Button className="bg-white text-blue-700 hover:bg-blue-50">
Schedule a Consultation
</Button>
</div>
</div>
</div>
</div>
</main>
</div>
);
};
export default AboutPage;

52
app/contact/page.jsx Normal file
View File

@ -0,0 +1,52 @@
import React from 'react';
const ContactPage = () => {
async function contactForm(formData) {
"use server";
const rawFormData = {
name: formData.get('name'),
email: formData.get('email'),
message: formData.get('message'),
};
console.log(rawFormData);
};
return (
<div className="bg-gray-100 mx-auto text-gray-900 px-4 pt-8">
<h1 className="text-3xl font-bold text-gray-900 mb-6">Contact Techaro Computing Canada</h1>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<div className="text-gray-900">
<h2 className="text-xl font-semibold mb-4">Get in Touch</h2>
<p className="mb-4">We would love to hear from you. Please fill out the form below or use our contact information.</p>
<h3 className="text-lg font-semibold mb-2">Contact Information</h3>
<p>Email: sales@techaro.lol</p>
<p>Phone: (123) 456-7890</p>
<p>Address: 123 Tech Street, Toronto, ON M5V 1J2</p>
</div>
<div className="pb-4">
<h2 className="text-xl font-semibold mb-4">Contact Form</h2>
<form className="space-y-4" action={contactForm}>
<div>
<label htmlFor="name" className="block mb-1">Name</label>
<input disabled type="text" id="name" name="name" className="w-full px-3 py-2 border rounded" required />
</div>
<div>
<label htmlFor="email" className="block mb-1">Email</label>
<input disabled type="email" id="email" name="email" className="w-full px-3 py-2 border rounded" required />
</div>
<div>
<label htmlFor="message" className="block mb-1">Message</label>
<textarea disabled id="message" name="message" rows="4" className="w-full px-3 py-2 border rounded" required></textarea>
</div>
<button type="submit" disabled className="bg-gray-500 text-white px-4 py-2 rounded hover:bg-gray-600">Send Message</button>
</form>
</div>
</div>
</div>
);
};
export default ContactPage;

View File

@ -2,6 +2,14 @@
@tailwind components;
@tailwind utilities;
html {
font-family: var(--font-inter);
}
h1 {
font-family: var(--font-podkova);
}
:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;

View File

@ -1,12 +1,25 @@
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import { Inter, Podkova } from "next/font/google";
import "./globals.css";
import React from "react";
import Link from "next/link";
import { Button } from "@/components/ui/Button";
const inter = Inter({ subsets: ["latin"] });
const inter = Inter({
subsets: ["latin"],
variable: "--font-inter",
display: "swap",
});
const podkova = Podkova({
subsets: ["latin"],
variable: "--font-podkova",
display: "swap",
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: "Techaro Computing Canada",
description: "Your one-stop shop for all your computing needs.",
};
export default function RootLayout({
@ -16,7 +29,69 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
<body
className={`${inter.variable} ${podkova.variable} ${inter.className}`}
>
<div className="min-h-screen bg-gray-50">
<header className="bg-white shadow-sm">
<nav
className={`${inter.className} max-w-7xl mx-auto px-4 sm:px-6 lg:px-8`}
>
<div className="flex justify-between h-16">
<div className={`flex`}>
<div className="flex-shrink-0 flex items-center">
<Link
href="/"
className={`${inter.className} text-2xl font-bold text-gray-900`}
>
Techaro
</Link>
</div>
</div>
<div className="flex items-center">
<Link href="/services" passHref>
<Button
variant="ghost"
className="text-gray-600 hover:text-gray-900"
>
Services
</Button>
</Link>
<Link href="/about" passHref>
<Button
variant="ghost"
className="text-gray-600 hover:text-gray-900"
>
About
</Button>
</Link>
<Link href="/contact" passHref>
<Button
variant="ghost"
className="text-gray-600 hover:text-gray-900"
>
Contact
</Button>
</Link>
</div>
</div>
</nav>
</header>
<main>{children}</main>
<footer className="bg-white mt-16">
<div className="max-w-7xl mx-auto py-12 px-4 sm:px-6 md:flex md:items-center md:justify-between lg:px-8">
<div className="flex justify-center space-x-6 md:order-2">
{/* Add social media links here */}
</div>
<div className="mt-8 md:mt-0 md:order-1">
<p className="text-center text-base text-gray-400">
&copy; 2024 Techaro Computing Canada. All rights reserved.
</p>
</div>
</div>
</footer>
</div>
</body>
</html>
);
}

91
app/page.jsx Normal file
View File

@ -0,0 +1,91 @@
import React from 'react';
import Link from 'next/link';
import { ChevronRight, Laptop, Users, TrendingUp, Brain } from 'lucide-react';
import { Button } from '@/components/ui/Button';
const HomePage = () => {
return (
<div className="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
<div className="px-4 py-6 sm:px-0">
<div className="text-center">
<h1 className="text-4xl tracking-tight font-extrabold text-gray-900 sm:text-5xl md:text-6xl">
<span className="block">Transform Your Business</span>
<span className="block text-blue-600">with Techaro Computing Canada</span>
</h1>
<p className="mt-3 max-w-md mx-auto text-base text-gray-500 sm:text-lg md:mt-5 md:text-xl md:max-w-3xl">
We help Canadian businesses leverage cutting-edge technology to drive growth, efficiency, and innovation.
</p>
<div className="mt-5 max-w-md mx-auto sm:flex sm:justify-center md:mt-8">
<div className="rounded-md shadow">
<Link href="/contact" passHref>
<Button className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 md:py-4 md:text-lg md:px-10">
Get started
<ChevronRight className="ml-2 -mr-1 h-5 w-5" />
</Button>
</Link>
</div>
<div className="mt-3 rounded-md shadow sm:mt-0 sm:ml-3">
<Link href="/services" passHref>
<Button variant="outline" className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-blue-600 bg-white hover:bg-gray-50 md:py-4 md:text-lg md:px-10">
Learn more
</Button>
</Link>
</div>
</div>
</div>
</div>
<div className="mt-10">
<h2 className="text-2xl font-semibold text-gray-900 text-center">Our Services</h2>
<div className="mt-6 grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
{[
{ icon: Laptop, title: "IT Strategy", description: "Align your technology investments with your business goals for maximum impact." },
{ icon: Users, title: "Digital Transformation", description: "Modernize your operations and customer experiences with cutting-edge digital solutions." },
{ icon: TrendingUp, title: "Data Analytics", description: "Unlock the power of your data to drive informed decision-making and business growth." }
].map((service, index) => (
<div key={index} className="pt-6">
<div className="flow-root bg-white rounded-lg px-6 pb-8">
<div className="-mt-6">
<div>
<span className="inline-flex items-center justify-center p-3 bg-blue-500 rounded-md shadow-lg">
<service.icon className="h-6 w-6 text-white" />
</span>
</div>
<h3 className="mt-8 text-lg font-medium text-gray-900 tracking-tight">{service.title}</h3>
<p className="mt-5 text-base text-gray-500">{service.description}</p>
</div>
</div>
</div>
))}
</div>
</div>
<div className="mt-16 bg-blue-700 rounded-lg shadow-xl overflow-hidden lg:grid lg:grid-cols-2 lg:gap-4">
<div className="pt-10 pb-12 px-6 sm:pt-16 sm:px-16 lg:py-16 lg:pr-0 xl:py-20 xl:px-20">
<div className="lg:self-center">
<h2 className="text-3xl font-extrabold text-white sm:text-4xl">
<span className="block">Transform Your Business</span>
<span className="block">with Industry-Leading AI Tools</span>
</h2>
<p className="mt-4 text-lg leading-6 text-blue-200">
At Techaro Computing Canada, we offer transformational experiences by leveraging cutting-edge AI technologies. Our solutions empower your business to stay ahead in the rapidly evolving digital landscape.
</p>
<Link href="/services#ai" passHref>
<Button className="mt-8 bg-white border border-transparent rounded-md shadow px-5 py-3 inline-flex items-center text-base font-medium text-blue-600 hover:bg-blue-50">
Learn about our AI solutions
</Button>
</Link>
</div>
</div>
<div className="relative -mt-6 aspect-w-5 aspect-h-3 md:aspect-w-2 md:aspect-h-1">
<div className="absolute inset-0 flex items-center justify-center">
<Brain className="h-48 w-48 text-blue-100" />
</div>
<div className="absolute inset-0 bg-blue-600 opacity-25"></div>
</div>
</div>
</div>
);
};
export default HomePage;

View File

@ -1,113 +0,0 @@
import Image from "next/image";
export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex">
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
Get started by editing&nbsp;
<code className="font-mono font-bold">app/page.tsx</code>
</p>
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:size-auto lg:bg-none">
<a
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
By{" "}
<Image
src="/vercel.svg"
alt="Vercel Logo"
className="dark:invert"
width={100}
height={24}
priority
/>
</a>
</div>
</div>
<div className="relative z-[-1] flex place-items-center before:absolute before:h-[300px] before:w-full before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-full after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 sm:before:w-[480px] sm:after:w-[240px] before:lg:h-[360px]">
<Image
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
src="/next.svg"
alt="Next.js Logo"
width={180}
height={37}
priority
/>
</div>
<div className="mb-32 grid text-center lg:mb-0 lg:w-full lg:max-w-5xl lg:grid-cols-4 lg:text-left">
<a
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
target="_blank"
rel="noopener noreferrer"
>
<h2 className="mb-3 text-2xl font-semibold">
Docs{" "}
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
-&gt;
</span>
</h2>
<p className="m-0 max-w-[30ch] text-sm opacity-50">
Find in-depth information about Next.js features and API.
</p>
</a>
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
target="_blank"
rel="noopener noreferrer"
>
<h2 className="mb-3 text-2xl font-semibold">
Learn{" "}
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
-&gt;
</span>
</h2>
<p className="m-0 max-w-[30ch] text-sm opacity-50">
Learn about Next.js in an interactive course with&nbsp;quizzes!
</p>
</a>
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
target="_blank"
rel="noopener noreferrer"
>
<h2 className="mb-3 text-2xl font-semibold">
Templates{" "}
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
-&gt;
</span>
</h2>
<p className="m-0 max-w-[30ch] text-sm opacity-50">
Explore starter templates for Next.js.
</p>
</a>
<a
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
target="_blank"
rel="noopener noreferrer"
>
<h2 className="mb-3 text-2xl font-semibold">
Deploy{" "}
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
-&gt;
</span>
</h2>
<p className="m-0 max-w-[30ch] text-balance text-sm opacity-50">
Instantly deploy your Next.js site to a shareable URL with Vercel.
</p>
</a>
</div>
</main>
);
}

85
app/services/page.jsx Normal file
View File

@ -0,0 +1,85 @@
import React from 'react';
import Link from 'next/link';
import { Cpu, Database, Cloud, Shield, Users, TrendingUp } from 'lucide-react';
import { Button } from '@/components/ui/Button';
const ServiceCard = ({ icon: Icon, title, description }) => (
<div className="bg-white overflow-hidden shadow rounded-lg">
<div className="px-4 py-5 sm:p-6">
<Icon className="h-8 w-8 text-blue-500 mb-4" />
<h3 className="text-lg font-medium text-gray-900">{title}</h3>
<p className="mt-2 text-base text-gray-500">{description}</p>
</div>
</div>
);
const ServicesPage = () => {
const services = [
{
icon: Cpu,
title: "AI and Machine Learning",
description: "Leverage cutting-edge AI technologies to automate processes, gain insights, and drive innovation in your business."
},
{
icon: Database,
title: "Data Analytics",
description: "Transform your raw data into actionable insights with our advanced analytics solutions."
},
{
icon: Cloud,
title: "Cloud Migration",
description: "Seamlessly transition your infrastructure and applications to the cloud for improved scalability and efficiency."
},
{
icon: Shield,
title: "Cybersecurity",
description: "Protect your digital assets with our comprehensive cybersecurity services and solutions."
},
{
icon: Users,
title: "Digital Transformation",
description: "Modernize your business processes and customer experiences with our digital transformation strategies."
},
{
icon: TrendingUp,
title: "IT Strategy Consulting",
description: "Align your technology investments with your business goals to maximize ROI and drive growth."
}
];
return (
<div className="bg-gray-100 min-h-screen">
<header className="bg-white shadow">
<div className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
<h1 className="text-3xl font-bold text-gray-900">Our Services</h1>
</div>
</header>
<div className="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
<div className="px-4 py-6 sm:px-0">
<div className="text-center mb-12">
<h2 className="text-3xl font-extrabold text-gray-900 sm:text-4xl">
Comprehensive IT Solutions for Canadian Businesses
</h2>
<p className="mt-4 text-xl text-gray-500">
At Techaro Computing Canada, we offer a wide range of services to help your business thrive in the digital age.
</p>
</div>
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
{services.map((service, index) => (
<ServiceCard key={index} {...service} />
))}
</div>
<div className="mt-12 text-center">
<Link href="/contact" passHref>
<Button className="px-6 py-3 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition duration-300">
Contact Us for a Consultation
</Button>
</Link>
</div>
</div>
</div>
</div>
);
};
export default ServicesPage;

49
components/ui/Button.tsx Normal file
View File

@ -0,0 +1,49 @@
import React from "react";
import { cn } from "@/lib/utils";
const buttonVariants = {
base: "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none",
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",
},
};
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: keyof typeof buttonVariants.variant;
size?: keyof typeof buttonVariants.size;
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant = "default", size = "default", ...props }, ref) => {
return (
<button
className={cn(
buttonVariants.base,
buttonVariants.variant[variant],
buttonVariants.size[size],
className
)}
ref={ref}
{...props}
/>
);
}
);
Button.displayName = "Button";
export { Button, buttonVariants };

22
fly.toml Normal file
View File

@ -0,0 +1,22 @@
# fly.toml app configuration file generated for techaro on 2024-07-01T10:58:51-04:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#
app = 'techaro'
primary_region = 'yul'
[build]
[http_service]
internal_port = 3000
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0
processes = ['app']
[[vm]]
memory = '1gb'
cpu_kind = 'shared'
cpus = 1

8
lib/utils.ts Normal file
View File

@ -0,0 +1,8 @@
type ClassValue = string | number | boolean | undefined | null;
type ClassArray = ClassValue[];
type ClassDictionary = Record<string, any>;
type ClassProp = ClassValue | ClassArray | ClassDictionary;
export function cn(...inputs: ClassProp[]): string {
return inputs.flat().filter(Boolean).join(' ');
}

285
package-lock.json generated
View File

@ -8,11 +8,13 @@
"name": "www",
"version": "0.1.0",
"dependencies": {
"lucide-react": "^0.399.0",
"next": "14.2.4",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@flydotio/dockerfile": "^0.5.7",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
@ -96,6 +98,39 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@flydotio/dockerfile": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/@flydotio/dockerfile/-/dockerfile-0.5.7.tgz",
"integrity": "sha512-BVkXM2K/jLLYBFos1gT/bYv0YPJue8L4j0dkIsskJI4JRn6rPA9bZjT4sJzkzhdubZuwRGG9cgxj4Cfgt4lHlw==",
"dev": true,
"license": "MIT",
"dependencies": {
"chalk": "^5.3.0",
"diff": "^5.1.0",
"ejs": "^3.1.9",
"shell-quote": "^1.8.1",
"yargs": "^17.7.2"
},
"bin": {
"dockerfile": "index.js"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@flydotio/dockerfile/node_modules/chalk": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
"integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@ -951,6 +986,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/async": {
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
"integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==",
"dev": true,
"license": "MIT"
},
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@ -1163,6 +1205,61 @@
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT"
},
"node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"dev": true,
"license": "ISC",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
"wrap-ansi": "^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/cliui/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true,
"license": "MIT"
},
"node_modules/cliui/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/cliui/node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@ -1397,6 +1494,16 @@
"dev": true,
"license": "Apache-2.0"
},
"node_modules/diff": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
"integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@ -1437,6 +1544,22 @@
"dev": true,
"license": "MIT"
},
"node_modules/ejs": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
"integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"jake": "^10.8.5"
},
"bin": {
"ejs": "bin/cli.js"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
@ -1645,6 +1768,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/escalade": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
"integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@ -2168,6 +2301,39 @@
"node": "^10.12.0 || >=12.0.0"
}
},
"node_modules/filelist": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
"integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"minimatch": "^5.0.1"
}
},
"node_modules/filelist/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/filelist/node_modules/minimatch": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=10"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@ -2308,6 +2474,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
"license": "ISC",
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
},
"node_modules/get-intrinsic": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
@ -3122,6 +3298,25 @@
"@pkgjs/parseargs": "^0.11.0"
}
},
"node_modules/jake": {
"version": "10.9.1",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.9.1.tgz",
"integrity": "sha512-61btcOHNnLnsOdtLgA5efqQWjnSi/vow5HbI7HMdKKWqvrKR1bLK3BPlJn9gcSaP2ewuamUSMB5XEy76KUIS2w==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"async": "^3.2.3",
"chalk": "^4.0.2",
"filelist": "^1.0.4",
"minimatch": "^3.1.2"
},
"bin": {
"jake": "bin/cli.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/jiti": {
"version": "1.21.6",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
@ -3307,6 +3502,15 @@
"node": "14 || >=16.14"
}
},
"node_modules/lucide-react": {
"version": "0.399.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.399.0.tgz",
"integrity": "sha512-UyTNa3djBISdzL2UktgCrESXexQXaDQWi/WsDkbw6fBFfHlapajR58WoR+gxQ4laxfEyiHmoFrEIM3V+5XOVQg==",
"license": "ISC",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@ -4152,6 +4356,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/resolve": {
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@ -4380,6 +4594,16 @@
"node": ">=8"
}
},
"node_modules/shell-quote": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz",
"integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
@ -5238,6 +5462,16 @@
"dev": true,
"license": "ISC"
},
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=10"
}
},
"node_modules/yaml": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz",
@ -5251,6 +5485,57 @@
"node": ">= 14"
}
},
"node_modules/yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"dev": true,
"license": "MIT",
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"y18n": "^5.0.5",
"yargs-parser": "^21.1.1"
},
"engines": {
"node": ">=12"
}
},
"node_modules/yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/yargs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true,
"license": "MIT"
},
"node_modules/yargs/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",

View File

@ -9,18 +9,20 @@
"lint": "next lint"
},
"dependencies": {
"lucide-react": "^0.399.0",
"next": "14.2.4",
"react": "^18",
"react-dom": "^18",
"next": "14.2.4"
"react-dom": "^18"
},
"devDependencies": {
"typescript": "^5",
"@flydotio/dockerfile": "^0.5.7",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "14.2.4",
"postcss": "^8",
"tailwindcss": "^3.4.1",
"eslint": "^8",
"eslint-config-next": "14.2.4"
"typescript": "^5"
}
}