Skip to content
/ portfolio Public template

A modern, high-performance personal portfolio and blog built with Astro.js. Designed to showcase your projects and technical writing with blazing-fast performance and exceptional SEO.

License

Notifications You must be signed in to change notification settings

cojocaru-david/portfolio

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

73 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Developer Portfolio & Blog

Astro React TailwindCSS TypeScript

thubnail

A modern, high-performance personal portfolio and blog built with Astro.js. Designed to showcase your projects and technical writing with blazing-fast performance and exceptional SEO.

✨ Features

  • πŸš€ Blazing fast performance - Built with Astro.js for optimal loading speeds
  • πŸ“ Full-featured blog - Support for technical articles with code highlighting
  • 🎨 Beautiful UI - Modern, responsive design powered by Tailwind CSS
  • πŸŒ™ Dark mode support - Seamless light/dark theme switching
  • πŸ“± Fully responsive - Looks great on all devices from mobile to desktop
  • πŸ” SEO optimized - Structured data, meta tags, and optimized for search engines
  • 🏷️ Tag system - Categorize blog posts and projects with tags
  • πŸ“Š Content collection - Organized content management with Astro's content collections
  • πŸ–ΌοΈ Project showcase - Display your work with images, descriptions, and technology tags

πŸ› οΈ Tech Stack

  • Astro.js - Static site generator with excellent performance
  • React.js - For interactive components
  • Tailwind CSS - Utility-first CSS framework
  • TypeScript - Type safety and improved developer experience
  • MDX - Markdown with JSX for rich content creation
  • Preact - Lightweight alternative to React for UI components

πŸ“‹ Prerequisites

Before you begin, ensure you have the following installed:

βš™οΈ Installation & Setup

  1. Clone the repository

    git clone https://github.com/cojocaru-david/portfolio.git
    cd portfolio
  2. Install dependencies

    npm install
    # or
    yarn install
  3. Start the development server

    npm run dev
    # or
    yarn dev
  4. Open your browser Navigate to http://localhost:4321 to see the site running locally.

πŸ“ Project Structure

portfolio/
β”œβ”€β”€ public/                 # Static assets
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ components/         # UI components
β”‚   β”œβ”€β”€ content/            # Content collections
β”‚   β”‚   β”œβ”€β”€ blog/           # Blog posts in MD/MDX format
β”‚   β”‚   └── projects/       # Project data
β”‚   β”œβ”€β”€ layouts/            # Page layouts
β”‚   β”œβ”€β”€ lib/                # Utility functions
β”‚   β”œβ”€β”€ pages/              # Page routes
β”‚   └── styles/             # Global styles
β”œβ”€β”€ astro.config.mjs        # Astro configuration
β”œβ”€β”€ tailwind.config.cjs     # Tailwind CSS configuration
β”œβ”€β”€ tsconfig.json           # TypeScript configuration
└── package.json            # Project dependencies

πŸš€ Usage

Creating a Blog Post

  1. Create a new .mdx or .md file in src/content/blog
  2. Add frontmatter with title, description, date, tags, and authors
  3. Write your content using Markdown and MDX components
---
title: "Your Post Title"
description: "A brief description of your post"
date: 2025-04-20
tags: ["tag1", "tag2", "tag3"]
authors: ["Your Name", "Co-author (optional)"]
---

# Your Post Title

Write your content here using Markdown.

## Subheading

More content...

Adding a Project

  1. Create a new .md file in projects
  2. Add project details including name, description, tags, and image path

πŸŒ™ Dark Mode

The project includes dark mode support using Tailwind CSS and Preact. It detects user preferences and applies the appropriate theme, with an option to toggle between light and dark modes.

πŸ“Š Data Utilities

The project includes several utility functions in data-utils.ts:

  • getAllPosts() - Retrieve all blog posts
  • getRecentPosts(count) - Get the most recent posts
  • getAdjacentPosts(currentId) - Get next and previous posts
  • getAllTags() - Get all tags used in posts
  • getSortedTags() - Get tags sorted by usage count
  • getPostsByAuthor(authorId) - Get all posts by a specific author

πŸ“Š Database Setup (Likes/Dislikes Feature)

