Skip to content

Commit

Permalink
Merge pull request #11 from max1mde/more_components
Browse files Browse the repository at this point in the history
More components
  • Loading branch information
max1mde authored Dec 11, 2024
2 parents 538c60c + 2e94486 commit c493322
Show file tree
Hide file tree
Showing 28 changed files with 611 additions and 489 deletions.
8 changes: 4 additions & 4 deletions CONFIG.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
"url":"https://github.com/max1mde/portfolio"
},
{
"label":"YouTube",
"url":"https://www.youtube.com/@max1mde"
"label":"Contact",
"url":"/contact"
},
{
"label":"Privacy",
Expand Down Expand Up @@ -101,7 +101,7 @@
},
"contact":{
"enabled":true,
"header":"Contact Me",
"header":"Socials",
"route":"/contact",
"email":"[email protected]",
"direct_contact":"Reach Me Directly",
Expand Down Expand Up @@ -149,7 +149,7 @@
"label":"Your Email",
"type":"email",
"required":true
},
},
{
"name":"message",
"label":"Your Message",
Expand Down
4 changes: 2 additions & 2 deletions public/scripts/hover.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Portfolio
* Copyright (C) 2024 Maxim (https://github.com/max1mde)
*
* Copyright (C) 2024 Maxim (https://github.com/max1mde/portfolio)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation.
Expand Down
4 changes: 2 additions & 2 deletions public/scripts/scroll.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Portfolio
* Copyright (C) 2024 Maxim (https://github.com/max1mde)
*
* Copyright (C) 2024 Maxim (https://github.com/max1mde/portfolio)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation.
Expand Down
15 changes: 5 additions & 10 deletions scripts/add-headers.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Portfolio
* Copyright (C) 2024 Maxim (https://github.com/max1mde)
*
* Copyright (C) 2024 Maxim (https://github.com/max1mde/portfolio)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation.
Expand All @@ -11,7 +11,7 @@ const fs = require("fs").promises;
const path = require("path");

const CURRENT_YEAR = new Date().getFullYear();
const GITHUB_LINK = "https://github.com/max1mde";
const GITHUB_LINK = "https://github.com/max1mde/portfolio";

function createLicenseHeader(year) {
return `/**
Expand Down Expand Up @@ -40,7 +40,7 @@ function hasLicenseHeader(content, licenseHeader) {
};

const contentStripped = stripYear(
content.split("\n").slice(0, 10).join("\n")
content.split("\n").slice(0, 10).join("\n"),
);
const headerStripped = stripYear(licenseHeader);

Expand All @@ -53,18 +53,15 @@ async function processFile(filePath) {
const existingYear = extractCopyrightYear(content);
const licenseHeader = createLicenseHeader(CURRENT_YEAR);


if (!hasLicenseHeader(content, licenseHeader)) {

if (existingYear && existingYear !== CURRENT_YEAR) {
const updatedContent = content.replace(
/Copyright \(C\) \d{4}/,
`Copyright (C) ${CURRENT_YEAR}`
`Copyright (C) ${CURRENT_YEAR}`,
);
await fs.writeFile(filePath, updatedContent);
console.log(`Updated copyright year in: ${filePath}`);
} else {

await fs.writeFile(filePath, licenseHeader + content);
console.log(`Added license header to: ${filePath}`);
}
Expand All @@ -82,7 +79,6 @@ async function addLicenseHeaders(dir) {
const stat = await fs.stat(fullPath);

if (stat.isDirectory()) {

const skipDirs = ["node_modules", ".next", ".git", "dist", "build"];
if (!skipDirs.includes(file)) {
await addLicenseHeaders(fullPath);
Expand All @@ -98,7 +94,6 @@ async function addLicenseHeaders(dir) {
}
}


addLicenseHeaders(process.cwd())
.then(() => console.log("License header processing complete"))
.catch(console.error);
2 changes: 1 addition & 1 deletion src/app/api/contact/route.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* Portfolio
* Copyright (C) 2024 Maxim (https://github.com/max1mde)
* Copyright (C) 2024 Maxim (https://github.com/max1mde/portfolio)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
Expand Down
209 changes: 19 additions & 190 deletions src/app/contact/page.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* Portfolio
* Copyright (C) 2024 Maxim (https://github.com/max1mde)
* Copyright (C) 2024 Maxim (https://github.com/max1mde/portfolio)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
Expand All @@ -9,225 +9,54 @@

"use client";

import { useState } from "react";
import config from "/CONFIG.json";
import {
FaGithub,
FaLinkedin,
FaYoutube,
FaEnvelope,
FaTwitter,
FaTiktok,
FaInstagram,
FaDiscord,
FaSpotify,
FaXbox,
FaFacebook,
FaMapMarkerAlt,
FaPhone,
} from "react-icons/fa";

const SocialIcon = ({ name }) => {
const iconMap = {
github: FaGithub,
linkedin: FaLinkedin,
youtube: FaYoutube,
email: FaEnvelope,
twitter: FaTwitter,
tiktok: FaTiktok,
instagram: FaInstagram,
discord: FaDiscord,
spotify: FaSpotify,
xbox: FaXbox,
facebook: FaFacebook,
};

const Icon = iconMap[name.toLowerCase()] || FaEnvelope;
return <Icon className="w-6 h-6" />;
};
import { FaEnvelope } from "react-icons/fa";
import { SocialLinks } from "@/components/custom/social_links";
import { ContactForm } from "@/components/custom/contact_form";
import { LegalInfo } from "@/components/custom/legal_info";

export default function Contact() {
const [formData, setFormData] = useState({
name: "",
email: "",
message: "",
});

const [submitStatus, setSubmitStatus] = useState({
message: "",
type: "",
});

const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prev) => ({
...prev,
[name]: value,
}));
};

const handleSubmit = async (e) => {
e.preventDefault();
setSubmitStatus({ message: "", type: "" });
const contactConfig = config.pages.contact;

const handleContactSubmit = async (formData) => {
try {
const response = await fetch("/api/contact", {
return await fetch("/api/contact", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(formData),
});
const result = await response.json();

if (response.ok) {
setSubmitStatus({
message:
result.message || config.pages.contact.contact_form.success_message,
type: "success",
});
setFormData({ name: "", email: "", message: "" });
} else {
setSubmitStatus({
message:
result.message || config.pages.contact.contact_form.failure_message,
type: "error",
});
}
} catch (error) {
console.error("Submission error:", error);
setSubmitStatus({
message:
config.pages.contact.contact_form.error_message ||
"An unexpected error occurred.",
type: "error",
});
throw error;
}
};

return (
<div className="container mx-auto px-4 py-8 max-w-2xl">
<h1 className="c-cursor-text text-3xl font-bold text-center mb-10">
{config.pages.contact.header}
{contactConfig.header}
</h1>

<div className="flex justify-center space-x-6 mb-12">
{config.pages.contact.social_links.map((social, index) => (
<a
key={index}
href={social.url}
target="_blank"
rel="noopener noreferrer"
className="c-cursor-pointer text-gray-600 hover:text-primary transition-colors"
title={social.name}
>
<SocialIcon name={social.icon} />
</a>
))}
</div>

{config.pages.contact.contact_form.enabled && (
<form
onSubmit={handleSubmit}
className="bg-black/50 shadow-md rounded-lg p-8 space-y-6"
>
{config.pages.contact.contact_form.fields.map((field) => (
<div key={field.name}>
<label
htmlFor={field.name}
className="block text-gray-700 font-medium mb-2"
>
{field.label}
</label>
{field.type === "textarea" ? (
<textarea
id={field.name}
name={field.name}
required={field.required}
value={formData[field.name]}
onChange={handleChange}
className="c-cursor-text w-full px-3 py-2 border bg-black/10 rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
rows="4"
/>
) : (
<input
type={field.type}
id={field.name}
name={field.name}
required={field.required}
value={formData[field.name]}
onChange={handleChange}
className="c-cursor-text w-full px-3 py-2 border bg-black/10 rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
/>
)}
</div>
))}
<SocialLinks links={contactConfig.social_links} className="mb-12" />

<button
type="submit"
className="c-cursor-pointer w-full bg-primary text-white py-3 rounded-md hover:bg-primary/90 transition-colors"
>
{config.pages.contact.contact_form.send_button}
</button>
</form>
{contactConfig.contact_form.enabled && (
<ContactForm
config={contactConfig.contact_form}
onSubmit={handleContactSubmit}
/>
)}

{submitStatus.message && (
<div
className={`mt-4 text-center ${
submitStatus.type === "success" ? "text-green-500" : "text-red-500"
}`}
>
{submitStatus.message}
</div>
)}

{config.pages.contact.legal.enabled && (
<div className="mt-12 bg-black/50 rounded-lg p-6">
<h2 className="text-2xl font-semibold mb-4 text-center">
Legal Disclosure
</h2>
<div className="space-y-2 text-center">
{config.pages.contact.legal.name && (
<p className="flex items-center justify-center gap-2">
<FaMapMarkerAlt className="inline-block" />
{config.pages.contact.legal.name}
</p>
)}
{config.pages.contact.legal.address && (
<p className="flex items-center justify-center gap-2">
<FaMapMarkerAlt className="inline-block" />
{config.pages.contact.legal.address}
</p>
)}
{config.pages.contact.legal.email && (
<p className="flex items-center justify-center gap-2">
<FaEnvelope className="inline-block" />
{config.pages.contact.legal.email}
</p>
)}
{config.pages.contact.legal.phone && (
<p className="flex items-center justify-center gap-2">
<FaPhone className="inline-block" />
{config.pages.contact.legal.phone}
</p>
)}
{config.pages.contact.legal.legal_disclaimer && (
<p className="text-sm text-gray-400 mt-4">
{config.pages.contact.legal.legal_disclaimer}
</p>
)}
</div>
</div>
)}
<LegalInfo legal={contactConfig.legal} />

<div className="mt-12 text-center">
<h2 className="text-2xl font-semibold mb-4">
{config.pages.contact.direct_contact}
{contactConfig.direct_contact}
</h2>
<a className="c-cursor-text text-primary flex items-center justify-center gap-2">
<FaEnvelope className="inline-block" />
{config.pages.contact.email}
{contactConfig.email}
</a>
</div>
</div>
Expand Down
Loading

0 comments on commit c493322

Please sign in to comment.