Update Dockerfile and Next.js configuration; enhance contact components
- Modify Dockerfile to install curl without recommended packages for a leaner image. - Update Next.js configuration to set outputFileTracingRoot for better Docker compatibility. - Revise contact components to improve messaging and clarity, changing "Get In Touch" to "Contact Me" and enhancing descriptions for collaboration opportunities. - Clean up Prisma schema by removing unnecessary comments and restructuring the Project model for clarity.
This commit is contained in:
@@ -4,7 +4,7 @@ FROM node:20 AS base
|
|||||||
# Install dependencies only when needed
|
# Install dependencies only when needed
|
||||||
FROM base AS deps
|
FROM base AS deps
|
||||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||||
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/*
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install dependencies based on the preferred package manager
|
# Install dependencies based on the preferred package manager
|
||||||
|
|||||||
@@ -93,10 +93,10 @@ const Contact = () => {
|
|||||||
className="text-center mb-16"
|
className="text-center mb-16"
|
||||||
>
|
>
|
||||||
<h2 className="text-4xl md:text-5xl font-bold mb-6 gradient-text">
|
<h2 className="text-4xl md:text-5xl font-bold mb-6 gradient-text">
|
||||||
Get In Touch
|
Contact Me
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-xl text-gray-400 max-w-2xl mx-auto">
|
<p className="text-xl text-gray-400 max-w-2xl mx-auto">
|
||||||
Have a project in mind or want to collaborate? I would love to hear from you!
|
Interested in working together or have questions about my projects? Feel free to reach out!
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
@@ -111,11 +111,11 @@ const Contact = () => {
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-2xl font-bold text-white mb-6">
|
<h3 className="text-2xl font-bold text-white mb-6">
|
||||||
Let's Connect
|
Get In Touch
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-gray-400 leading-relaxed">
|
<p className="text-gray-400 leading-relaxed">
|
||||||
I'm always open to discussing new opportunities, interesting projects,
|
I'm always available to discuss new opportunities, interesting projects,
|
||||||
or just having a chat about technology and innovation.
|
or simply chat about technology and innovation.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ const Hero = () => {
|
|||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
className="px-8 py-4 text-lg font-semibold border-2 border-gray-600 text-gray-300 hover:text-white hover:border-gray-500 rounded-lg transition-all duration-200"
|
className="px-8 py-4 text-lg font-semibold border-2 border-gray-600 text-gray-300 hover:text-white hover:border-gray-500 rounded-lg transition-all duration-200"
|
||||||
>
|
>
|
||||||
Get In Touch
|
Contact Me
|
||||||
</motion.a>
|
</motion.a>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export const metadata: Metadata = {
|
|||||||
authors: [{name: "Dennis Konkol", url: "https://dk0.dev"}],
|
authors: [{name: "Dennis Konkol", url: "https://dk0.dev"}],
|
||||||
openGraph: {
|
openGraph: {
|
||||||
title: "Dennis Konkol | Portfolio",
|
title: "Dennis Konkol | Portfolio",
|
||||||
description: "Explore my projects and get in touch!",
|
description: "Explore my projects and contact me for collaboration opportunities!",
|
||||||
url: "https://dk0.dev",
|
url: "https://dk0.dev",
|
||||||
siteName: "Dennis Konkol Portfolio",
|
siteName: "Dennis Konkol Portfolio",
|
||||||
images: [
|
images: [
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ dotenv.config({ path: path.resolve(__dirname, '.env') });
|
|||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
// Enable standalone output for Docker
|
// Enable standalone output for Docker
|
||||||
output: 'standalone',
|
output: 'standalone',
|
||||||
|
outputFileTracingRoot: path.join(__dirname, '../../'),
|
||||||
|
|
||||||
// Optimize for production
|
// Optimize for production
|
||||||
compress: true,
|
compress: true,
|
||||||
@@ -42,8 +43,7 @@ const nextConfig: NextConfig = {
|
|||||||
minimumCacheTTL: 60,
|
minimumCacheTTL: 60,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Disable static generation for dynamic routes
|
// Dynamic routes are handled automatically by Next.js
|
||||||
generateStaticParams: false,
|
|
||||||
|
|
||||||
// Add cache-busting headers
|
// Add cache-busting headers
|
||||||
async headers() {
|
async headers() {
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// This is your Prisma schema file,
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
|
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
}
|
}
|
||||||
@@ -13,8 +10,8 @@ datasource db {
|
|||||||
model Project {
|
model Project {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
title String @db.VarChar(255)
|
title String @db.VarChar(255)
|
||||||
description String @db.Text
|
description String
|
||||||
content String @db.Text
|
content String
|
||||||
tags String[] @default([])
|
tags String[] @default([])
|
||||||
featured Boolean @default(false)
|
featured Boolean @default(false)
|
||||||
category String @db.VarChar(100)
|
category String @db.VarChar(100)
|
||||||
@@ -23,12 +20,10 @@ model Project {
|
|||||||
live String? @db.VarChar(500)
|
live String? @db.VarChar(500)
|
||||||
published Boolean @default(true)
|
published Boolean @default(true)
|
||||||
imageUrl String? @db.VarChar(500)
|
imageUrl String? @db.VarChar(500)
|
||||||
metaDescription String? @db.Text
|
metaDescription String?
|
||||||
keywords String? @db.Text
|
keywords String?
|
||||||
ogImage String? @db.VarChar(500)
|
ogImage String? @db.VarChar(500)
|
||||||
schema Json?
|
schema Json?
|
||||||
|
|
||||||
// Advanced features
|
|
||||||
difficulty Difficulty @default(INTERMEDIATE)
|
difficulty Difficulty @default(INTERMEDIATE)
|
||||||
timeToComplete String? @db.VarChar(100)
|
timeToComplete String? @db.VarChar(100)
|
||||||
technologies String[] @default([])
|
technologies String[] @default([])
|
||||||
@@ -37,20 +32,13 @@ model Project {
|
|||||||
futureImprovements String[] @default([])
|
futureImprovements String[] @default([])
|
||||||
demoVideo String? @db.VarChar(500)
|
demoVideo String? @db.VarChar(500)
|
||||||
screenshots String[] @default([])
|
screenshots String[] @default([])
|
||||||
colorScheme String @db.VarChar(100) @default("Dark")
|
colorScheme String @default("Dark") @db.VarChar(100)
|
||||||
accessibility Boolean @default(true)
|
accessibility Boolean @default(true)
|
||||||
|
performance Json @default("{\"loadTime\": \"1.5s\", \"bundleSize\": \"50KB\", \"lighthouse\": 90}")
|
||||||
// Performance metrics
|
analytics Json @default("{\"likes\": 0, \"views\": 0, \"shares\": 0}")
|
||||||
performance Json @default("{\"lighthouse\": 90, \"bundleSize\": \"50KB\", \"loadTime\": \"1.5s\"}")
|
|
||||||
|
|
||||||
// Analytics
|
|
||||||
analytics Json @default("{\"views\": 0, \"likes\": 0, \"shares\": 0}")
|
|
||||||
|
|
||||||
// Timestamps
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
|
|
||||||
// Indexes for performance
|
|
||||||
@@index([category])
|
@@index([category])
|
||||||
@@index([featured])
|
@@index([featured])
|
||||||
@@index([published])
|
@@index([published])
|
||||||
@@ -59,6 +47,49 @@ model Project {
|
|||||||
@@index([tags])
|
@@index([tags])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model PageView {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
projectId Int? @map("project_id")
|
||||||
|
page String @db.VarChar(100)
|
||||||
|
ip String? @db.VarChar(45)
|
||||||
|
userAgent String? @map("user_agent")
|
||||||
|
referrer String? @db.VarChar(500)
|
||||||
|
timestamp DateTime @default(now())
|
||||||
|
|
||||||
|
@@index([projectId])
|
||||||
|
@@index([timestamp])
|
||||||
|
@@index([page])
|
||||||
|
}
|
||||||
|
|
||||||
|
model UserInteraction {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
projectId Int @map("project_id")
|
||||||
|
type InteractionType
|
||||||
|
ip String? @db.VarChar(45)
|
||||||
|
userAgent String? @map("user_agent")
|
||||||
|
timestamp DateTime @default(now())
|
||||||
|
|
||||||
|
@@index([projectId])
|
||||||
|
@@index([type])
|
||||||
|
@@index([timestamp])
|
||||||
|
}
|
||||||
|
|
||||||
|
model Contact {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
name String @db.VarChar(255)
|
||||||
|
email String @db.VarChar(255)
|
||||||
|
subject String @db.VarChar(500)
|
||||||
|
message String
|
||||||
|
responded Boolean @default(false)
|
||||||
|
responseTemplate String? @map("response_template") @db.VarChar(50)
|
||||||
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
|
|
||||||
|
@@index([email])
|
||||||
|
@@index([responded])
|
||||||
|
@@index([createdAt])
|
||||||
|
}
|
||||||
|
|
||||||
enum Difficulty {
|
enum Difficulty {
|
||||||
BEGINNER
|
BEGINNER
|
||||||
INTERMEDIATE
|
INTERMEDIATE
|
||||||
@@ -66,55 +97,9 @@ enum Difficulty {
|
|||||||
EXPERT
|
EXPERT
|
||||||
}
|
}
|
||||||
|
|
||||||
// Analytics tracking
|
|
||||||
model PageView {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
projectId Int? @map("project_id")
|
|
||||||
page String @db.VarChar(100)
|
|
||||||
ip String? @db.VarChar(45)
|
|
||||||
userAgent String? @db.Text @map("user_agent")
|
|
||||||
referrer String? @db.VarChar(500)
|
|
||||||
timestamp DateTime @default(now())
|
|
||||||
|
|
||||||
@@index([projectId])
|
|
||||||
@@index([timestamp])
|
|
||||||
@@index([page])
|
|
||||||
}
|
|
||||||
|
|
||||||
// User interactions
|
|
||||||
model UserInteraction {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
projectId Int @map("project_id")
|
|
||||||
type InteractionType
|
|
||||||
ip String? @db.VarChar(45)
|
|
||||||
userAgent String? @db.Text @map("user_agent")
|
|
||||||
timestamp DateTime @default(now())
|
|
||||||
|
|
||||||
@@index([projectId])
|
|
||||||
@@index([type])
|
|
||||||
@@index([timestamp])
|
|
||||||
}
|
|
||||||
|
|
||||||
enum InteractionType {
|
enum InteractionType {
|
||||||
LIKE
|
LIKE
|
||||||
SHARE
|
SHARE
|
||||||
BOOKMARK
|
BOOKMARK
|
||||||
COMMENT
|
COMMENT
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contact form submissions
|
|
||||||
model Contact {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
name String @db.VarChar(255)
|
|
||||||
email String @db.VarChar(255)
|
|
||||||
subject String @db.VarChar(500)
|
|
||||||
message String @db.Text
|
|
||||||
responded Boolean @default(false)
|
|
||||||
responseTemplate String? @db.VarChar(50) @map("response_template")
|
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
|
||||||
|
|
||||||
@@index([email])
|
|
||||||
@@index([responded])
|
|
||||||
@@index([createdAt])
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user