The portfolio includes a post feedback system allowing visitors to like or dislike blog posts. This feature requires a PostgreSQL database to store vote data. This guide explains how to set it up using Neon.tech.

Setting Up Neon.tech Database

  1. Create a Neon.tech Account

    • Go to Neon.tech and sign up for an account
    • Neon offers a generous free tier suitable for personal portfolio sites
  2. Create a New Project

    • From the Neon dashboard, click "New Project"
    • Choose a name for your project (e.g., "portfolio-feedback")
    • Select the closest region to your target audience
    • Click "Create Project"
  3. Get Connection Details

    • In your project dashboard, find the connection string under "Connection Details"
    • Save this connection string as you'll need it for your environment variables
  4. Set Environment Variables

    • Create a .env file in your project root (if not already present)
    • Add your database connection string:
      DATABASE_URL=your_neon_connection_string_here
      

Database Schema Setup

Run the following SQL queries in the Neon SQL Editor to create the necessary tables for the feedback system:

CREATE TABLE post_feedback (
  id SERIAL PRIMARY KEY,
  post_id VARCHAR(255) NOT NULL,
  likes INTEGER DEFAULT 0,
  dislikes INTEGER DEFAULT 0,
  CONSTRAINT unique_post_id UNIQUE (post_id)
);

CREATE TABLE post_likes (
  id SERIAL PRIMARY KEY,
  post_id VARCHAR(255) NOT NULL,
  fingerprint_id VARCHAR(255) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT unique_like UNIQUE (post_id, fingerprint_id)
);

CREATE TABLE post_dislikes (
  id SERIAL PRIMARY KEY,
  post_id VARCHAR(255) NOT NULL,
  fingerprint_id VARCHAR(255) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT unique_dislike UNIQUE (post_id, fingerprint_id)
);

CREATE INDEX idx_post_feedback_post_id ON post_feedback (post_id);
CREATE INDEX idx_post_likes_post_id_fingerprint ON post_likes (post_id, fingerprint_id);
CREATE INDEX idx_post_dislikes_post_id_fingerprint ON post_dislikes (post_id, fingerprint_id);

How the Feedback System Works

The feedback system consists of three tables:

  • post_feedback: Stores aggregate counts of likes and dislikes for each post
  • post_likes: Records individual like actions with fingerprint IDs to prevent duplicate votes
  • post_dislikes: Records individual dislike actions with fingerprint IDs

API Implementation

The portfolio includes API endpoints for handling likes and dislikes:

  1. Fetching Post Feedback

    • GET request to /api/like/{postId} returns current like/dislike counts
  2. Submitting Likes

    • POST request to /api/like/{postId} with fingerprint ID in the request body
    • The system checks if the user has already liked/disliked the post
    • If not, a like is recorded and the count is updated
  3. Submitting Dislikes

    • POST request to /api/dislike/{postId} works similarly to the like endpoint
    • Prevents duplicate votes from the same visitor

Working with the Database

When a new blog post is created:

  • No manual database entry is needed
  • The first like/dislike action will automatically create the entry in post_feedback

To reset likes for a post:

DELETE FROM post_likes WHERE post_id = 'your-post-id';
DELETE FROM post_dislikes WHERE post_id = 'your-post-id';
UPDATE post_feedback SET likes = 0, dislikes = 0 WHERE post_id = 'your-post-id';

To view post statistics:

SELECT * FROM post_feedback ORDER BY likes DESC;

To find which posts a specific user has interacted with:

SELECT post_id FROM post_likes WHERE fingerprint_id = 'specific-fingerprint-id';

Troubleshooting

If you encounter issues with the feedback system:

  1. Check Environment Variables

    • Ensure your .env file contains the correct DATABASE_URL
  2. Verify Database Connection

    • Add logging to your database connection code to check for errors
    • Make sure your Neon.tech project is active and not in suspended state
  3. Check for Errors in Console

    • The feedback component logs errors that can help diagnose issues
  4. Reset User Vote State

    • Users can clear their localStorage to reset their voting state:
      // In browser console
      localStorage.clear()

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

About

A modern, high-performance personal portfolio and blog built with Astro.js. Designed to showcase your projects and technical writing with blazing-fast performance and exceptional SEO.

Topics

Resources

License

Stars

Watchers

Forks

Contributors 3

  •  
  •  
  •