Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb70cc728d | |||
| 93d94616b5 | |||
| bbd466e050 | |||
| 247ada2b0e | |||
| 85f6efc82c | |||
| f8a10a8ff0 |
15
deploy.sh
Normal file
15
deploy.sh
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "Usage: $0 <project_path>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PROJECT_PATH=$1
|
||||||
|
|
||||||
|
echo "Deploying project..."
|
||||||
|
cd "$PROJECT_PATH" || { echo "Directory not found: $PROJECT_PATH"; exit 1; }
|
||||||
|
git pull origin main
|
||||||
|
docker-compose up -d --build
|
||||||
|
echo "Deployment finished!"
|
||||||
24
docker-compose.yml
Normal file
24
docker-compose.yml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
version: "3.8"
|
||||||
|
services:
|
||||||
|
nextjs:
|
||||||
|
build: .
|
||||||
|
deploy:
|
||||||
|
update_config:
|
||||||
|
parallelism: 1
|
||||||
|
delay: 5s
|
||||||
|
order: start-first
|
||||||
|
container_name: pablo.shortman.me
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.pablo-shortman-me.rule=Host(`pablo.shortman.me`)"
|
||||||
|
- "traefik.http.routers.pablo-shortman-me.entrypoints=websecure"
|
||||||
|
- "traefik.http.services.pablo-shortman-me.loadbalancer.server.port=3000"
|
||||||
|
- "traefik.http.routers.pablo-shortman-me.tls.certresolver=myresolver"
|
||||||
|
expose:
|
||||||
|
- "3000"
|
||||||
|
networks:
|
||||||
|
- webproxy
|
||||||
|
networks:
|
||||||
|
webproxy:
|
||||||
|
external: true
|
||||||
@ -2,11 +2,7 @@ import React from "react";
|
|||||||
import Contact from "@/components/setions/contact";
|
import Contact from "@/components/setions/contact";
|
||||||
|
|
||||||
function ContactPage() {
|
function ContactPage() {
|
||||||
return (
|
return <Contact />;
|
||||||
<div className="pt-12">
|
|
||||||
<Contact />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ContactPage;
|
export default ContactPage;
|
||||||
|
|||||||
@ -24,7 +24,6 @@ import {
|
|||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { sendDiscordNotification } from "@/lib/actions";
|
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
name: z.string().min(2).max(50),
|
name: z.string().min(2).max(50),
|
||||||
@ -40,16 +39,10 @@ function ContactForm() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 2. Define a submit handler.
|
// 2. Define a submit handler.
|
||||||
async function onSubmit({
|
function onSubmit(values: z.infer<typeof formSchema>) {
|
||||||
email,
|
// Do something with the form values.
|
||||||
message,
|
// ✅ This will be type-safe and validated.
|
||||||
name,
|
console.log(values);
|
||||||
budget,
|
|
||||||
}: z.infer<typeof formSchema>) {
|
|
||||||
await sendDiscordNotification(
|
|
||||||
`📬 **New Lead Submission**\n*Source*: pablo.shortman.me \n**Name**: ${name}\n**Email**: ${email}\n**Message**: ${message} \n**Budget**: ${budget} $`
|
|
||||||
);
|
|
||||||
form.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -105,8 +98,8 @@ function ContactForm() {
|
|||||||
<SelectValue placeholder="Select your Budget" />
|
<SelectValue placeholder="Select your Budget" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="< €2k">{"less then $1k"}</SelectItem>
|
<SelectItem value="< €2k">{"less then $2k"}</SelectItem>
|
||||||
<SelectItem value="> €4k">{"more then $3k"}</SelectItem>
|
<SelectItem value="> €4k">{"more then $4k"}</SelectItem>
|
||||||
<SelectItem value="> €6k">{"more then $6k"}</SelectItem>
|
<SelectItem value="> €6k">{"more then $6k"}</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|||||||
@ -1,16 +1,10 @@
|
|||||||
import Link from "next/link";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export type TechIcon = "ts" | "next" | "react" | "tailwind" | "PostgreSQL";
|
export type TechIcon = "ts" | "next" | "react" | "tailwind" | "PostgreSQL";
|
||||||
|
|
||||||
const tech: {
|
const tech: { label: string; Logo: (props: any) => JSX.Element }[] = [
|
||||||
label: string;
|
|
||||||
link: string;
|
|
||||||
Logo: (props: any) => JSX.Element;
|
|
||||||
}[] = [
|
|
||||||
{
|
{
|
||||||
label: "Tailwind CSS",
|
label: "Tailwind CSS",
|
||||||
link: "https://tailwindcss.com/",
|
|
||||||
Logo: (props: any) => (
|
Logo: (props: any) => (
|
||||||
<svg
|
<svg
|
||||||
{...props}
|
{...props}
|
||||||
@ -51,7 +45,6 @@ const tech: {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Typescript",
|
label: "Typescript",
|
||||||
link: "https://www.typescriptlang.org/",
|
|
||||||
Logo: (props: any) => (
|
Logo: (props: any) => (
|
||||||
<svg
|
<svg
|
||||||
{...props}
|
{...props}
|
||||||
@ -79,7 +72,6 @@ const tech: {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Next JS",
|
label: "Next JS",
|
||||||
link: "https://nextjs.org/",
|
|
||||||
Logo: (props: any) => (
|
Logo: (props: any) => (
|
||||||
<svg
|
<svg
|
||||||
{...props}
|
{...props}
|
||||||
@ -107,8 +99,6 @@ const tech: {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Drizzle ORM",
|
label: "Drizzle ORM",
|
||||||
link: "https://orm.drizzle.team/",
|
|
||||||
|
|
||||||
Logo: (props: any) => (
|
Logo: (props: any) => (
|
||||||
<svg
|
<svg
|
||||||
{...props}
|
{...props}
|
||||||
@ -138,7 +128,6 @@ const tech: {
|
|||||||
|
|
||||||
{
|
{
|
||||||
label: "PostgreSQL",
|
label: "PostgreSQL",
|
||||||
link: "https://www.postgresql.org/",
|
|
||||||
Logo: (props: any) => (
|
Logo: (props: any) => (
|
||||||
<svg
|
<svg
|
||||||
{...props}
|
{...props}
|
||||||
@ -168,7 +157,6 @@ const tech: {
|
|||||||
|
|
||||||
{
|
{
|
||||||
label: "Figma",
|
label: "Figma",
|
||||||
link: "https://www.figma.com",
|
|
||||||
Logo: (props: any) => (
|
Logo: (props: any) => (
|
||||||
<svg
|
<svg
|
||||||
{...props}
|
{...props}
|
||||||
@ -196,7 +184,6 @@ const tech: {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Github",
|
label: "Github",
|
||||||
link: "https://github.com/",
|
|
||||||
Logo: (props: any) => (
|
Logo: (props: any) => (
|
||||||
<svg
|
<svg
|
||||||
{...props}
|
{...props}
|
||||||
@ -228,20 +215,18 @@ function Tech() {
|
|||||||
return (
|
return (
|
||||||
<div className="py-12 lg:py-20 container relative space-y-8">
|
<div className="py-12 lg:py-20 container relative space-y-8">
|
||||||
<h3 className="text-sm font-mono text-muted-foreground text-center">
|
<h3 className="text-sm font-mono text-muted-foreground text-center">
|
||||||
most liked <span className="text-foreground">technologies</span> and{" "}
|
most liked{" "}
|
||||||
<span className="text-foreground">tools</span>
|
<span className="underline text-foreground">technologies</span> and{" "}
|
||||||
|
<span className="underline text-foreground">tools</span>
|
||||||
</h3>
|
</h3>
|
||||||
<ul className="flex w-full items-center justify-center gap-2 md:gap-4 lg:gap-8 flex-wrap">
|
<ul className="flex w-full items-center justify-center gap-2 md:gap-4 lg:gap-8 flex-wrap">
|
||||||
{tech.map(({ Logo, label, link }, idx) => (
|
{tech.map(({ Logo, label }, idx) => (
|
||||||
<li key={idx}>
|
<li
|
||||||
<Link
|
className="flex items-center gap-2 py-2 px-6 rounded-md bg-muted"
|
||||||
href={link}
|
key={idx}
|
||||||
target="_blank"
|
>
|
||||||
className="flex items-center gap-2 py-2 px-6 rounded-md bg-muted"
|
<Logo className="size-6" />
|
||||||
>
|
<span>{label}</span>
|
||||||
<Logo className="size-6" />
|
|
||||||
<span>{label}</span>
|
|
||||||
</Link>
|
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
"use server";
|
|
||||||
|
|
||||||
export async function sendDiscordNotification(message: string) {
|
|
||||||
const webhookUrl = process.env.DISCORD_WEBHOOK_URL;
|
|
||||||
|
|
||||||
await fetch(webhookUrl!, {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify({
|
|
||||||
content: message,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
15
test.yml
15
test.yml
@ -1,15 +0,0 @@
|
|||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "traefik.http.routers.logipedia.rule=Host(`logipedia.shortman.me`)"
|
|
||||||
- "traefik.http.routers.logipedia.entrypoints=websecure"
|
|
||||||
- "traefik.http.routers.logipedia.tls.certresolver=myresolver"
|
|
||||||
networks:
|
|
||||||
- logipedia_network
|
|
||||||
- webproxy
|
|
||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "traefik.http.routers.pablo-shortman-me.rule=Host(`pablo.shortman.me`)"
|
|
||||||
- "traefik.http.routers.pablo-shortman-me.entrypoints=websecure"
|
|
||||||
- "traefik.http.routers.pablo-shortman-me.tls.certresolver=myresolver"
|
|
||||||
networks:
|
|
||||||
- webproxy
|
|
||||||
Reference in New Issue
Block a user