Compare commits
1 Commits
b68325123b
...
feat/intl-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78cdc7b539 |
@@ -1,34 +0,0 @@
|
|||||||
name: PR Checks
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, synchronize, reopened, ready_for_review]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint-and-build:
|
|
||||||
runs-on: node-22
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: 📥 Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: 🔍 Run ESLint
|
|
||||||
run: npm run lint
|
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
- name: 💅 Check code formatting (Prettier)
|
|
||||||
run: npm run format:check
|
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
- name: 🔤 TypeScript type checking
|
|
||||||
run: npx tsc --noEmit
|
|
||||||
|
|
||||||
- name: ✅ All quality checks passed
|
|
||||||
run: |
|
|
||||||
echo "✅ All code quality checks passed successfully!"
|
|
||||||
echo " - ESLint: No linting errors"
|
|
||||||
echo " - Prettier: Code is properly formatted"
|
|
||||||
echo " - TypeScript: No type errors"
|
|
||||||
@@ -1,384 +0,0 @@
|
|||||||
# Gitea Actions Workflow for Next.js Blog Application - Staging Environment
|
|
||||||
# This workflow builds a Docker image and deploys it to staging
|
|
||||||
#
|
|
||||||
# Workflow triggers:
|
|
||||||
# - Push to staging branch (automatic deployment)
|
|
||||||
# - Manual trigger via workflow_dispatch
|
|
||||||
#
|
|
||||||
# Required Secrets (configure in Gitea repository settings):
|
|
||||||
# - PRODUCTION_HOST: IP address or hostname of production server (same server hosts staging)
|
|
||||||
# - PRODUCTION_USER: SSH username (e.g., 'deployer')
|
|
||||||
# - SSH_PRIVATE_KEY: Private SSH key for authentication
|
|
||||||
#
|
|
||||||
# Environment Variables (configured below):
|
|
||||||
# - REGISTRY: Docker registry URL
|
|
||||||
# - IMAGE_NAME: Docker image name
|
|
||||||
#
|
|
||||||
# Docker Registry Configuration:
|
|
||||||
# - Current registry (repository.workspace:5000) is INSECURE - no authentication required
|
|
||||||
# - Registry login steps are SKIPPED to avoid 7+ minute timeout delays
|
|
||||||
# - Docker push/pull operations work without credentials
|
|
||||||
# - If switching to authenticated registry: uncomment login steps and configure secrets
|
|
||||||
|
|
||||||
name: Build and Deploy Next.js Blog to Staging
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- staging # Trigger on push to staging branch
|
|
||||||
workflow_dispatch: # Allow manual trigger from Gitea UI
|
|
||||||
|
|
||||||
env:
|
|
||||||
# Docker registry configuration
|
|
||||||
# Update this to match your private registry URL
|
|
||||||
REGISTRY: repository.workspace:5000
|
|
||||||
IMAGE_NAME: mypage
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
# ============================================
|
|
||||||
# Job 1: Code Quality Checks (Linting)
|
|
||||||
# ============================================
|
|
||||||
lint:
|
|
||||||
name: 🔍 Code Quality Checks
|
|
||||||
runs-on: node-22
|
|
||||||
# env:
|
|
||||||
# ACTIONS_RUNTIME_URL: http://192.168.1.53:3000 # Setează la nivel de job
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: 🔎 Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
# with:
|
|
||||||
# github-server-url: ${{ env.ACTIONS_RUNTIME_URL }}
|
|
||||||
|
|
||||||
# - name: 📦 Setup Node.js
|
|
||||||
# uses: actions/setup-node@v4
|
|
||||||
# with:
|
|
||||||
# node-version: "22"
|
|
||||||
# cache: "npm"
|
|
||||||
|
|
||||||
- name: 📥 Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: 🔍 Run ESLint
|
|
||||||
run: npm run lint
|
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
- name: 💅 Check code formatting (Prettier)
|
|
||||||
run: npm run format:check
|
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
- name: 🔤 TypeScript type checking
|
|
||||||
run: npx tsc --noEmit
|
|
||||||
|
|
||||||
- name: ✅ All quality checks passed
|
|
||||||
run: |
|
|
||||||
echo "✅ All code quality checks passed successfully!"
|
|
||||||
echo " - ESLint: No linting errors"
|
|
||||||
echo " - Prettier: Code is properly formatted"
|
|
||||||
echo " - TypeScript: No type errors"
|
|
||||||
|
|
||||||
# ============================================
|
|
||||||
# Job 2: Build and Push Docker Image
|
|
||||||
# ============================================
|
|
||||||
build-and-push:
|
|
||||||
name: 🏗️ Build and Push Docker Image
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [lint] # Wait for lint job to complete successfully
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: 🔎 Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: 📝 Create .env file from Gitea secrets
|
|
||||||
run: |
|
|
||||||
echo "Creating .env file for Docker build..."
|
|
||||||
cat > .env << EOF
|
|
||||||
# Build-time environment variables
|
|
||||||
NEXT_PUBLIC_SITE_URL=${{ vars.NEXT_PUBLIC_SITE_URL }}
|
|
||||||
NODE_ENV=production
|
|
||||||
NEXT_TELEMETRY_DISABLED=1
|
|
||||||
|
|
||||||
# Add other build-time variables here as needed
|
|
||||||
# NEXT_PUBLIC_GA_ID=${{ vars.NEXT_PUBLIC_GA_ID }}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
echo "✅ .env file created successfully"
|
|
||||||
echo "Preview (secrets masked):"
|
|
||||||
cat .env | sed 's/=.*/=***MASKED***/g'
|
|
||||||
|
|
||||||
# Insecure registry configuration - no authentication required
|
|
||||||
# The registry at repository.workspace:5000 does not require login
|
|
||||||
# Docker push/pull operations work without credentials
|
|
||||||
- name: ℹ️ Registry configuration (insecure - no login required)
|
|
||||||
run: |
|
|
||||||
echo "=== Docker Registry Configuration ==="
|
|
||||||
echo "Registry: ${{ env.REGISTRY }}"
|
|
||||||
echo "Type: Insecure (no authentication required)"
|
|
||||||
echo ""
|
|
||||||
echo "ℹ️ Skipping registry login - insecure registry allows push/pull without credentials"
|
|
||||||
echo ""
|
|
||||||
echo "If your registry requires authentication in the future:"
|
|
||||||
echo " 1. Set REGISTRY_USERNAME and REGISTRY_PASSWORD secrets in Gitea"
|
|
||||||
echo " 2. Uncomment the login step below this message"
|
|
||||||
echo " 3. Change registry URL to authenticated registry"
|
|
||||||
|
|
||||||
# Uncomment this step if registry requires authentication in the future
|
|
||||||
# - name: 🔐 Log in to Docker Registry
|
|
||||||
# timeout-minutes: 1
|
|
||||||
# run: |
|
|
||||||
# if [ -n "${{ secrets.REGISTRY_USERNAME }}" ] && [ -n "${{ secrets.REGISTRY_PASSWORD }}" ]; then
|
|
||||||
# echo "Attempting login to ${{ env.REGISTRY }}..."
|
|
||||||
# timeout 30s bash -c 'echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ env.REGISTRY }} -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin' || {
|
|
||||||
# echo "⚠️ Login failed - continuing anyway"
|
|
||||||
# }
|
|
||||||
# fi
|
|
||||||
|
|
||||||
- name: 🏗️ Build Docker image
|
|
||||||
timeout-minutes: 30
|
|
||||||
env:
|
|
||||||
DOCKER_BUILDKIT: 1 # Enable BuildKit for faster builds and better caching
|
|
||||||
run: |
|
|
||||||
echo "Building Next.js Docker image with BuildKit (staging)..."
|
|
||||||
echo "Build context size:"
|
|
||||||
du -sh . 2>/dev/null || echo "Cannot measure context size"
|
|
||||||
|
|
||||||
# Build the Docker image for staging
|
|
||||||
# - Uses Dockerfile.nextjs from project root
|
|
||||||
# - Tags image with 'staging' tag
|
|
||||||
# - Enables inline cache for faster subsequent builds
|
|
||||||
docker build \
|
|
||||||
--progress=plain \
|
|
||||||
--build-arg BUILDKIT_INLINE_CACHE=1 \
|
|
||||||
-t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:staging \
|
|
||||||
-f Dockerfile.nextjs \
|
|
||||||
.
|
|
||||||
|
|
||||||
echo "✅ Build successful"
|
|
||||||
echo "Image size:"
|
|
||||||
docker images ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:staging
|
|
||||||
|
|
||||||
- name: 🚀 Push Docker image to registry
|
|
||||||
run: |
|
|
||||||
echo "Pushing staging image to registry..."
|
|
||||||
|
|
||||||
# Push staging tag
|
|
||||||
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:staging
|
|
||||||
|
|
||||||
echo "✅ Image pushed successfully"
|
|
||||||
echo " - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:staging"
|
|
||||||
|
|
||||||
# ============================================
|
|
||||||
# Job 3: Deploy to Staging Server
|
|
||||||
# ============================================
|
|
||||||
deploy-staging:
|
|
||||||
name: 🚀 Deploy to Staging
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: [build-and-push] # Wait for build job to complete
|
|
||||||
environment:
|
|
||||||
name: staging
|
|
||||||
url: http://192.168.1.54:3031
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: 🔎 Checkout code (for docker-compose file)
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
# Verify Docker is accessible on staging server
|
|
||||||
# Registry authentication is not required for insecure registry
|
|
||||||
- name: ℹ️ Verify staging server Docker access
|
|
||||||
uses: appleboy/ssh-action@v1.0.3
|
|
||||||
with:
|
|
||||||
host: ${{ vars.PRODUCTION_HOST }}
|
|
||||||
username: ${{ vars.PRODUCTION_USER }}
|
|
||||||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
|
||||||
port: 22
|
|
||||||
script: |
|
|
||||||
echo "=== Verifying Docker is accessible ==="
|
|
||||||
docker info > /dev/null 2>&1 || {
|
|
||||||
echo "❌ Docker is not running or user has no access"
|
|
||||||
echo "Please ensure Docker is installed and user is in docker group"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
echo "✅ Docker is accessible"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Registry Configuration ==="
|
|
||||||
echo "Registry: ${{ env.REGISTRY }}"
|
|
||||||
echo "Type: Insecure (no authentication)"
|
|
||||||
echo "ℹ️ Skipping registry login - push/pull will work without credentials"
|
|
||||||
|
|
||||||
- name: 📁 Ensure staging directory structure
|
|
||||||
uses: appleboy/ssh-action@v1.0.3
|
|
||||||
with:
|
|
||||||
host: ${{ vars.PRODUCTION_HOST }}
|
|
||||||
username: ${{ vars.PRODUCTION_USER }}
|
|
||||||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
|
||||||
port: 22
|
|
||||||
script: |
|
|
||||||
echo "=== Ensuring staging directory structure ==="
|
|
||||||
|
|
||||||
# Verify base directory exists and is writable
|
|
||||||
# Update /opt/mypage-staging to match your deployment directory
|
|
||||||
if [ ! -d /opt/mypage-staging ]; then
|
|
||||||
echo "❌ /opt/mypage-staging does not exist!"
|
|
||||||
echo "Please run manually on staging server:"
|
|
||||||
echo " sudo mkdir -p /opt/mypage-staging"
|
|
||||||
echo " sudo chown -R deployer:docker /opt/mypage-staging"
|
|
||||||
echo " sudo chmod -R 775 /opt/mypage-staging"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -w /opt/mypage-staging ]; then
|
|
||||||
echo "❌ /opt/mypage-staging is not writable by $USER user"
|
|
||||||
echo "Please run manually on staging server:"
|
|
||||||
echo " sudo chown -R deployer:docker /opt/mypage-staging"
|
|
||||||
echo " sudo chmod -R 775 /opt/mypage-staging"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create data directories for logs
|
|
||||||
mkdir -p /opt/mypage-staging/data/logs || { echo "❌ Failed to create logs directory"; exit 1; }
|
|
||||||
|
|
||||||
echo "✅ Directory structure ready"
|
|
||||||
ls -la /opt/mypage-staging
|
|
||||||
|
|
||||||
- name: 📦 Copy docker-compose.staging.yml to staging server
|
|
||||||
uses: appleboy/scp-action@v0.1.7
|
|
||||||
with:
|
|
||||||
host: ${{ vars.PRODUCTION_HOST }}
|
|
||||||
username: ${{ vars.PRODUCTION_USER }}
|
|
||||||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
|
||||||
port: 22
|
|
||||||
source: "docker-compose.staging.yml"
|
|
||||||
target: "/opt/mypage-staging/"
|
|
||||||
overwrite: true
|
|
||||||
|
|
||||||
- name: 🐳 Deploy application via Docker Compose
|
|
||||||
uses: appleboy/ssh-action@v1.0.3
|
|
||||||
env:
|
|
||||||
# Optional: only needed if registry requires authentication
|
|
||||||
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD || '' }}
|
|
||||||
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME || '' }}
|
|
||||||
REGISTRY_URL: ${{ env.REGISTRY }}
|
|
||||||
IMAGE_FULL: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:staging
|
|
||||||
with:
|
|
||||||
host: ${{ vars.PRODUCTION_HOST }}
|
|
||||||
username: ${{ vars.PRODUCTION_USER }}
|
|
||||||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
|
||||||
port: 22
|
|
||||||
envs: REGISTRY_PASSWORD,REGISTRY_USERNAME,REGISTRY_URL,IMAGE_FULL
|
|
||||||
script_stop: true # Stop execution on any error
|
|
||||||
script: |
|
|
||||||
echo "=== Starting deployment to staging server ==="
|
|
||||||
cd /opt/mypage-staging
|
|
||||||
|
|
||||||
# Registry configuration - insecure registry does not require authentication
|
|
||||||
echo "=== Registry Configuration ==="
|
|
||||||
echo "Registry: $REGISTRY_URL"
|
|
||||||
echo "Type: Insecure (no authentication required)"
|
|
||||||
echo "ℹ️ Skipping registry login"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Verify docker-compose.staging.yml exists (copied by previous step)
|
|
||||||
if [ ! -f docker-compose.staging.yml ]; then
|
|
||||||
echo "❌ docker-compose.staging.yml not found in /opt/mypage-staging"
|
|
||||||
echo "File should have been copied by CI/CD workflow"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✅ Using docker-compose.staging.yml"
|
|
||||||
|
|
||||||
# Pull latest staging image from registry
|
|
||||||
echo "=== Pulling latest Docker image (staging) ==="
|
|
||||||
docker pull "$IMAGE_FULL"
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "❌ Failed to pull image, aborting deployment"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Deploy new container
|
|
||||||
# - Stops old container
|
|
||||||
# - Removes old container
|
|
||||||
# - Creates and starts new container with fresh image
|
|
||||||
echo "=== Deploying new staging container ==="
|
|
||||||
docker compose -f docker-compose.staging.yml up -d --force-recreate
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "❌ Failed to deploy new container"
|
|
||||||
echo "Check logs above for errors"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check container status
|
|
||||||
echo "=== Container Status ==="
|
|
||||||
docker compose -f docker-compose.staging.yml ps
|
|
||||||
|
|
||||||
# Show recent logs for debugging
|
|
||||||
echo "=== Recent application logs ==="
|
|
||||||
docker compose -f docker-compose.staging.yml logs --tail=50
|
|
||||||
|
|
||||||
# Clean up old/unused images to save disk space
|
|
||||||
echo "=== Cleaning up old Docker images ==="
|
|
||||||
docker image prune -f
|
|
||||||
|
|
||||||
echo "✅ Staging deployment completed successfully ==="
|
|
||||||
|
|
||||||
- name: ❤️ Health check
|
|
||||||
uses: appleboy/ssh-action@v1.0.3
|
|
||||||
with:
|
|
||||||
host: ${{ vars.PRODUCTION_HOST }}
|
|
||||||
username: ${{ vars.PRODUCTION_USER }}
|
|
||||||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
|
||||||
port: 22
|
|
||||||
script: |
|
|
||||||
echo "=== Performing health check ==="
|
|
||||||
cd /opt/mypage-staging
|
|
||||||
max_attempts=15
|
|
||||||
attempt=1
|
|
||||||
|
|
||||||
# Wait for container to be healthy (respect start_period from health check)
|
|
||||||
echo "Waiting for application to start (40s start period)..."
|
|
||||||
sleep 40
|
|
||||||
|
|
||||||
# Retry health check up to 15 times
|
|
||||||
while [ $attempt -le $max_attempts ]; do
|
|
||||||
# Check if application responds at port 3031
|
|
||||||
if curl -f http://localhost:3031/ > /dev/null 2>&1; then
|
|
||||||
echo "✅ Health check passed!"
|
|
||||||
echo "Application is healthy and responding to requests"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
echo "Attempt $attempt/$max_attempts: Health check failed, retrying in 5s..."
|
|
||||||
sleep 5
|
|
||||||
attempt=$((attempt + 1))
|
|
||||||
done
|
|
||||||
|
|
||||||
# Health check failed - gather diagnostic information
|
|
||||||
echo "❌ Health check failed after $max_attempts attempts"
|
|
||||||
echo ""
|
|
||||||
echo "=== Container Status ==="
|
|
||||||
docker compose -f docker-compose.staging.yml ps
|
|
||||||
echo ""
|
|
||||||
echo "=== Container Health ==="
|
|
||||||
docker inspect mypage-staging --format='{{.State.Health.Status}}' 2>/dev/null || echo "No health status"
|
|
||||||
echo ""
|
|
||||||
echo "=== Recent Application Logs ==="
|
|
||||||
docker compose -f docker-compose.staging.yml logs --tail=100
|
|
||||||
|
|
||||||
exit 1
|
|
||||||
|
|
||||||
- name: 📊 Deployment summary
|
|
||||||
if: always() # Run even if previous steps fail
|
|
||||||
run: |
|
|
||||||
echo "### 🚀 Deployment Summary" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "- **Environment**: Staging" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "- **Image**: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:staging" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "- **Commit**: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "- **Workflow Run**: #${{ github.run_number }}" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "- **Triggered By**: ${{ github.actor }}" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "- **Status**: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "**Next Steps:**" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "1. Verify application is accessible at http://192.168.1.54:3031" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "2. Check application logs for any errors" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "3. Test staging features before promoting to production" >> $GITHUB_STEP_SUMMARY
|
|
||||||
46
.vscode/launch.json
vendored
46
.vscode/launch.json
vendored
@@ -1,46 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "Next.js: Full Stack",
|
|
||||||
"type": "node-terminal",
|
|
||||||
"request": "launch",
|
|
||||||
"command": "npm run dev",
|
|
||||||
"serverReadyAction": {
|
|
||||||
"pattern": "started server on .+, url: (https?://.+)",
|
|
||||||
"uriFormat": "%s",
|
|
||||||
"action": "debugWithChrome"
|
|
||||||
},
|
|
||||||
"console": "integratedTerminal",
|
|
||||||
"internalConsoleOptions": "neverOpen"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Next.js: Frontend",
|
|
||||||
"type": "chrome",
|
|
||||||
"request": "launch",
|
|
||||||
"url": "http://localhost:3030",
|
|
||||||
"webRoot": "${workspaceFolder}",
|
|
||||||
"sourceMapPathOverrides": {
|
|
||||||
"webpack://_N_E/*": "${webRoot}/*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Next.js: Backend",
|
|
||||||
"type": "node",
|
|
||||||
"request": "attach",
|
|
||||||
"port": 9229,
|
|
||||||
"restart": true,
|
|
||||||
"sourceMaps": true,
|
|
||||||
"sourceMapPathOverrides": {
|
|
||||||
"webpack:///*": "${workspaceFolder}/*"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"compounds": [
|
|
||||||
{
|
|
||||||
"name": "Next.js: Debug Full Stack",
|
|
||||||
"configurations": ["Next.js: Backend", "Next.js: Frontend"],
|
|
||||||
"stopAll": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Metadata } from 'next'
|
import { Metadata } from 'next'
|
||||||
import { Navbar } from '@/components/blog/navbar'
|
import { Navbar } from '@/components/blog/navbar'
|
||||||
import {setRequestLocale, getTranslations} from 'next-intl/server'
|
import {setRequestLocale} from 'next-intl/server'
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'About',
|
title: 'About',
|
||||||
@@ -14,7 +14,6 @@ type Props = {
|
|||||||
export default async function AboutPage({params}: Props) {
|
export default async function AboutPage({params}: Props) {
|
||||||
const {locale} = await params
|
const {locale} = await params
|
||||||
setRequestLocale(locale)
|
setRequestLocale(locale)
|
||||||
const t = await getTranslations('About')
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
@@ -23,10 +22,10 @@ export default async function AboutPage({params}: Props) {
|
|||||||
{/* Classification Header */}
|
{/* Classification Header */}
|
||||||
<div className="border-2 border-[rgb(var(--border-primary))] p-8 mb-10">
|
<div className="border-2 border-[rgb(var(--border-primary))] p-8 mb-10">
|
||||||
<p className="text-[rgb(var(--text-muted))] font-mono text-xs uppercase tracking-widest mb-4">
|
<p className="text-[rgb(var(--text-muted))] font-mono text-xs uppercase tracking-widest mb-4">
|
||||||
{t('classificationHeader')}
|
>> _DOC://PUBLIC_ACCESS
|
||||||
</p>
|
</p>
|
||||||
<h1 className="text-4xl md:text-5xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] tracking-tight">
|
<h1 className="text-4xl md:text-5xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] tracking-tight">
|
||||||
{t('mainTitle')}
|
ABOUT ME_
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -36,10 +35,12 @@ export default async function AboutPage({params}: Props) {
|
|||||||
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
||||||
<div className="border-l-4 border-[var(--neon-cyan)] pl-6">
|
<div className="border-l-4 border-[var(--neon-cyan)] pl-6">
|
||||||
<p className="font-mono text-base text-[rgb(var(--text-primary))] leading-relaxed mb-4">
|
<p className="font-mono text-base text-[rgb(var(--text-primary))] leading-relaxed mb-4">
|
||||||
{t('introParagraph1')}
|
Welcome to my corner of the internet! This is where I share my thoughts, opinions,
|
||||||
|
and experiences - from tech adventures to life as a family man. Yes, I love
|
||||||
|
technology, but there's so much more to life than just code and servers.
|
||||||
</p>
|
</p>
|
||||||
<p className="font-mono text-sm text-[rgb(var(--text-muted))] uppercase tracking-wider">
|
<p className="font-mono text-sm text-[rgb(var(--text-muted))] uppercase tracking-wider">
|
||||||
{t('introLabel')}
|
STATUS: ACTIVE // ROLE: DAD + DEV + LIFE ENTHUSIAST
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -47,39 +48,46 @@ export default async function AboutPage({params}: Props) {
|
|||||||
{/* Life & Values Section */}
|
{/* Life & Values Section */}
|
||||||
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
||||||
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
||||||
{t('lifeValuesTitle')}
|
> LIFE & VALUES
|
||||||
</h2>
|
</h2>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="border-l-4 border-[var(--neon-pink)] pl-6">
|
<div className="border-l-4 border-[var(--neon-pink)] pl-6">
|
||||||
<h3 className="font-mono text-sm font-bold text-[var(--neon-pink)] uppercase mb-2">
|
<h3 className="font-mono text-sm font-bold text-[var(--neon-pink)] uppercase mb-2">
|
||||||
{t('familyFirstTitle')}
|
[FAMILY FIRST]
|
||||||
</h3>
|
</h3>
|
||||||
<p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
<p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
{t('familyFirstText')}
|
Being a dad to an amazing toddler is my most important role. Family time is
|
||||||
|
sacred - whether it's building block towers, exploring parks, or just
|
||||||
|
enjoying the chaos of everyday life together. Tech can wait; these moments
|
||||||
|
can't.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="border-l-4 border-[var(--neon-cyan)] pl-6">
|
<div className="border-l-4 border-[var(--neon-cyan)] pl-6">
|
||||||
<h3 className="font-mono text-sm font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
<h3 className="font-mono text-sm font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||||
{t('activeLifestyleTitle')}
|
[ACTIVE LIFESTYLE]
|
||||||
</h3>
|
</h3>
|
||||||
<p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
<p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
{t('activeLifestyleText')}
|
I believe in keeping the body active. Whether it's hitting the gym, playing
|
||||||
|
sports, or just staying on the move - physical activity keeps me sharp,
|
||||||
|
balanced, and ready for whatever life throws my way.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="border-l-4 border-[var(--neon-green)] pl-6">
|
<div className="border-l-4 border-[var(--neon-green)] pl-6">
|
||||||
<h3 className="font-mono text-sm font-bold text-[var(--neon-green)] uppercase mb-2">
|
<h3 className="font-mono text-sm font-bold text-[var(--neon-green)] uppercase mb-2">
|
||||||
{t('simpleThingsTitle')}
|
[ENJOYING THE SIMPLE THINGS]
|
||||||
</h3>
|
</h3>
|
||||||
<p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
<p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
{t('simpleThingsText')}
|
Life's too short not to enjoy it. A good drink, a relaxing
|
||||||
|
evening after a long day, or just not doing anything a blowing some steam off.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="border-l-4 border-[var(--neon-orange)] pl-6">
|
<div className="border-l-4 border-[var(--neon-orange)] pl-6">
|
||||||
<h3 className="font-mono text-sm font-bold text-[var(--neon-orange)] uppercase mb-2">
|
<h3 className="font-mono text-sm font-bold text-[var(--neon-orange)] uppercase mb-2">
|
||||||
{t('techPurposeTitle')}
|
[TECH WITH PURPOSE]
|
||||||
</h3>
|
</h3>
|
||||||
<p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
<p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
{t('techPurposeText')}
|
Yes, I love tech - self-hosting, privacy, tinkering with hardware. But it's
|
||||||
|
a tool, not a lifestyle. Tech should serve life, not the other way around.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -88,46 +96,51 @@ export default async function AboutPage({params}: Props) {
|
|||||||
{/* Content Section */}
|
{/* Content Section */}
|
||||||
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
||||||
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
||||||
{t('contentTitle')}
|
> WHAT YOU'LL FIND HERE
|
||||||
</h2>
|
</h2>
|
||||||
<p className="font-mono text-sm text-[rgb(var(--text-muted))] uppercase tracking-wider mb-6">
|
<p className="font-mono text-sm text-[rgb(var(--text-muted))] uppercase tracking-wider mb-6">
|
||||||
{t('contentSubtitle')}
|
CONTENT SCOPE // EVERYTHING FROM TECH TO LIFE
|
||||||
</p>
|
</p>
|
||||||
<ul className="space-y-3">
|
<ul className="space-y-3">
|
||||||
<li className="flex items-start gap-3">
|
<li className="flex items-start gap-3">
|
||||||
<span className="text-[var(--neon-pink)] font-mono font-bold">></span>
|
<span className="text-[var(--neon-pink)] font-mono font-bold">></span>
|
||||||
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
<strong>{t('contentThoughts')}</strong> - {t('contentThoughtsDesc')}
|
<strong>Thoughts & Opinions</strong> - My take on life, work, and everything in
|
||||||
|
between
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="flex items-start gap-3">
|
<li className="flex items-start gap-3">
|
||||||
<span className="text-[var(--neon-pink)] font-mono font-bold">></span>
|
<span className="text-[var(--neon-pink)] font-mono font-bold">></span>
|
||||||
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
<strong>{t('contentLifeFamily')}</strong> - {t('contentLifeFamilyDesc')}
|
<strong>Life & Family</strong> - Adventures in parenting, sports, and enjoying
|
||||||
|
the simple things
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="flex items-start gap-3">
|
<li className="flex items-start gap-3">
|
||||||
<span className="text-[var(--neon-cyan)] font-mono font-bold">></span>
|
<span className="text-[var(--neon-cyan)] font-mono font-bold">></span>
|
||||||
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
<strong>{t('contentTechResearch')}</strong> - {t('contentTechResearchDesc')}
|
<strong>Tech Research</strong> - When I dive into interesting technologies and
|
||||||
|
experiments
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="flex items-start gap-3">
|
<li className="flex items-start gap-3">
|
||||||
<span className="text-[var(--neon-cyan)] font-mono font-bold">></span>
|
<span className="text-[var(--neon-cyan)] font-mono font-bold">></span>
|
||||||
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
<strong>{t('contentSysAdmin')}</strong> - {t('contentSysAdminDesc')}
|
<strong>System Administration</strong> - Self-hosting, infrastructure, and
|
||||||
|
DevOps adventures
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="flex items-start gap-3">
|
<li className="flex items-start gap-3">
|
||||||
<span className="text-[var(--neon-cyan)] font-mono font-bold">></span>
|
<span className="text-[var(--neon-cyan)] font-mono font-bold">></span>
|
||||||
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
<strong>{t('contentDevelopment')}</strong> - {t('contentDevelopmentDesc')}
|
<strong>Development Insights</strong> - Lessons learned from building software
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li className="flex items-start gap-3">
|
<li className="flex items-start gap-3">
|
||||||
<span className="text-[var(--neon-green)] font-mono font-bold">></span>
|
<span className="text-[var(--neon-green)] font-mono font-bold">></span>
|
||||||
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
<strong>{t('contentRandom')}</strong> - {t('contentRandomDesc')}
|
<strong>Random Stuff</strong> - Because life doesn't fit into neat
|
||||||
|
categories!
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -136,39 +149,40 @@ export default async function AboutPage({params}: Props) {
|
|||||||
{/* Areas of Focus Section */}
|
{/* Areas of Focus Section */}
|
||||||
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
||||||
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
||||||
{t('focusTitle')}
|
> AREAS OF FOCUS
|
||||||
</h2>
|
</h2>
|
||||||
<div className="grid md:grid-cols-2 gap-4">
|
<div className="grid md:grid-cols-2 gap-4">
|
||||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-pink)] uppercase mb-2">
|
<h3 className="font-mono text-xs font-bold text-[var(--neon-pink)] uppercase mb-2">
|
||||||
{t('focusBeingDadTitle')}
|
[BEING A DAD]
|
||||||
</h3>
|
</h3>
|
||||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
{t('focusBeingDadText')}
|
Playing with my boy, teaching moments, watching him grow, building memories
|
||||||
|
together
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||||
{t('focusStayingActiveTitle')}
|
[STAYING ACTIVE]
|
||||||
</h3>
|
</h3>
|
||||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
{t('focusStayingActiveText')}
|
Gym sessions, sports, keeping fit, maintaining energy for life's demands
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-green)] uppercase mb-2">
|
<h3 className="font-mono text-xs font-bold text-[var(--neon-green)] uppercase mb-2">
|
||||||
{t('focusTechnologyTitle')}
|
[TECHNOLOGY & SYSTEMS]
|
||||||
</h3>
|
</h3>
|
||||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
{t('focusTechnologyText')}
|
Software development, infrastructure, DevOps, self-hosting adventures
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-orange)] uppercase mb-2">
|
<h3 className="font-mono text-xs font-bold text-[var(--neon-orange)] uppercase mb-2">
|
||||||
{t('focusLifeBalanceTitle')}
|
[LIFE BALANCE]
|
||||||
</h3>
|
</h3>
|
||||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
{t('focusLifeBalanceText')}
|
Relaxing with good company, enjoying downtime, appreciating the simple moments
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -176,42 +190,42 @@ export default async function AboutPage({params}: Props) {
|
|||||||
{/* Tech Stack Section */}
|
{/* Tech Stack Section */}
|
||||||
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
||||||
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
||||||
{t('techStackTitle')}
|
> TECH STACK
|
||||||
</h2>
|
</h2>
|
||||||
<p className="font-mono text-sm text-[rgb(var(--text-muted))] uppercase tracking-wider mb-6">
|
<p className="font-mono text-sm text-[rgb(var(--text-muted))] uppercase tracking-wider mb-6">
|
||||||
{t('techStackSubtitle')}
|
TOOLS I USE // WHEN NEEDED
|
||||||
</p>
|
</p>
|
||||||
<div className="grid md:grid-cols-2 gap-4">
|
<div className="grid md:grid-cols-2 gap-4">
|
||||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||||
{t('techStackDevelopmentTitle')}
|
[DEVELOPMENT]
|
||||||
</h3>
|
</h3>
|
||||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
{t('techStackDevelopmentText')}
|
.NET, Golang, TypeScript, Next.js, React
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||||
{t('techStackInfrastructureTitle')}
|
[INFRASTRUCTURE]
|
||||||
</h3>
|
</h3>
|
||||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
{t('techStackInfrastructureText')}
|
Windows Server, Linux, Docker, Hyper-V
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||||
{t('techStackDesignTitle')}
|
[DESIGN]
|
||||||
</h3>
|
</h3>
|
||||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
{t('techStackDesignText')}
|
Tailwind CSS, Markdown, Terminal aesthetics
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||||
{t('techStackSelfHostingTitle')}
|
[SELF-HOSTING]
|
||||||
</h3>
|
</h3>
|
||||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||||
{t('techStackSelfHostingText')}
|
Home lab, privacy-focused services, full control, Git server
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -219,7 +233,7 @@ export default async function AboutPage({params}: Props) {
|
|||||||
{/* Contact Section */}
|
{/* Contact Section */}
|
||||||
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
||||||
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
||||||
{t('contactTitle')}
|
> CONTACT
|
||||||
</h2>
|
</h2>
|
||||||
<div className="border-l-4 border-[var(--neon-pink)] pl-6">
|
<div className="border-l-4 border-[var(--neon-pink)] pl-6">
|
||||||
{/* <p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed mb-4">
|
{/* <p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed mb-4">
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { BlogCard } from '@/components/blog/blog-card'
|
|||||||
import { SearchBar } from '@/components/blog/search-bar'
|
import { SearchBar } from '@/components/blog/search-bar'
|
||||||
import { SortDropdown } from '@/components/blog/sort-dropdown'
|
import { SortDropdown } from '@/components/blog/sort-dropdown'
|
||||||
import { TagFilter } from '@/components/blog/tag-filter'
|
import { TagFilter } from '@/components/blog/tag-filter'
|
||||||
|
import { Navbar } from '@/components/blog/navbar'
|
||||||
|
|
||||||
interface BlogPageClientProps {
|
interface BlogPageClientProps {
|
||||||
posts: Post[]
|
posts: Post[]
|
||||||
@@ -141,7 +142,7 @@ export default function BlogPageClient({ posts, allTags }: BlogPageClientProps)
|
|||||||
disabled={currentPage === 1}
|
disabled={currentPage === 1}
|
||||||
className="px-6 py-3 font-mono text-sm uppercase border border-[rgb(var(--border-primary))] text-[rgb(var(--text-primary))] disabled:opacity-30 disabled:cursor-not-allowed hover:border-[var(--neon-cyan)] hover:text-[var(--neon-cyan)] transition-colors cursor-pointer"
|
className="px-6 py-3 font-mono text-sm uppercase border border-[rgb(var(--border-primary))] text-[rgb(var(--text-primary))] disabled:opacity-30 disabled:cursor-not-allowed hover:border-[var(--neon-cyan)] hover:text-[var(--neon-cyan)] transition-colors cursor-pointer"
|
||||||
>
|
>
|
||||||
{t('prev')}
|
< PREV
|
||||||
</button>
|
</button>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{Array.from({ length: totalPages }, (_, i) => i + 1).map(page => (
|
{Array.from({ length: totalPages }, (_, i) => i + 1).map(page => (
|
||||||
@@ -163,7 +164,7 @@ export default function BlogPageClient({ posts, allTags }: BlogPageClientProps)
|
|||||||
disabled={currentPage === totalPages}
|
disabled={currentPage === totalPages}
|
||||||
className="px-6 py-3 font-mono text-sm uppercase border border-[rgb(var(--border-primary))] text-[rgb(var(--text-primary))] disabled:opacity-30 disabled:cursor-not-allowed hover:border-[var(--neon-cyan)] hover:text-[var(--neon-cyan)] transition-colors cursor-pointer"
|
className="px-6 py-3 font-mono text-sm uppercase border border-[rgb(var(--border-primary))] text-[rgb(var(--text-primary))] disabled:opacity-30 disabled:cursor-not-allowed hover:border-[var(--neon-cyan)] hover:text-[var(--neon-cyan)] transition-colors cursor-pointer"
|
||||||
>
|
>
|
||||||
{t('next')}
|
NEXT >
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { getAllPosts } from '@/lib/markdown'
|
import { getAllPosts } from '@/lib/markdown'
|
||||||
import BlogPageClient from './blog-client'
|
import BlogPageClient from './blog-client'
|
||||||
import { setRequestLocale } from 'next-intl/server'
|
import {setRequestLocale} from 'next-intl/server'
|
||||||
|
|
||||||
export default async function BlogPage({ params }: { params: Promise<{ locale: string }> }) {
|
export default async function BlogPage() {
|
||||||
const { locale } = await params;
|
const posts = await getAllPosts()
|
||||||
await setRequestLocale(locale)
|
|
||||||
const posts = await getAllPosts(locale)
|
|
||||||
const allTags = Array.from(new Set(posts.flatMap(post => post.frontmatter.tags))).sort()
|
const allTags = Array.from(new Set(posts.flatMap(post => post.frontmatter.tags))).sort()
|
||||||
|
|
||||||
return <BlogPageClient posts={posts} allTags={allTags} />
|
return <BlogPageClient posts={posts} allTags={allTags} />
|
||||||
|
|||||||
@@ -3,18 +3,9 @@ import Image from 'next/image'
|
|||||||
import { getAllPosts } from '@/lib/markdown'
|
import { getAllPosts } from '@/lib/markdown'
|
||||||
import { formatDate } from '@/lib/utils'
|
import { formatDate } from '@/lib/utils'
|
||||||
import { ThemeToggle } from '@/components/theme-toggle'
|
import { ThemeToggle } from '@/components/theme-toggle'
|
||||||
import {setRequestLocale, getTranslations} from 'next-intl/server'
|
import {setRequestLocale} from 'next-intl/server'
|
||||||
|
|
||||||
type Props = {
|
|
||||||
params: Promise<{locale: string}>
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function HomePage({params}: Props) {
|
|
||||||
const {locale} = await params
|
|
||||||
setRequestLocale(locale)
|
|
||||||
const t = await getTranslations('Home')
|
|
||||||
const tNav = await getTranslations('Navigation')
|
|
||||||
|
|
||||||
|
export default async function HomePage() {
|
||||||
const allPosts = await getAllPosts()
|
const allPosts = await getAllPosts()
|
||||||
const featuredPosts = allPosts.slice(0, 6)
|
const featuredPosts = allPosts.slice(0, 6)
|
||||||
|
|
||||||
@@ -33,7 +24,7 @@ export default async function HomePage({params}: Props) {
|
|||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<Image src="/logo.png" alt="Logo" width={32} height={32} className="opacity-80" />
|
<Image src="/logo.png" alt="Logo" width={32} height={32} className="opacity-80" />
|
||||||
<span className="font-mono text-xs text-slate-500 uppercase tracking-widest">
|
<span className="font-mono text-xs text-slate-500 uppercase tracking-widest">
|
||||||
{t('terminalVersion')}
|
TERMINAL:// V2.0
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-4 items-center">
|
<div className="flex gap-4 items-center">
|
||||||
@@ -41,13 +32,13 @@ export default async function HomePage({params}: Props) {
|
|||||||
href="/blog"
|
href="/blog"
|
||||||
className="font-mono text-xs text-slate-600 dark:text-slate-400 uppercase tracking-wider hover:text-cyan-600 dark:hover:text-cyan-400"
|
className="font-mono text-xs text-slate-600 dark:text-slate-400 uppercase tracking-wider hover:text-cyan-600 dark:hover:text-cyan-400"
|
||||||
>
|
>
|
||||||
[{tNav('blog')}]
|
[BLOG]
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
href="/about"
|
href="/about"
|
||||||
className="font-mono text-xs text-slate-600 dark:text-slate-400 uppercase tracking-wider hover:text-cyan-600 dark:hover:text-cyan-400"
|
className="font-mono text-xs text-slate-600 dark:text-slate-400 uppercase tracking-wider hover:text-cyan-600 dark:hover:text-cyan-400"
|
||||||
>
|
>
|
||||||
[{tNav('about')}]
|
[ABOUT]
|
||||||
</Link>
|
</Link>
|
||||||
<ThemeToggle />
|
<ThemeToggle />
|
||||||
</div>
|
</div>
|
||||||
@@ -55,13 +46,15 @@ export default async function HomePage({params}: Props) {
|
|||||||
|
|
||||||
<div className="border-l-4 border-cyan-700 dark:border-cyan-900 pl-6 mb-8">
|
<div className="border-l-4 border-cyan-700 dark:border-cyan-900 pl-6 mb-8">
|
||||||
<p className="font-mono text-xs text-slate-500 dark:text-slate-500 uppercase tracking-widest mb-2">
|
<p className="font-mono text-xs text-slate-500 dark:text-slate-500 uppercase tracking-widest mb-2">
|
||||||
{t('documentLevel')}
|
DOCUMENT LEVEL-1 //
|
||||||
</p>
|
</p>
|
||||||
<h1 className="text-4xl md:text-6xl lg:text-7xl font-mono font-bold text-slate-900 dark:text-slate-100 uppercase tracking-tight mb-6">
|
<h1 className="text-4xl md:text-6xl lg:text-7xl font-mono font-bold text-slate-900 dark:text-slate-100 uppercase tracking-tight mb-6">
|
||||||
{t('heroTitle')}
|
BUILD. WRITE.
|
||||||
|
<br />
|
||||||
|
SHARE.
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-base md:text-lg lg:text-xl text-slate-700 dark:text-slate-400 font-mono leading-relaxed max-w-2xl">
|
<p className="text-base md:text-lg lg:text-xl text-slate-700 dark:text-slate-400 font-mono leading-relaxed max-w-2xl">
|
||||||
{t('heroSubtitle')}
|
> Explore ideas
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -70,13 +63,13 @@ export default async function HomePage({params}: Props) {
|
|||||||
href="/blog"
|
href="/blog"
|
||||||
className="px-6 md:px-8 py-3 md:py-4 bg-cyan-700 dark:bg-cyan-900 text-white dark:text-slate-100 border-2 border-cyan-600 dark:border-cyan-700 font-mono font-bold uppercase text-xs md:text-sm tracking-wider hover:bg-cyan-600 dark:hover:bg-cyan-800 hover:border-cyan-500 dark:hover:border-cyan-600 rounded-none transition-colors duration-200"
|
className="px-6 md:px-8 py-3 md:py-4 bg-cyan-700 dark:bg-cyan-900 text-white dark:text-slate-100 border-2 border-cyan-600 dark:border-cyan-700 font-mono font-bold uppercase text-xs md:text-sm tracking-wider hover:bg-cyan-600 dark:hover:bg-cyan-800 hover:border-cyan-500 dark:hover:border-cyan-600 rounded-none transition-colors duration-200"
|
||||||
>
|
>
|
||||||
{t('checkPostsButton')}
|
[CHECK POSTS]
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
href="/about"
|
href="/about"
|
||||||
className="px-6 md:px-8 py-3 md:py-4 bg-transparent text-slate-700 dark:text-slate-300 border-2 border-slate-400 dark:border-slate-700 font-mono font-bold uppercase text-xs md:text-sm tracking-wider hover:bg-slate-200 dark:hover:bg-slate-800 hover:border-slate-500 dark:hover:border-slate-600 rounded-none transition-colors duration-200"
|
className="px-6 md:px-8 py-3 md:py-4 bg-transparent text-slate-700 dark:text-slate-300 border-2 border-slate-400 dark:border-slate-700 font-mono font-bold uppercase text-xs md:text-sm tracking-wider hover:bg-slate-200 dark:hover:bg-slate-800 hover:border-slate-500 dark:hover:border-slate-600 rounded-none transition-colors duration-200"
|
||||||
>
|
>
|
||||||
{t('aboutMeButton')}
|
[ABOUT ME]
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -88,10 +81,10 @@ export default async function HomePage({params}: Props) {
|
|||||||
<div className="max-w-7xl mx-auto px-6">
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
<div className="border-l-4 border-emerald-700 dark:border-emerald-900 pl-6 mb-12">
|
<div className="border-l-4 border-emerald-700 dark:border-emerald-900 pl-6 mb-12">
|
||||||
<p className="font-mono text-xs text-slate-500 dark:text-slate-500 uppercase tracking-widest mb-2">
|
<p className="font-mono text-xs text-slate-500 dark:text-slate-500 uppercase tracking-widest mb-2">
|
||||||
{t('recentEntriesLabel')}
|
ARCHIVE ACCESS // RECENT ENTRIES
|
||||||
</p>
|
</p>
|
||||||
<h2 className="text-3xl md:text-5xl font-mono font-bold text-slate-900 dark:text-slate-100 uppercase tracking-tight">
|
<h2 className="text-3xl md:text-5xl font-mono font-bold text-slate-900 dark:text-slate-100 uppercase tracking-tight">
|
||||||
{t('recentEntriesTitle')}
|
> RECENT ENTRIES
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -141,7 +134,7 @@ export default async function HomePage({params}: Props) {
|
|||||||
href={`/blog/${post.slug}`}
|
href={`/blog/${post.slug}`}
|
||||||
className="inline-flex items-center text-cyan-600 dark:text-cyan-400 font-mono text-xs font-bold uppercase tracking-wider hover:text-cyan-500 dark:hover:text-cyan-300 border-2 border-slate-400 dark:border-slate-700 px-4 py-2 hover:border-cyan-700 dark:hover:border-cyan-900 transition-colors duration-200"
|
className="inline-flex items-center text-cyan-600 dark:text-cyan-400 font-mono text-xs font-bold uppercase tracking-wider hover:text-cyan-500 dark:hover:text-cyan-300 border-2 border-slate-400 dark:border-slate-700 px-4 py-2 hover:border-cyan-700 dark:hover:border-cyan-900 transition-colors duration-200"
|
||||||
>
|
>
|
||||||
{t('accessButton')}
|
[ACCESEAZĂ] >>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
@@ -154,14 +147,14 @@ export default async function HomePage({params}: Props) {
|
|||||||
href="/blog"
|
href="/blog"
|
||||||
className="inline-flex items-center px-8 py-4 bg-transparent text-slate-700 dark:text-slate-300 border-2 border-slate-400 dark:border-slate-700 font-mono font-bold uppercase text-sm tracking-wider hover:bg-slate-200 dark:hover:bg-slate-800 hover:border-slate-500 dark:hover:border-slate-600 transition-colors duration-200"
|
className="inline-flex items-center px-8 py-4 bg-transparent text-slate-700 dark:text-slate-300 border-2 border-slate-400 dark:border-slate-700 font-mono font-bold uppercase text-sm tracking-wider hover:bg-slate-200 dark:hover:bg-slate-800 hover:border-slate-500 dark:hover:border-slate-600 transition-colors duration-200"
|
||||||
>
|
>
|
||||||
{t('seePostsButton')}
|
[SEE POSTS] >>
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
<Link
|
<Link
|
||||||
href="/tags"
|
href="/tags"
|
||||||
className="inline-flex items-center px-8 py-4 bg-transparent text-slate-700 dark:text-slate-300 border-2 border-slate-400 dark:border-slate-700 font-mono font-bold uppercase text-sm tracking-wider hover:bg-slate-200 dark:hover:bg-slate-800 hover:border-slate-500 dark:hover:border-slate-600 transition-colors duration-200"
|
className="inline-flex items-center px-8 py-4 bg-transparent text-slate-700 dark:text-slate-300 border-2 border-slate-400 dark:border-slate-700 font-mono font-bold uppercase text-sm tracking-wider hover:bg-slate-200 dark:hover:bg-slate-800 hover:border-slate-500 dark:hover:border-slate-600 transition-colors duration-200"
|
||||||
>
|
>
|
||||||
{t('seeAllTagsButton')}
|
[SEE ALL TAGS] >>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 'First post'
|
title: 'Why I created this page'
|
||||||
description: 'First post'
|
description: 'First post'
|
||||||
date: '2025-12-02'
|
date: '2025-12-02'
|
||||||
author: 'Rares'
|
author: 'Rares'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: 'Primul post'
|
title: 'Why I created this page'
|
||||||
description: 'Primul post'
|
description: 'First post'
|
||||||
date: '2025-12-02'
|
date: '2025-12-02'
|
||||||
author: 'Rares'
|
author: 'Rares'
|
||||||
category: 'Opinion'
|
category: 'Opinion'
|
||||||
@@ -13,28 +13,29 @@ draft: false
|
|||||||
|
|
||||||
Daca te intrebi de ce aceata pagina? Pentru ca vreau sa jurnalizez lucrurile la care lucrez, sau gandurile pe care vreua sa le impartesesc.
|
Daca te intrebi de ce aceata pagina? Pentru ca vreau sa jurnalizez lucrurile la care lucrez, sau gandurile pe care vreua sa le impartesesc.
|
||||||
|
|
||||||
## De ce blog?
|
## Why a blog?
|
||||||
|
|
||||||
Dacă te gândești de ce să mai creezi inca un blog cand sunt atea pe net, pai ideea este ca este si ca un jurnal, unde postez lucruri si ma ajuta sa revin la ceea ce am investigat.
|
You might be thinking, "Why create another tech blog? There are plenty out there."
|
||||||
|
Well, yes, there are. But I believe that sharing some of my opinions and experiences will eventually act out as a journal:
|
||||||
|
|
||||||
1. **Este personal**: Nu este un lucru formal, chiar daca am lucrat in corporate, unde toti se asteapta sa fii prietenos si zambaret mereu, aici o sa fie mai sincere opiniile.
|
1. **Personal touch**: Even though i've been working corporate all my career, this webpage won't contain that sugar coated language 😅. It's a place where you'll get to know me – my thoughts, my mistakes, and my victories. I believe that this personal touch makes the content more engaging and relatable.
|
||||||
2. **Mai mult decat tech**: O sa scriu despre tech dar, nu ăsta e focusul aici
|
2. **Beyond tech**: While I'll be writing about technology, I also want to explore other topics that interest me, such as mental health, productivity and so on.... I think a well-rounded approach can help create a more engaging and informative space.
|
||||||
3. **Cum fac selfhost**: Fac selfhost, la cateva servicii utile: git, webpage-ul acesta. O sa incerc sa povestesc si cum fac mentenanta sau ce probleme am intampinat pe parcursul acestor deploymenturi.
|
3. **Self-hosting adventure**: As you might have guessed from the title, this blog is self-hosted. This was an exciting journey for me, and I'll be sharing my experiences, challenges, and learnings along the way. If you're interested in self-hosting or just want to understand what it's all about, you might find what worked for me or didn't.
|
||||||
|
|
||||||
## De ce selfhost?
|
## Why self-host?
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Am inceput sa fac hosting acasa din cateva motive:
|
Now, let's talk about why I chose to self-host this blog. In a nutshell, self-hosting gave me:
|
||||||
|
|
||||||
- **Detin controlul**: Nu depind de cloud providers sau alte 3rd parties (inafara de VPS).
|
- **Full control**: By hosting my own website, I have complete control over my content and how it's displayed. No more compromises or limitations imposed by third-party platforms.
|
||||||
- **Nu exista scurgeri de informatii**: Sunt unele lucruri pe care nu as vrea sa le impartasesc cu marii provideri de servicii cloud.
|
- **Owning my data**: It's just, that I can have control over my data without others snooping around.
|
||||||
- **E destul de smecher**: Este destul de tare sa vezi cum datele ruleaza pe hardwareul de la tine din casa.
|
- **It's fun**: Started looking into sysadmin/devops for a long time, after a burnout I stepped into selfhosting more convincingly.
|
||||||
|
|
||||||
## Ce este aici de fapt
|
## What to expect
|
||||||
|
|
||||||
E un blog, o jurnalizare e ceea ce fac eu, ma ajuta sa tin evidenta cand explica lucruri.
|
As I mentioned earlier, this blog will be a mix of tech tutorials, personal thoughts, and everything in between. Here's what you can look forward to:
|
||||||
|
|
||||||
- **Resurse tehnice**: Ghiduri pas cu pas despre diverse subiecte, de la configurarea propriului mediului de dezvoltare până la ajustarea serverului.
|
- **Tech how-tos**: Step-by-step guides on various topics, from setting up your own development environment to configuring your server.
|
||||||
- **Experiențe personale cu selfhosting**: Ce realizat, cum am solutionat, provocari ...
|
- **Self-hosting adventures**: My experiences, learnings, and tips on self-hosting, including challenges faced and solutions implemented.
|
||||||
- **Gânduri aleatorii**: Gânduri despre eficiența profesională, sănătatea mintală și alte interese personale care nu sunt direct legate de tehnologie.
|
- **Random musings**: Thoughts on productivity, mental health, and other interests of mine that might not be directly related to tech.
|
||||||
|
|||||||
@@ -1,135 +0,0 @@
|
|||||||
# Docker Compose Configuration for Staging Deployment
|
|
||||||
# This file is used by CI/CD to deploy the application on staging servers
|
|
||||||
#
|
|
||||||
# Key differences from production docker-compose.prod.yml:
|
|
||||||
# - Container name: mypage-staging (vs mypage-prod)
|
|
||||||
# - Port mapping: 3031:3030 (vs 3030:3030)
|
|
||||||
# - Network name: mypage-staging-network (vs mypage-network)
|
|
||||||
# - Image tag: staging (vs latest)
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# 1. This file is automatically copied to server by CI/CD workflow
|
|
||||||
# 2. Server pulls image from registry: docker compose -f docker-compose.staging.yml pull
|
|
||||||
# 3. Server starts container: docker compose -f docker-compose.staging.yml up -d
|
|
||||||
#
|
|
||||||
# Manual deployment (if CI/CD is not available):
|
|
||||||
# ssh user@staging-server
|
|
||||||
# cd /opt/mypage-staging
|
|
||||||
# docker compose -f docker-compose.staging.yml pull
|
|
||||||
# docker compose -f docker-compose.staging.yml up -d --force-recreate
|
|
||||||
|
|
||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
|
||||||
mypage:
|
|
||||||
# Use pre-built image from private registry with staging tag
|
|
||||||
# This image is built and pushed by the CI/CD workflow
|
|
||||||
# Format: REGISTRY_URL/IMAGE_NAME:TAG
|
|
||||||
image: repository.workspace:5000/mypage:staging
|
|
||||||
|
|
||||||
container_name: mypage-staging
|
|
||||||
|
|
||||||
# Restart policy: always restart on failure or server reboot
|
|
||||||
# This ensures high availability in staging
|
|
||||||
restart: always
|
|
||||||
|
|
||||||
# Port mapping: host:container
|
|
||||||
# Staging runs on port 3031 to avoid conflicts with production (3030)
|
|
||||||
# The application will be accessible at http://SERVER_IP:3031
|
|
||||||
ports:
|
|
||||||
- "3031:3030"
|
|
||||||
|
|
||||||
# Staging environment variables
|
|
||||||
environment:
|
|
||||||
- NODE_ENV=production
|
|
||||||
- NEXT_TELEMETRY_DISABLED=1
|
|
||||||
- PORT=3030
|
|
||||||
- HOSTNAME=0.0.0.0
|
|
||||||
# Add any other staging-specific environment variables here
|
|
||||||
# Example:
|
|
||||||
# - DATABASE_URL=postgresql://user:pass@db:5432/mypage_staging
|
|
||||||
# - REDIS_URL=redis://redis:6379
|
|
||||||
|
|
||||||
# Persistent volumes for logs (optional)
|
|
||||||
# Uncomment if your application writes logs
|
|
||||||
volumes:
|
|
||||||
- ./data/logs:/app/logs
|
|
||||||
|
|
||||||
# Health check configuration
|
|
||||||
# Docker monitors the application and marks it unhealthy if checks fail
|
|
||||||
# If container is unhealthy, restart policy will trigger a restart
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:3030/", "||", "exit", "1"]
|
|
||||||
interval: 30s # Check every 30 seconds
|
|
||||||
timeout: 10s # Wait up to 10 seconds for response
|
|
||||||
retries: 3 # Mark unhealthy after 3 consecutive failures
|
|
||||||
start_period: 40s # Grace period during container startup
|
|
||||||
|
|
||||||
# Resource limits for staging
|
|
||||||
# Prevents container from consuming all server resources
|
|
||||||
# deploy:
|
|
||||||
# resources:
|
|
||||||
# limits:
|
|
||||||
# cpus: '1.0' # Maximum 1 CPU core
|
|
||||||
# memory: 512M # Maximum 512MB RAM
|
|
||||||
# reservations:
|
|
||||||
# cpus: '0.25' # Reserve at least 0.25 CPU cores
|
|
||||||
# memory: 256M # Reserve at least 256MB RAM
|
|
||||||
|
|
||||||
# Network configuration
|
|
||||||
networks:
|
|
||||||
- mypage-staging-network
|
|
||||||
|
|
||||||
# Logging configuration
|
|
||||||
# Prevents logs from consuming all disk space
|
|
||||||
logging:
|
|
||||||
driver: "json-file"
|
|
||||||
options:
|
|
||||||
max-size: "10m" # Maximum 10MB per log file
|
|
||||||
max-file: "3" # Keep only 3 log files (30MB total)
|
|
||||||
|
|
||||||
# Network definition
|
|
||||||
networks:
|
|
||||||
mypage-staging-network:
|
|
||||||
driver: bridge
|
|
||||||
|
|
||||||
# ============================================
|
|
||||||
# Staging Deployment Commands
|
|
||||||
# ============================================
|
|
||||||
#
|
|
||||||
# Pull latest image from registry:
|
|
||||||
# docker compose -f docker-compose.staging.yml pull
|
|
||||||
#
|
|
||||||
# Start/update containers:
|
|
||||||
# docker compose -f docker-compose.staging.yml up -d --force-recreate
|
|
||||||
#
|
|
||||||
# View logs:
|
|
||||||
# docker compose -f docker-compose.staging.yml logs -f mypage
|
|
||||||
#
|
|
||||||
# Check health status:
|
|
||||||
# docker inspect mypage-staging | grep -A 10 Health
|
|
||||||
#
|
|
||||||
# Stop containers:
|
|
||||||
# docker compose -f docker-compose.staging.yml down
|
|
||||||
#
|
|
||||||
# Restart containers:
|
|
||||||
# docker compose -f docker-compose.staging.yml restart
|
|
||||||
#
|
|
||||||
# Remove old/unused images (cleanup):
|
|
||||||
# docker image prune -f
|
|
||||||
#
|
|
||||||
# ============================================
|
|
||||||
# Troubleshooting
|
|
||||||
# ============================================
|
|
||||||
#
|
|
||||||
# If container keeps restarting:
|
|
||||||
# 1. Check logs: docker compose -f docker-compose.staging.yml logs --tail=100
|
|
||||||
# 2. Check health: docker inspect mypage-staging | grep -A 10 Health
|
|
||||||
# 3. Verify port is not already in use: netstat -tulpn | grep 3031
|
|
||||||
# 4. Check resource usage: docker stats mypage-staging
|
|
||||||
#
|
|
||||||
# If health check fails:
|
|
||||||
# 1. Test manually: docker exec mypage-staging curl -f http://localhost:3030/
|
|
||||||
# 2. Check if Next.js server is running: docker exec mypage-staging ps aux
|
|
||||||
# 3. Verify environment variables: docker exec mypage-staging env
|
|
||||||
#
|
|
||||||
@@ -18,21 +18,6 @@
|
|||||||
"about": "About"
|
"about": "About"
|
||||||
},
|
},
|
||||||
|
|
||||||
"Home": {
|
|
||||||
"terminalVersion": "TERMINAL:// V2.0",
|
|
||||||
"documentLevel": "DOCUMENT LEVEL-1 //",
|
|
||||||
"heroTitle": "BUILD. WRITE. SHARE.",
|
|
||||||
"heroSubtitle": "> Explore ideas",
|
|
||||||
"checkPostsButton": "[CHECK POSTS]",
|
|
||||||
"aboutMeButton": "[ABOUT ME]",
|
|
||||||
"recentEntriesLabel": "ARCHIVE ACCESS // RECENT ENTRIES",
|
|
||||||
"recentEntriesTitle": "> RECENT ENTRIES",
|
|
||||||
"fileLabel": "FILE#{number} // {category}",
|
|
||||||
"accessButton": "[ACCESS] >>",
|
|
||||||
"seePostsButton": "[SEE POSTS] >>",
|
|
||||||
"seeAllTagsButton": "[SEE ALL TAGS] >>"
|
|
||||||
},
|
|
||||||
|
|
||||||
"BlogListing": {
|
"BlogListing": {
|
||||||
"title": "Blog",
|
"title": "Blog",
|
||||||
"subtitle": "Latest articles and thoughts",
|
"subtitle": "Latest articles and thoughts",
|
||||||
@@ -44,9 +29,7 @@
|
|||||||
"filterByTag": "Filter by tag",
|
"filterByTag": "Filter by tag",
|
||||||
"clearFilters": "Clear filters",
|
"clearFilters": "Clear filters",
|
||||||
"foundPosts": "Found {count} posts",
|
"foundPosts": "Found {count} posts",
|
||||||
"noPosts": "No posts found",
|
"noPosts": "No posts found"
|
||||||
"prev": "< PREV",
|
|
||||||
"next": "NEXT >"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"BlogPost": {
|
"BlogPost": {
|
||||||
@@ -70,54 +53,7 @@
|
|||||||
|
|
||||||
"About": {
|
"About": {
|
||||||
"title": "About",
|
"title": "About",
|
||||||
"subtitle": "Learn more about me",
|
"subtitle": "Learn more about me"
|
||||||
"classificationHeader": ">> _DOC://PUBLIC_ACCESS",
|
|
||||||
"mainTitle": "ABOUT ME_",
|
|
||||||
"introLabel": "STATUS: ACTIVE // ROLE: DAD + DEV",
|
|
||||||
"introParagraph1": "Welcome to my corner of the internet! This is where I share my thoughts, opinions, and experiences - from tech adventures to life as a family man. Yes, I love technology, but there's so much more to life than just code and servers.",
|
|
||||||
"lifeValuesTitle": "> LIFE & VALUES",
|
|
||||||
"familyFirstTitle": "[FAMILY FIRST]",
|
|
||||||
"familyFirstText": "Being a dad to an amazing toddler is my most important role. Family time is sacred - whether it's building block towers, exploring parks, or just enjoying the chaos of everyday life together. Tech can wait; these moments can't.",
|
|
||||||
"activeLifestyleTitle": "[ACTIVE LIFESTYLE]",
|
|
||||||
"activeLifestyleText": "I believe in keeping the body active. Whether it's hitting the gym, playing sports, or just staying on the move - physical activity keeps me sharp, balanced, and ready for whatever life throws my way.",
|
|
||||||
"simpleThingsTitle": "[ENJOYING THE SIMPLE THINGS]",
|
|
||||||
"simpleThingsText": "Life's too short not to enjoy it. A good drink, a relaxing evening after a long day, or just not doing anything a blowing some steam off.",
|
|
||||||
"techPurposeTitle": "[TECH WITH PURPOSE]",
|
|
||||||
"techPurposeText": "Yes, I love tech - self-hosting, privacy, tinkering with hardware. But it's a tool, not a lifestyle. Tech should serve life, not the other way around.",
|
|
||||||
"contentTitle": "> WHAT YOU'LL FIND HERE",
|
|
||||||
"contentSubtitle": "CONTENT SCOPE // EVERYTHING FROM TECH TO LIFE",
|
|
||||||
"contentThoughts": "Thoughts & Opinions",
|
|
||||||
"contentThoughtsDesc": "My take on life, work, and everything in between",
|
|
||||||
"contentLifeFamily": "Life & Family",
|
|
||||||
"contentLifeFamilyDesc": "Adventures in parenting, sports, and enjoying the simple things",
|
|
||||||
"contentTechResearch": "Tech Research",
|
|
||||||
"contentTechResearchDesc": "When I dive into interesting technologies and experiments",
|
|
||||||
"contentSysAdmin": "System Administration",
|
|
||||||
"contentSysAdminDesc": "Self-hosting, infrastructure, and DevOps adventures",
|
|
||||||
"contentDevelopment": "Development Insights",
|
|
||||||
"contentDevelopmentDesc": "Lessons learned from building software",
|
|
||||||
"contentRandom": "Random Stuff",
|
|
||||||
"contentRandomDesc": "Because life doesn't fit into neat categories!",
|
|
||||||
"focusTitle": "> AREAS OF FOCUS",
|
|
||||||
"focusBeingDadTitle": "[BEING A DAD]",
|
|
||||||
"focusBeingDadText": "Playing with my boy, teaching moments, watching him grow, building memories together",
|
|
||||||
"focusStayingActiveTitle": "[STAYING ACTIVE]",
|
|
||||||
"focusStayingActiveText": "Gym sessions, sports, keeping fit, maintaining energy for life's demands",
|
|
||||||
"focusTechnologyTitle": "[TECHNOLOGY & SYSTEMS]",
|
|
||||||
"focusTechnologyText": "Software development, infrastructure, DevOps, self-hosting adventures",
|
|
||||||
"focusLifeBalanceTitle": "[LIFE BALANCE]",
|
|
||||||
"focusLifeBalanceText": "Relaxing with good company, enjoying downtime, appreciating the simple moments",
|
|
||||||
"techStackTitle": "> TECH STACK",
|
|
||||||
"techStackSubtitle": "TOOLS I USE // WHEN NEEDED",
|
|
||||||
"techStackDevelopmentTitle": "[DEVELOPMENT]",
|
|
||||||
"techStackDevelopmentText": ".NET, Golang, TypeScript, Next.js, React",
|
|
||||||
"techStackInfrastructureTitle": "[INFRASTRUCTURE]",
|
|
||||||
"techStackInfrastructureText": "Windows Server, Linux, Docker, Hyper-V",
|
|
||||||
"techStackDesignTitle": "[DESIGN]",
|
|
||||||
"techStackDesignText": "Tailwind CSS, Markdown, Terminal aesthetics",
|
|
||||||
"techStackSelfHostingTitle": "[SELF-HOSTING]",
|
|
||||||
"techStackSelfHostingText": "Home lab, privacy-focused services, full control, Git server",
|
|
||||||
"contactTitle": "> CONTACT"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"NotFound": {
|
"NotFound": {
|
||||||
|
|||||||
@@ -3,32 +3,21 @@
|
|||||||
"siteTitle": "Blog Personal",
|
"siteTitle": "Blog Personal",
|
||||||
"siteDescription": "Gânduri despre tehnologie și dezvoltare"
|
"siteDescription": "Gânduri despre tehnologie și dezvoltare"
|
||||||
},
|
},
|
||||||
|
|
||||||
"Navigation": {
|
"Navigation": {
|
||||||
"home": "Acasă",
|
"home": "Acasă",
|
||||||
"blog": "Blog",
|
"blog": "Blog",
|
||||||
"tags": "Etichete",
|
"tags": "Etichete",
|
||||||
"about": "Despre"
|
"about": "Despre"
|
||||||
},
|
},
|
||||||
|
|
||||||
"Breadcrumbs": {
|
"Breadcrumbs": {
|
||||||
"home": "Acasă",
|
"home": "Acasă",
|
||||||
"blog": "Blog",
|
"blog": "Blog",
|
||||||
"tags": "Etichete",
|
"tags": "Etichete",
|
||||||
"about": "Despre"
|
"about": "Despre"
|
||||||
},
|
},
|
||||||
"Home": {
|
|
||||||
"terminalVersion": "TERMINAL:// V2.0",
|
|
||||||
"documentLevel": "DOCUMENT LEVEL-1 //",
|
|
||||||
"heroTitle": "BUILD. WRITE. SHARE.",
|
|
||||||
"heroSubtitle": "> Explore ideas",
|
|
||||||
"checkPostsButton": "[CHECK POSTS]",
|
|
||||||
"aboutMeButton": "[ABOUT ME]",
|
|
||||||
"recentEntriesLabel": "ARCHIVE ACCESS // RECENT ENTRIES",
|
|
||||||
"recentEntriesTitle": "> RECENT ENTRIES",
|
|
||||||
"fileLabel": "FILE#{number} // {category}",
|
|
||||||
"accessButton": "[ACCESS] >>",
|
|
||||||
"seePostsButton": "[SEE POSTS] >>",
|
|
||||||
"seeAllTagsButton": "[SEE ALL TAGS] >>"
|
|
||||||
},
|
|
||||||
"BlogListing": {
|
"BlogListing": {
|
||||||
"title": "Blog",
|
"title": "Blog",
|
||||||
"subtitle": "Ultimele articole și gânduri",
|
"subtitle": "Ultimele articole și gânduri",
|
||||||
@@ -40,10 +29,9 @@
|
|||||||
"filterByTag": "Filtrează după etichetă",
|
"filterByTag": "Filtrează după etichetă",
|
||||||
"clearFilters": "Șterge filtrele",
|
"clearFilters": "Șterge filtrele",
|
||||||
"foundPosts": "{count} articole găsite",
|
"foundPosts": "{count} articole găsite",
|
||||||
"noPosts": "Niciun articol găsit",
|
"noPosts": "Niciun articol găsit"
|
||||||
"prev": "< PREV",
|
|
||||||
"next": "NEXT >"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"BlogPost": {
|
"BlogPost": {
|
||||||
"readMore": "Citește mai mult",
|
"readMore": "Citește mai mult",
|
||||||
"readingTime": "{minutes} min citire",
|
"readingTime": "{minutes} min citire",
|
||||||
@@ -53,6 +41,7 @@
|
|||||||
"relatedPosts": "Articole similare",
|
"relatedPosts": "Articole similare",
|
||||||
"sharePost": "Distribuie acest articol"
|
"sharePost": "Distribuie acest articol"
|
||||||
},
|
},
|
||||||
|
|
||||||
"Tags": {
|
"Tags": {
|
||||||
"title": "Etichete",
|
"title": "Etichete",
|
||||||
"subtitle": "Navighează după subiect",
|
"subtitle": "Navighează după subiect",
|
||||||
@@ -61,64 +50,20 @@
|
|||||||
"relatedTags": "Etichete similare",
|
"relatedTags": "Etichete similare",
|
||||||
"quickNav": "Navigare rapidă"
|
"quickNav": "Navigare rapidă"
|
||||||
},
|
},
|
||||||
|
|
||||||
"About": {
|
"About": {
|
||||||
"title": "Despre",
|
"title": "Despre",
|
||||||
"subtitle": "Află mai multe despre mine",
|
"subtitle": "Află mai multe despre mine"
|
||||||
"classificationHeader": ">> _DOC://PUBLIC_ACCESS",
|
|
||||||
"mainTitle": "DESPRE_",
|
|
||||||
"introLabel": "STATUS: ACTIV // ROL: TATĂ + DEV",
|
|
||||||
"introParagraph1": "Mi-am făcut un colțișor pe internet unde pot să împărtășesc cam tot ce vreau. O să găsești aici și tech, și viață, și haosul de zi cu zi.",
|
|
||||||
"lifeValuesTitle": "> VIAȚĂ & VALORI",
|
|
||||||
"familyFirstTitle": "[FAMILIA PE PRIMUL LOC]",
|
|
||||||
"familyFirstText": "Să fiu tată pentru un puști genial e cel mai important rol al meu. Timpul cu familia e sfânt – fie că construim turnuri din cuburi, explorăm parcuri sau doar trăim frumos haosul de zi cu zi. Tech-ul poate să aștepte, momentele astea nu.",
|
|
||||||
"activeLifestyleTitle": "[STIL DE VIAȚĂ ACTIV]",
|
|
||||||
"activeLifestyleText": "Încerc să-mi țin corpul în mișcare. Sală, sport, orice mă scoate din scaun. Mă ajută să fiu mai clar la minte, mai echilibrat și pregătit de ce aruncă viața în mine.",
|
|
||||||
"simpleThingsTitle": "[BUCURIA LUCRURILOR SIMPLE]",
|
|
||||||
"simpleThingsText": "Viața e prea scurtă să n-o savurezi. O băutură bună, o seară liniștită după o zi grea sau pur și simplu să nu faci nimic și să lași aburii să iasă… și e perfect așa.",
|
|
||||||
"techPurposeTitle": "[TECH CU SENS]",
|
|
||||||
"techPurposeText": "Da, îmi place tehnologia – self-hosting, privacy, joacă cu hardware. Dar pentru mine e o unealtă, nu un stil de viață. Tech-ul ar trebui să lucreze pentru tine, nu tu pentru el.",
|
|
||||||
"contentTitle": "> CE GĂSEȘTI AICI",
|
|
||||||
"contentSubtitle": "CONTENT SCOPE // DE LA TECH LA VIAȚĂ",
|
|
||||||
"contentThoughts": "Gânduri & Opinii",
|
|
||||||
"contentThoughtsDesc": "Cum văd eu viața, munca și tot ce e între ele",
|
|
||||||
"contentLifeFamily": "Viață & Familie",
|
|
||||||
"contentLifeFamilyDesc": "Aventuri de părinte, sport și bucuria lucrurilor mici",
|
|
||||||
"contentTechResearch": "Experimente Tech",
|
|
||||||
"contentTechResearchDesc": "Când mă afund în tehnologii interesante și experimente ciudate",
|
|
||||||
"contentSysAdmin": "Administrare Sisteme",
|
|
||||||
"contentSysAdminDesc": "Self-hosting, infrastructură și aventuri de tip DevOps",
|
|
||||||
"contentDevelopment": "Development Insights",
|
|
||||||
"contentDevelopmentDesc": "Lecții învățate din proiectele pe care le construiesc",
|
|
||||||
"contentRandom": "Chestii Random",
|
|
||||||
"contentRandomDesc": "Pentru că viața nu intră mereu frumos pe categorii!",
|
|
||||||
"focusTitle": "> ZONE DE FOCUS",
|
|
||||||
"focusBeingDadTitle": "[TATĂ ÎN PRIMUL RÂND]",
|
|
||||||
"focusBeingDadText": "Joacă cu băiatul meu, momente de învățat, să-l văd cum crește și să strângem amintiri împreună",
|
|
||||||
"focusStayingActiveTitle": "[SĂ RĂMÂN ACTIV]",
|
|
||||||
"focusStayingActiveText": "Sesiuni la sală, sport, să mă țin în formă și cu energie pentru tot ce am de dus",
|
|
||||||
"focusTechnologyTitle": "[TECH & SISTEME]",
|
|
||||||
"focusTechnologyText": "Dezvoltare software, infrastructură, DevOps, aventuri de self-hosting",
|
|
||||||
"focusLifeBalanceTitle": "[ECHILIBRU ÎN VIAȚĂ]",
|
|
||||||
"focusLifeBalanceText": "Relax cu prietenii, timp de respiro, apreciat momentele simple",
|
|
||||||
"techStackTitle": "> TECH STACK",
|
|
||||||
"techStackSubtitle": "UNELTELE PE CARE LE FOLOSESC // CÂND TREBUIE",
|
|
||||||
"techStackDevelopmentTitle": "[DEVELOPMENT]",
|
|
||||||
"techStackDevelopmentText": ".NET, Golang, TypeScript, Next.js, React",
|
|
||||||
"techStackInfrastructureTitle": "[INFRASTRUCTURĂ]",
|
|
||||||
"techStackInfrastructureText": "Windows Server, Linux, Docker, Hyper-V",
|
|
||||||
"techStackDesignTitle": "[DESIGN]",
|
|
||||||
"techStackDesignText": "Tailwind CSS, Markdown",
|
|
||||||
"techStackSelfHostingTitle": "[SELF-HOSTING]",
|
|
||||||
"techStackSelfHostingText": "Home lab, servicii cu focus pe privacy, control total, server Git",
|
|
||||||
"contactTitle": "> CONTACT"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"NotFound": {
|
"NotFound": {
|
||||||
"title": "Pagina nu a fost găsită",
|
"title": "Pagina nu a fost găsită",
|
||||||
"description": "Pagina pe care o cauți nu există",
|
"description": "Pagina pe care o cauți nu există",
|
||||||
"goHome": "Mergi la pagina principală"
|
"goHome": "Mergi la pagina principală"
|
||||||
},
|
},
|
||||||
|
|
||||||
"LanguageSwitcher": {
|
"LanguageSwitcher": {
|
||||||
"switchLanguage": "Schimbă limba",
|
"switchLanguage": "Schimbă limba",
|
||||||
"currentLanguage": "Limba curentă"
|
"currentLanguage": "Limba curentă"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
379
package-lock.json
generated
379
package-lock.json
generated
@@ -11,16 +11,16 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.17",
|
"@tailwindcss/postcss": "^4.1.17",
|
||||||
"@tailwindcss/typography": "^0.5.19",
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.0",
|
||||||
"@types/react": "^19.2.7",
|
"@types/react": "^19.2.2",
|
||||||
"autoprefixer": "^10.4.22",
|
"autoprefixer": "^10.4.21",
|
||||||
"gray-matter": "^4.0.3",
|
"gray-matter": "^4.0.3",
|
||||||
"next": "^16.0.7",
|
"next": "^16.0.1",
|
||||||
"next-intl": "^4.5.8",
|
"next-intl": "^4.5.7",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"react": "^19.2.1",
|
"react": "^19.2.0",
|
||||||
"react-dom": "^19.2.1",
|
"react-dom": "^19.2.0",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"rehype-raw": "^7.0.0",
|
"rehype-raw": "^7.0.0",
|
||||||
"rehype-sanitize": "^6.0.0",
|
"rehype-sanitize": "^6.0.0",
|
||||||
@@ -32,17 +32,17 @@
|
|||||||
"unist-util-visit": "^5.0.0"
|
"unist-util-visit": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3.3.3",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
"@eslint/js": "^9.39.1",
|
"@eslint/js": "^9.39.1",
|
||||||
"@next/bundle-analyzer": "^16.0.7",
|
"@next/bundle-analyzer": "^16.0.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.48.1",
|
"@typescript-eslint/eslint-plugin": "^8.46.4",
|
||||||
"@typescript-eslint/parser": "^8.48.1",
|
"@typescript-eslint/parser": "^8.46.4",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"eslint-config-next": "^16.0.7",
|
"eslint-config-next": "^16.0.3",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-prettier": "^5.5.4",
|
"eslint-plugin-prettier": "^5.5.4",
|
||||||
"prettier": "^3.7.4",
|
"prettier": "^3.6.2",
|
||||||
"typescript-eslint": "^8.48.1"
|
"typescript-eslint": "^8.46.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@alloc/quick-lru": {
|
"node_modules/@alloc/quick-lru": {
|
||||||
@@ -453,9 +453,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/eslintrc": {
|
"node_modules/@eslint/eslintrc": {
|
||||||
"version": "3.3.3",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
|
||||||
"integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==",
|
"integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -465,7 +465,7 @@
|
|||||||
"globals": "^14.0.0",
|
"globals": "^14.0.0",
|
||||||
"ignore": "^5.2.0",
|
"ignore": "^5.2.0",
|
||||||
"import-fresh": "^3.2.1",
|
"import-fresh": "^3.2.1",
|
||||||
"js-yaml": "^4.1.1",
|
"js-yaml": "^4.1.0",
|
||||||
"minimatch": "^3.1.2",
|
"minimatch": "^3.1.2",
|
||||||
"strip-json-comments": "^3.1.1"
|
"strip-json-comments": "^3.1.1"
|
||||||
},
|
},
|
||||||
@@ -1202,9 +1202,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/bundle-analyzer": {
|
"node_modules/@next/bundle-analyzer": {
|
||||||
"version": "16.0.7",
|
"version": "16.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-16.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-16.0.3.tgz",
|
||||||
"integrity": "sha512-Um2YA3TSQND+DpqlMDuPZsdjdpcgLzo1wF3zx4zcBCLecS7ucP7O9YFqvHhg000HXTgt++KIjZ9FUwyJSKk1Kw==",
|
"integrity": "sha512-6Xo8f8/ZXtASfTPa6TH1aUn+xDg9Pkyl1YHVxu+89cVdLH7MnYjxv3rPOfEJ9BwCZCU2q4Flyw5MwltfD2pGbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1212,25 +1212,55 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/env": {
|
"node_modules/@next/env": {
|
||||||
"version": "16.0.7",
|
"version": "16.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.1.tgz",
|
||||||
"integrity": "sha512-gpaNgUh5nftFKRkRQGnVi5dpcYSKGcZZkQffZ172OrG/XkrnS7UBTQ648YY+8ME92cC4IojpI2LqTC8sTDhAaw==",
|
"integrity": "sha512-LFvlK0TG2L3fEOX77OC35KowL8D7DlFF45C0OvKMC4hy8c/md1RC4UMNDlUGJqfCoCS2VWrZ4dSE6OjaX5+8mw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@next/eslint-plugin-next": {
|
"node_modules/@next/eslint-plugin-next": {
|
||||||
"version": "16.0.7",
|
"version": "16.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.0.3.tgz",
|
||||||
"integrity": "sha512-hFrTNZcMEG+k7qxVxZJq3F32Kms130FAhG8lvw2zkKBgAcNOJIxlljNiCjGygvBshvaGBdf88q2CqWtnqezDHA==",
|
"integrity": "sha512-6sPWmZetzFWMsz7Dhuxsdmbu3fK+/AxKRtj7OB0/3OZAI2MHB/v2FeYh271LZ9abvnM1WIwWc/5umYjx0jo5sQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-glob": "3.3.1"
|
"fast-glob": "3.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@next/eslint-plugin-next/node_modules/fast-glob": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@nodelib/fs.stat": "^2.0.2",
|
||||||
|
"@nodelib/fs.walk": "^1.2.3",
|
||||||
|
"glob-parent": "^5.1.2",
|
||||||
|
"merge2": "^1.3.0",
|
||||||
|
"micromatch": "^4.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/eslint-plugin-next/node_modules/glob-parent": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"is-glob": "^4.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@next/swc-darwin-arm64": {
|
"node_modules/@next/swc-darwin-arm64": {
|
||||||
"version": "16.0.7",
|
"version": "16.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.1.tgz",
|
||||||
"integrity": "sha512-LlDtCYOEj/rfSnEn/Idi+j1QKHxY9BJFmxx7108A6D8K0SB+bNgfYQATPk/4LqOl4C0Wo3LACg2ie6s7xqMpJg==",
|
"integrity": "sha512-R0YxRp6/4W7yG1nKbfu41bp3d96a0EalonQXiMe+1H9GTHfKxGNCGFNWUho18avRBPsO8T3RmdWuzmfurlQPbg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1244,9 +1274,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-darwin-x64": {
|
"node_modules/@next/swc-darwin-x64": {
|
||||||
"version": "16.0.7",
|
"version": "16.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.1.tgz",
|
||||||
"integrity": "sha512-rtZ7BhnVvO1ICf3QzfW9H3aPz7GhBrnSIMZyr4Qy6boXF0b5E3QLs+cvJmg3PsTCG2M1PBoC+DANUi4wCOKXpA==",
|
"integrity": "sha512-kETZBocRux3xITiZtOtVoVvXyQLB7VBxN7L6EPqgI5paZiUlnsgYv4q8diTNYeHmF9EiehydOBo20lTttCbHAg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1260,9 +1290,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||||
"version": "16.0.7",
|
"version": "16.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.1.tgz",
|
||||||
"integrity": "sha512-mloD5WcPIeIeeZqAIP5c2kdaTa6StwP4/2EGy1mUw8HiexSHGK/jcM7lFuS3u3i2zn+xH9+wXJs6njO7VrAqww==",
|
"integrity": "sha512-hWg3BtsxQuSKhfe0LunJoqxjO4NEpBmKkE+P2Sroos7yB//OOX3jD5ISP2wv8QdUwtRehMdwYz6VB50mY6hqAg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1276,9 +1306,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-arm64-musl": {
|
"node_modules/@next/swc-linux-arm64-musl": {
|
||||||
"version": "16.0.7",
|
"version": "16.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.1.tgz",
|
||||||
"integrity": "sha512-+ksWNrZrthisXuo9gd1XnjHRowCbMtl/YgMpbRvFeDEqEBd523YHPWpBuDjomod88U8Xliw5DHhekBC3EOOd9g==",
|
"integrity": "sha512-UPnOvYg+fjAhP3b1iQStcYPWeBFRLrugEyK/lDKGk7kLNua8t5/DvDbAEFotfV1YfcOY6bru76qN9qnjLoyHCQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1292,9 +1322,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-x64-gnu": {
|
"node_modules/@next/swc-linux-x64-gnu": {
|
||||||
"version": "16.0.7",
|
"version": "16.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.1.tgz",
|
||||||
"integrity": "sha512-4WtJU5cRDxpEE44Ana2Xro1284hnyVpBb62lIpU5k85D8xXxatT+rXxBgPkc7C1XwkZMWpK5rXLXTh9PFipWsA==",
|
"integrity": "sha512-Et81SdWkcRqAJziIgFtsFyJizHoWne4fzJkvjd6V4wEkWTB4MX6J0uByUb0peiJQ4WeAt6GGmMszE5KrXK6WKg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1308,9 +1338,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-x64-musl": {
|
"node_modules/@next/swc-linux-x64-musl": {
|
||||||
"version": "16.0.7",
|
"version": "16.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.1.tgz",
|
||||||
"integrity": "sha512-HYlhqIP6kBPXalW2dbMTSuB4+8fe+j9juyxwfMwCe9kQPPeiyFn7NMjNfoFOfJ2eXkeQsoUGXg+O2SE3m4Qg2w==",
|
"integrity": "sha512-qBbgYEBRrC1egcG03FZaVfVxrJm8wBl7vr8UFKplnxNRprctdP26xEv9nJ07Ggq4y1adwa0nz2mz83CELY7N6Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1324,9 +1354,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||||
"version": "16.0.7",
|
"version": "16.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.1.tgz",
|
||||||
"integrity": "sha512-EviG+43iOoBRZg9deGauXExjRphhuYmIOJ12b9sAPy0eQ6iwcPxfED2asb/s2/yiLYOdm37kPaiZu8uXSYPs0Q==",
|
"integrity": "sha512-cPuBjYP6I699/RdbHJonb3BiRNEDm5CKEBuJ6SD8k3oLam2fDRMKAvmrli4QMDgT2ixyRJ0+DTkiODbIQhRkeQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1340,9 +1370,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-win32-x64-msvc": {
|
"node_modules/@next/swc-win32-x64-msvc": {
|
||||||
"version": "16.0.7",
|
"version": "16.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.1.tgz",
|
||||||
"integrity": "sha512-gniPjy55zp5Eg0896qSrf3yB1dw4F/3s8VK1ephdsZZ129j2n6e1WqCbE2YgcKhW9hPB9TVZENugquWJD5x0ug==",
|
"integrity": "sha512-XeEUJsE4JYtfrXe/LaJn3z1pD19fK0Q6Er8Qoufi+HqvdO4LEPyCxLUt4rxA+4RfYo6S9gMlmzCMU2F+AatFqQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1961,21 +1991,21 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "24.10.1",
|
"version": "24.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz",
|
||||||
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
|
"integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~7.16.0"
|
"undici-types": "~7.16.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/react": {
|
"node_modules/@types/react": {
|
||||||
"version": "19.2.7",
|
"version": "19.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
|
||||||
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.2.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/unist": {
|
"node_modules/@types/unist": {
|
||||||
@@ -1985,17 +2015,17 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.48.1",
|
"version": "8.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.4.tgz",
|
||||||
"integrity": "sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==",
|
"integrity": "sha512-R48VhmTJqplNyDxCyqqVkFSZIx1qX6PzwqgcXn1olLrzxcSBDlOsbtcnQuQhNtnNiJ4Xe5gREI1foajYaYU2Vg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "8.48.1",
|
"@typescript-eslint/scope-manager": "8.46.4",
|
||||||
"@typescript-eslint/type-utils": "8.48.1",
|
"@typescript-eslint/type-utils": "8.46.4",
|
||||||
"@typescript-eslint/utils": "8.48.1",
|
"@typescript-eslint/utils": "8.46.4",
|
||||||
"@typescript-eslint/visitor-keys": "8.48.1",
|
"@typescript-eslint/visitor-keys": "8.46.4",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^7.0.0",
|
"ignore": "^7.0.0",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@@ -2009,22 +2039,22 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@typescript-eslint/parser": "^8.48.1",
|
"@typescript-eslint/parser": "^8.46.4",
|
||||||
"eslint": "^8.57.0 || ^9.0.0",
|
"eslint": "^8.57.0 || ^9.0.0",
|
||||||
"typescript": ">=4.8.4 <6.0.0"
|
"typescript": ">=4.8.4 <6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "8.48.1",
|
"version": "8.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.4.tgz",
|
||||||
"integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==",
|
"integrity": "sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.48.1",
|
"@typescript-eslint/scope-manager": "8.46.4",
|
||||||
"@typescript-eslint/types": "8.48.1",
|
"@typescript-eslint/types": "8.46.4",
|
||||||
"@typescript-eslint/typescript-estree": "8.48.1",
|
"@typescript-eslint/typescript-estree": "8.46.4",
|
||||||
"@typescript-eslint/visitor-keys": "8.48.1",
|
"@typescript-eslint/visitor-keys": "8.46.4",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2040,14 +2070,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/project-service": {
|
"node_modules/@typescript-eslint/project-service": {
|
||||||
"version": "8.48.1",
|
"version": "8.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.4.tgz",
|
||||||
"integrity": "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==",
|
"integrity": "sha512-nPiRSKuvtTN+no/2N1kt2tUh/HoFzeEgOm9fQ6XQk4/ApGqjx0zFIIaLJ6wooR1HIoozvj2j6vTi/1fgAz7UYQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/tsconfig-utils": "^8.48.1",
|
"@typescript-eslint/tsconfig-utils": "^8.46.4",
|
||||||
"@typescript-eslint/types": "^8.48.1",
|
"@typescript-eslint/types": "^8.46.4",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2062,14 +2092,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "8.48.1",
|
"version": "8.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.4.tgz",
|
||||||
"integrity": "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==",
|
"integrity": "sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.48.1",
|
"@typescript-eslint/types": "8.46.4",
|
||||||
"@typescript-eslint/visitor-keys": "8.48.1"
|
"@typescript-eslint/visitor-keys": "8.46.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -2080,9 +2110,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||||
"version": "8.48.1",
|
"version": "8.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.4.tgz",
|
||||||
"integrity": "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==",
|
"integrity": "sha512-+/XqaZPIAk6Cjg7NWgSGe27X4zMGqrFqZ8atJsX3CWxH/jACqWnrWI68h7nHQld0y+k9eTTjb9r+KU4twLoo9A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2097,15 +2127,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "8.48.1",
|
"version": "8.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.4.tgz",
|
||||||
"integrity": "sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==",
|
"integrity": "sha512-V4QC8h3fdT5Wro6vANk6eojqfbv5bpwHuMsBcJUJkqs2z5XnYhJzyz9Y02eUmF9u3PgXEUiOt4w4KHR3P+z0PQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.48.1",
|
"@typescript-eslint/types": "8.46.4",
|
||||||
"@typescript-eslint/typescript-estree": "8.48.1",
|
"@typescript-eslint/typescript-estree": "8.46.4",
|
||||||
"@typescript-eslint/utils": "8.48.1",
|
"@typescript-eslint/utils": "8.46.4",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^2.1.0"
|
"ts-api-utils": "^2.1.0"
|
||||||
},
|
},
|
||||||
@@ -2122,9 +2152,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.48.1",
|
"version": "8.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.4.tgz",
|
||||||
"integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==",
|
"integrity": "sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2136,20 +2166,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.48.1",
|
"version": "8.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.4.tgz",
|
||||||
"integrity": "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==",
|
"integrity": "sha512-7oV2qEOr1d4NWNmpXLR35LvCfOkTNymY9oyW+lUHkmCno7aOmIf/hMaydnJBUTBMRCOGZh8YjkFOc8dadEoNGA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/project-service": "8.48.1",
|
"@typescript-eslint/project-service": "8.46.4",
|
||||||
"@typescript-eslint/tsconfig-utils": "8.48.1",
|
"@typescript-eslint/tsconfig-utils": "8.46.4",
|
||||||
"@typescript-eslint/types": "8.48.1",
|
"@typescript-eslint/types": "8.46.4",
|
||||||
"@typescript-eslint/visitor-keys": "8.48.1",
|
"@typescript-eslint/visitor-keys": "8.46.4",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
|
"fast-glob": "^3.3.2",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
"minimatch": "^9.0.4",
|
"minimatch": "^9.0.4",
|
||||||
"semver": "^7.6.0",
|
"semver": "^7.6.0",
|
||||||
"tinyglobby": "^0.2.15",
|
|
||||||
"ts-api-utils": "^2.1.0"
|
"ts-api-utils": "^2.1.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2164,16 +2195,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "8.48.1",
|
"version": "8.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.4.tgz",
|
||||||
"integrity": "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==",
|
"integrity": "sha512-AbSv11fklGXV6T28dp2Me04Uw90R2iJ30g2bgLz529Koehrmkbs1r7paFqr1vPCZi7hHwYxYtxfyQMRC8QaVSg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.7.0",
|
"@eslint-community/eslint-utils": "^4.7.0",
|
||||||
"@typescript-eslint/scope-manager": "8.48.1",
|
"@typescript-eslint/scope-manager": "8.46.4",
|
||||||
"@typescript-eslint/types": "8.48.1",
|
"@typescript-eslint/types": "8.46.4",
|
||||||
"@typescript-eslint/typescript-estree": "8.48.1"
|
"@typescript-eslint/typescript-estree": "8.46.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -2188,13 +2219,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.48.1",
|
"version": "8.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.1.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.4.tgz",
|
||||||
"integrity": "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==",
|
"integrity": "sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.48.1",
|
"@typescript-eslint/types": "8.46.4",
|
||||||
"eslint-visitor-keys": "^4.2.1"
|
"eslint-visitor-keys": "^4.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2759,9 +2790,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/autoprefixer": {
|
"node_modules/autoprefixer": {
|
||||||
"version": "10.4.22",
|
"version": "10.4.21",
|
||||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.22.tgz",
|
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
|
||||||
"integrity": "sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg==",
|
"integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -2778,9 +2809,9 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"browserslist": "^4.27.0",
|
"browserslist": "^4.24.4",
|
||||||
"caniuse-lite": "^1.0.30001754",
|
"caniuse-lite": "^1.0.30001702",
|
||||||
"fraction.js": "^5.3.4",
|
"fraction.js": "^4.3.7",
|
||||||
"normalize-range": "^0.1.2",
|
"normalize-range": "^0.1.2",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"postcss-value-parser": "^4.2.0"
|
"postcss-value-parser": "^4.2.0"
|
||||||
@@ -3148,9 +3179,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/csstype": {
|
"node_modules/csstype": {
|
||||||
"version": "3.2.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||||
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/damerau-levenshtein": {
|
"node_modules/damerau-levenshtein": {
|
||||||
@@ -3663,13 +3694,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-config-next": {
|
"node_modules/eslint-config-next": {
|
||||||
"version": "16.0.7",
|
"version": "16.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.0.3.tgz",
|
||||||
"integrity": "sha512-WubFGLFHfk2KivkdRGfx6cGSFhaQqhERRfyO8BRx+qiGPGp7WLKcPvYC4mdx1z3VhVRcrfFzczjjTrbJZOpnEQ==",
|
"integrity": "sha512-5F6qDjcZldf0Y0ZbqvWvap9xzYUxyDf7/of37aeyhvkrQokj/4bT1JYWZdlWUr283aeVa+s52mPq9ogmGg+5dw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@next/eslint-plugin-next": "16.0.7",
|
"@next/eslint-plugin-next": "16.0.3",
|
||||||
"eslint-import-resolver-node": "^0.3.6",
|
"eslint-import-resolver-node": "^0.3.6",
|
||||||
"eslint-import-resolver-typescript": "^3.5.2",
|
"eslint-import-resolver-typescript": "^3.5.2",
|
||||||
"eslint-plugin-import": "^2.32.0",
|
"eslint-plugin-import": "^2.32.0",
|
||||||
@@ -4294,9 +4325,9 @@
|
|||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/fast-glob": {
|
"node_modules/fast-glob": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
|
||||||
"integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
|
"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -4304,7 +4335,7 @@
|
|||||||
"@nodelib/fs.walk": "^1.2.3",
|
"@nodelib/fs.walk": "^1.2.3",
|
||||||
"glob-parent": "^5.1.2",
|
"glob-parent": "^5.1.2",
|
||||||
"merge2": "^1.3.0",
|
"merge2": "^1.3.0",
|
||||||
"micromatch": "^4.0.4"
|
"micromatch": "^4.0.8"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.6.0"
|
"node": ">=8.6.0"
|
||||||
@@ -4428,15 +4459,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fraction.js": {
|
"node_modules/fraction.js": {
|
||||||
"version": "5.3.4",
|
"version": "4.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
|
||||||
"integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==",
|
"integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": "*"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "patreon",
|
||||||
"url": "https://github.com/sponsors/rawify"
|
"url": "https://github.com/sponsors/rawify"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -6976,12 +7007,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/next": {
|
"node_modules/next": {
|
||||||
"version": "16.0.7",
|
"version": "16.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/next/-/next-16.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/next/-/next-16.0.1.tgz",
|
||||||
"integrity": "sha512-3mBRJyPxT4LOxAJI6IsXeFtKfiJUbjCLgvXO02fV8Wy/lIhPvP94Fe7dGhUgHXcQy4sSuYwQNcOLhIfOm0rL0A==",
|
"integrity": "sha512-e9RLSssZwd35p7/vOa+hoDFggUZIUbZhIUSLZuETCwrCVvxOs87NamoUzT+vbcNAL8Ld9GobBnWOA6SbV/arOw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@next/env": "16.0.7",
|
"@next/env": "16.0.1",
|
||||||
"@swc/helpers": "0.5.15",
|
"@swc/helpers": "0.5.15",
|
||||||
"caniuse-lite": "^1.0.30001579",
|
"caniuse-lite": "^1.0.30001579",
|
||||||
"postcss": "8.4.31",
|
"postcss": "8.4.31",
|
||||||
@@ -6994,14 +7025,14 @@
|
|||||||
"node": ">=20.9.0"
|
"node": ">=20.9.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@next/swc-darwin-arm64": "16.0.7",
|
"@next/swc-darwin-arm64": "16.0.1",
|
||||||
"@next/swc-darwin-x64": "16.0.7",
|
"@next/swc-darwin-x64": "16.0.1",
|
||||||
"@next/swc-linux-arm64-gnu": "16.0.7",
|
"@next/swc-linux-arm64-gnu": "16.0.1",
|
||||||
"@next/swc-linux-arm64-musl": "16.0.7",
|
"@next/swc-linux-arm64-musl": "16.0.1",
|
||||||
"@next/swc-linux-x64-gnu": "16.0.7",
|
"@next/swc-linux-x64-gnu": "16.0.1",
|
||||||
"@next/swc-linux-x64-musl": "16.0.7",
|
"@next/swc-linux-x64-musl": "16.0.1",
|
||||||
"@next/swc-win32-arm64-msvc": "16.0.7",
|
"@next/swc-win32-arm64-msvc": "16.0.1",
|
||||||
"@next/swc-win32-x64-msvc": "16.0.7",
|
"@next/swc-win32-x64-msvc": "16.0.1",
|
||||||
"sharp": "^0.34.4"
|
"sharp": "^0.34.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@@ -7028,9 +7059,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/next-intl": {
|
"node_modules/next-intl": {
|
||||||
"version": "4.5.8",
|
"version": "4.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.5.8.tgz",
|
"resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.5.7.tgz",
|
||||||
"integrity": "sha512-BdN6494nvt09WtmW5gbWdwRhDDHC/Sg7tBMhN7xfYds3vcRCngSDXat81gmJkblw9jYOv8zXzzFJyu5VYXnJzg==",
|
"integrity": "sha512-7iT9rBEFZvsJI5uLoOLgI1kAieg1k7zCwbuby6ylKRbpvt08I1vkZ5FJnIBey1M+r1jam/wANlnqRYeJagjL2Q==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "individual",
|
"type": "individual",
|
||||||
@@ -7042,9 +7073,9 @@
|
|||||||
"@formatjs/intl-localematcher": "^0.5.4",
|
"@formatjs/intl-localematcher": "^0.5.4",
|
||||||
"@swc/core": "^1.15.2",
|
"@swc/core": "^1.15.2",
|
||||||
"negotiator": "^1.0.0",
|
"negotiator": "^1.0.0",
|
||||||
"next-intl-swc-plugin-extractor": "^4.5.8",
|
"next-intl-swc-plugin-extractor": "^4.5.7",
|
||||||
"po-parser": "^1.0.2",
|
"po-parser": "^1.0.2",
|
||||||
"use-intl": "^4.5.8"
|
"use-intl": "^4.5.7"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
|
"next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
|
||||||
@@ -7058,9 +7089,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/next-intl-swc-plugin-extractor": {
|
"node_modules/next-intl-swc-plugin-extractor": {
|
||||||
"version": "4.5.8",
|
"version": "4.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.5.8.tgz",
|
"resolved": "https://registry.npmjs.org/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.5.7.tgz",
|
||||||
"integrity": "sha512-hscCKUv+5GQ0CCNbvqZ8gaxnAGToCgDTbL++jgCq8SCk/ljtZDEeQZcMk46Nm6Ynn49Q/JKF4Npo/Sq1mpbusA==",
|
"integrity": "sha512-cSHtDpEoSHuEC4CzUDmAAfB0H3fqSephpJNd/GtS9LvUoZM78wJQwkEaqN9yTxXEvJ8uQG60nnOeSl2LQU9qdQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/next-intl/node_modules/@swc/core": {
|
"node_modules/next-intl/node_modules/@swc/core": {
|
||||||
@@ -7536,9 +7567,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.7.4",
|
"version": "3.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
|
||||||
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
|
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -7618,24 +7649,24 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/react": {
|
"node_modules/react": {
|
||||||
"version": "19.2.1",
|
"version": "19.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
|
||||||
"integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==",
|
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "19.2.1",
|
"version": "19.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
|
||||||
"integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==",
|
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.27.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^19.2.1"
|
"react": "^19.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
@@ -8744,16 +8775,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript-eslint": {
|
"node_modules/typescript-eslint": {
|
||||||
"version": "8.48.1",
|
"version": "8.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.1.tgz",
|
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.4.tgz",
|
||||||
"integrity": "sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A==",
|
"integrity": "sha512-KALyxkpYV5Ix7UhvjTwJXZv76VWsHG+NjNlt/z+a17SOQSiOcBdUXdbJdyXi7RPxrBFECtFOiPwUJQusJuCqrg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "8.48.1",
|
"@typescript-eslint/eslint-plugin": "8.46.4",
|
||||||
"@typescript-eslint/parser": "8.48.1",
|
"@typescript-eslint/parser": "8.46.4",
|
||||||
"@typescript-eslint/typescript-estree": "8.48.1",
|
"@typescript-eslint/typescript-estree": "8.46.4",
|
||||||
"@typescript-eslint/utils": "8.48.1"
|
"@typescript-eslint/utils": "8.46.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -8955,9 +8986,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/use-intl": {
|
"node_modules/use-intl": {
|
||||||
"version": "4.5.8",
|
"version": "4.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.5.8.tgz",
|
"resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.5.7.tgz",
|
||||||
"integrity": "sha512-rWPV2Sirw55BQbA/7ndUBtsikh8WXwBrUkZJ1mD35+emj/ogPPqgCZdv1DdrEFK42AjF1g5w8d3x8govhqPH6Q==",
|
"integrity": "sha512-WBVD1fxV9td5osQFK0TRQhz217zHERhxBuA3EmZuH7wCINJPXbYPs+0FH2oMpy6p6BBwuHCJK2ER8hKwxf0LQA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formatjs/fast-memoize": "^2.2.0",
|
"@formatjs/fast-memoize": "^2.2.0",
|
||||||
|
|||||||
28
package.json
28
package.json
@@ -30,16 +30,16 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.17",
|
"@tailwindcss/postcss": "^4.1.17",
|
||||||
"@tailwindcss/typography": "^0.5.19",
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.0",
|
||||||
"@types/react": "^19.2.7",
|
"@types/react": "^19.2.2",
|
||||||
"autoprefixer": "^10.4.22",
|
"autoprefixer": "^10.4.21",
|
||||||
"gray-matter": "^4.0.3",
|
"gray-matter": "^4.0.3",
|
||||||
"next": "^16.0.7",
|
"next": "^16.0.1",
|
||||||
"next-intl": "^4.5.8",
|
"next-intl": "^4.5.7",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"react": "^19.2.1",
|
"react": "^19.2.0",
|
||||||
"react-dom": "^19.2.1",
|
"react-dom": "^19.2.0",
|
||||||
"react-markdown": "^10.1.0",
|
"react-markdown": "^10.1.0",
|
||||||
"rehype-raw": "^7.0.0",
|
"rehype-raw": "^7.0.0",
|
||||||
"rehype-sanitize": "^6.0.0",
|
"rehype-sanitize": "^6.0.0",
|
||||||
@@ -51,16 +51,16 @@
|
|||||||
"unist-util-visit": "^5.0.0"
|
"unist-util-visit": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3.3.3",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
"@eslint/js": "^9.39.1",
|
"@eslint/js": "^9.39.1",
|
||||||
"@next/bundle-analyzer": "^16.0.7",
|
"@next/bundle-analyzer": "^16.0.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.48.1",
|
"@typescript-eslint/eslint-plugin": "^8.46.4",
|
||||||
"@typescript-eslint/parser": "^8.48.1",
|
"@typescript-eslint/parser": "^8.46.4",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"eslint-config-next": "^16.0.7",
|
"eslint-config-next": "^16.0.3",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-prettier": "^5.5.4",
|
"eslint-plugin-prettier": "^5.5.4",
|
||||||
"prettier": "^3.7.4",
|
"prettier": "^3.6.2",
|
||||||
"typescript-eslint": "^8.48.1"
|
"typescript-eslint": "^8.46.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
public/blog/tech/articol-tehnic.md
Normal file
20
public/blog/tech/articol-tehnic.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
title: 'Technical Article'
|
||||||
|
description: 'A technical article to test internal links'
|
||||||
|
date: '2025-01-10'
|
||||||
|
author: 'John Doe'
|
||||||
|
category: 'Tech'
|
||||||
|
tags: ['tech', 'test']
|
||||||
|
---
|
||||||
|
|
||||||
|
# Technical Article
|
||||||
|
|
||||||
|
This is a test article for internal blog post linking.
|
||||||
|
|
||||||
|
Imagine cooler:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Content
|
||||||
|
|
||||||
|
You are reading the technical article that was linked from the example post.
|
||||||
Reference in New Issue
Block a user