added phone number and updated some things

This commit is contained in:
2026-08-31 12:03:56 +02:00
parent a4cc12d763
commit d6dbc71071
4 changed files with 18 additions and 20 deletions
+5 -3
View File
@@ -1,5 +1,5 @@
import Link from "next/link";
import { Mail } from "lucide-react";
import { Mail, Phone } from "lucide-react";
import { FaLinkedin } from "react-icons/fa6";
import { SiGitea } from "react-icons/si";
import type { Locale, Dictionary } from "@/lib/dictionaries";
@@ -23,6 +23,7 @@ export default function Footer({ locale, dict }: FooterProps) {
[dict.footer.connect]: [
{ label: "Source Code", href: "https://git.ksan.dev/ksan", external: true },
{ label: "Email", href: "mailto:contact@ksan.dev", external: true },
{ label: "+387 66 644 094", href: "tel:+38766644094", external: true },
{ label: "LinkedIn", href: "https://www.linkedin.com/in/%C4%91or%C4%91e-k%C5%A1an-886871266", external: true },
],
};
@@ -30,6 +31,7 @@ export default function Footer({ locale, dict }: FooterProps) {
const socials = [
{ icon: SiGitea, href: "https://git.ksan.dev/ksan", label: "Gitea" },
{ icon: Mail, href: "mailto:contact@ksan.dev", label: "Email" },
{ icon: Phone, href: "tel:+38766644094", label: "Phone" },
{ icon: FaLinkedin, href: "https://www.linkedin.com/in/%C4%91or%C4%91e-k%C5%A1an-886871266/", label: "LinkedIn" },
];
@@ -84,8 +86,8 @@ export default function Footer({ locale, dict }: FooterProps) {
{"external" in link && link.external ? (
<a
href={link.href}
target="_blank"
rel="noopener noreferrer"
target={link.href.startsWith("http") ? "_blank" : undefined}
rel={link.href.startsWith("http") ? "noopener noreferrer" : undefined}
className="text-sm text-text-secondary transition-colors hover:text-text-primary"
>
{link.label}
+7
View File
@@ -6,6 +6,7 @@ import { SiGitea } from "react-icons/si";
import {
ArrowRight,
Mail,
Phone,
MapPin,
Clock,
Send,
@@ -74,6 +75,12 @@ export default function ContactForm({ dict }: ContactFormProps) {
value: "contact@ksan.dev",
href: "mailto:contact@ksan.dev",
},
{
icon: Phone,
label: t.phoneLabel,
value: "+387 66 644 094",
href: "tel:+38766644094",
},
{
icon: SiGitea,
label: "Source Code",
+1 -12
View File
@@ -14,7 +14,7 @@ interface HeroProps {
export default function Hero({ locale, dict }: HeroProps) {
const stats = [
{ value: "13+", label: dict.hero.stats.projects },
{ value: "4", label: dict.hero.stats.clients },
{ value: "5", label: dict.hero.stats.clients },
{ value: "10", label: dict.hero.stats.infra },
{ value: "<24h", label: dict.hero.stats.response },
];
@@ -65,17 +65,6 @@ export default function Hero({ locale, dict }: HeroProps) {
animate="visible"
className="mx-auto max-w-4xl text-center"
>
{/* Badge */}
<motion.div variants={fadeUp} className="mb-8 flex justify-center">
<span className="inline-flex items-center gap-2 rounded-full border border-emerald-500/30 bg-emerald-500/10 px-3.5 py-1.5 font-mono text-xs tracking-tight text-emerald-300 backdrop-blur-md">
<span className="relative flex h-1.5 w-1.5">
<span className="absolute inset-0 animate-ping rounded-full bg-emerald-400 opacity-75" />
<span className="relative inline-flex h-1.5 w-1.5 rounded-full bg-emerald-400" />
</span>
{dict.hero.badge}
</span>
</motion.div>
{/* Heading */}
<motion.h1
variants={fadeUp}
+5 -5
View File
@@ -17,9 +17,9 @@ export type Dictionary = typeof dictionaries.en;
// independently of type. Lower numbers come first. `inCarousel: false` hides
// a project from the homepage carousel while keeping it on the projects page.
const projectsMeta = {
"security-consultancy": { order: 1, carouselOrder: 4, inCarousel: true, tags: ["React", "Node.js", "Express", "JavaScript"], live: true, type: "client" as const, url: "https://obzor.rs/", github: "", download: "", inProgress: false, screenshots: ["/site1.png"] as string[] },
"ecommerce-platform": { order: 2, carouselOrder: 5, inCarousel: true, tags: ["React", "Express.js", "Docker", "CI/CD"], live: true, type: "client" as const, url: "https://kupitri.com", github: "", download: "", inProgress: false, screenshots: ["/site2.png"] as string[] },
"pramoal": { order: 3, carouselOrder: 3, inCarousel: true, tags: ["Next.js", "Tailwind CSS", "SEO"], live: true, type: "client" as const, url: "https://pramoal.rs", github: "", download: "", inProgress: false, screenshots: ["/pramoal.png"] as string[] },
"security-consultancy": { order: 2, carouselOrder: 4, inCarousel: true, tags: ["React", "Node.js", "Express", "JavaScript"], live: true, type: "client" as const, url: "https://obzor.rs/", github: "", download: "", inProgress: false, screenshots: ["/site1.png"] as string[] },
"ecommerce-platform": { order: 3, carouselOrder: 5, inCarousel: true, tags: ["React", "Express.js", "Docker", "CI/CD"], live: true, type: "client" as const, url: "https://kupitri.com", github: "", download: "", inProgress: false, screenshots: ["/site2.png"] as string[] },
"pramoal": { order: 1, carouselOrder: 3, inCarousel: true, tags: ["Next.js", "Tailwind CSS", "SEO"], live: true, type: "client" as const, url: "https://pramoal.rs", github: "", download: "", inProgress: false, screenshots: ["/pramoal.png"] as string[] },
"mobile-companion": { order: 4, carouselOrder: 3, inCarousel: false, tags: ["Java", "Spring Boot", "React Native", "PostgreSQL"], live: false, type: "client" as const, url: "", github: "", download: "", inProgress: true, screenshots: ["/tba.png"] as string[] },
"business-landing": { order: 5, carouselOrder: 4, inCarousel: false, tags: ["Next.js", "Tailwind CSS"], live: false, type: "client" as const, url: "", github: "", download: "", inProgress: true, screenshots: ["/tba.png"] as string[] },
"etf-oglasi": { order: 1, carouselOrder: 1, inCarousel: true, tags: ["React Native", "Node.js"], live: false, type: "personal" as const, url: "", github: "https://git.ksan.dev/ksan/etf-oglasi", download: "https://git.ksan.dev/ksan/etf-oglasi/releases/tag/mobile-v6", inProgress: false, screenshots: ["/etfoglasi.png", "/etf2.png", "/etfoglasiapp.jpg", "/etf1.png"] as string[] },
@@ -34,7 +34,6 @@ export const dictionaries = {
en: {
nav: { features: "Features", projects: "Projects", services: "Services", about: "About", contact: "Contact" },
hero: {
badge: "Available for freelance & full-time",
titleLine1: "Full-stack engineering,", titleLine2: "end to end.",
subtitle: "From idea to production-ready software. I build and deploy end-to-end systems — including web applications, backend services, and APIs — into production.",
cta: "Start a project", ctaSecondary: "See what I do",
@@ -272,6 +271,7 @@ export const dictionaries = {
messageLabel: "Message", messagePlaceholder: "Tell me about your project...",
send: "Send message", sending: "Sending...", avgResponse: "Average response time: under 24h",
successTitle: "Message sent.", successMessage: "Thanks for reaching out — I'll get back to you within 24 hours.", sendAnother: "Send another message",
phoneLabel: "Phone",
responseTime: "Response time", responseValue: "Usually within 24h",
location: "Location", locationValue: "Banja Luka, Bosnia and Herzegovina",
},
@@ -284,7 +284,6 @@ export const dictionaries = {
sr: {
nav: { features: "Vještine", projects: "Projekti", services: "Usluge", about: "O meni", contact: "Kontakt" },
hero: {
badge: "Dostupan za freelance i stalni posao",
titleLine1: "Full-stack inženjering,", titleLine2: "end-to-end",
subtitle: "Od ideje do produkcijski spremnog softvera. Razvijam i deploy-ujem end-to-end sisteme — od web aplikacija i backend servisa do API-ja — u produkcijsko okruženje.",
cta: "Započni projekat", ctaSecondary: "Pogledaj usluge",
@@ -490,6 +489,7 @@ export const dictionaries = {
messageLabel: "Poruka", messagePlaceholder: "Ispričajte mi o svom projektu...",
send: "Pošalji poruku", sending: "Slanje...", avgResponse: "Prosječno vrijeme odgovora: ispod 24h",
successTitle: "Poruka poslata.", successMessage: "Hvala na poruci — javiću vam se u roku od 24 sata.", sendAnother: "Pošalji novu poruku",
phoneLabel: "Telefon",
responseTime: "Vrijeme odgovora", responseValue: "Obično ispod 24h",
location: "Lokacija", locationValue: "Banja Luka, Bosna i Hercegovina",
},