Compare commits

...

6 Commits

Author SHA1 Message Date
muszyn 903818307f testing git 2025-12-06 10:56:28 -05:00
muszyn 7ff55c4679 fix: fetch was not using rest requests 2025-07-04 12:15:32 -04:00
muszyn a41d1ceaea feat: public self-hosting 2025-07-04 10:04:28 -04:00
muszyn 60c9cec7aa feat: fix vite url using env var 2025-06-25 20:56:16 -04:00
muszyn c0eae42daf feat: expand cors 2025-06-25 19:57:00 -04:00
muszyn afe6c08101 feat(aboutme): update photos and blurb 2025-06-24 21:54:59 -04:00
17 changed files with 96 additions and 63 deletions
+2
View File
@@ -26,3 +26,5 @@ dist-ssr
*.njsproj
*.sln
*.sw?
.env
+1
View File
@@ -6,6 +6,7 @@ from dotenv import load_dotenv
env = load_dotenv()
DATABASE_URL = os.getenv("DATABASE_URL", "")
print(DATABASE_URL)
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
+14 -2
View File
@@ -1,5 +1,6 @@
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
from typing import Optional
@@ -10,11 +11,22 @@ from .database import SessionLocal, engine, Base
Base.metadata.create_all(bind=engine)
app = FastAPI()
app = FastAPI(proxy_headers=True)
app.add_middleware(
TrustedHostMiddleware, allowed_hosts=["site-api.muszyn.dev", "*.muszyn.dev"]
)
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000", "https://localhost:3000"],
allow_origins=[
"http://localhost:3000",
"http://localhost:8000",
"http://192.168.125.129:3000",
"https://192.168.125.129:3000",
"http://192.168.125.129:8000",
"https://192.168.125.129:8000",
"https://site.muszyn.dev",
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
+5 -3
View File
@@ -1,5 +1,3 @@
version: '3.8'
services:
db:
image: postgres:15
@@ -37,7 +35,11 @@ services:
- app-network
frontend:
build: ./frontend
build:
context: ./frontend
args:
VITE_API_URL: ${API_URL}
ports:
- "3000:80"
depends_on:
+13 -6
View File
@@ -1,15 +1,22 @@
# Build stage
FROM node:20 AS build
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
ARG VITE_API_URL
ENV VITE_API_URL=$VITE_API_URL
RUN npm run build
# Production stage
# Stage 2: Serve with NGINX
FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=build /app/dist /usr/share/nginx/html
# Clean out default config
RUN rm /etc/nginx/conf.d/default.conf
# Copy your custom nginx config
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Copy built files from Vite
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
+2 -19
View File
@@ -1,28 +1,11 @@
worker_processes 1;
events { worker_connections 1024; }
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name _;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
location / {
# try to serve file directly, otherwise fallback to index.html
try_files $uri $uri/ /index.html;
}
# optional: block .git, .env, etc
location ~ /\.(?!well-known).* {
deny all;
}
try_files $uri /index.html;
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

+34 -24
View File
@@ -5,6 +5,9 @@ import React, {
useEffect,
useRef,
} from "react";
import cruiseImg from "./images/cruise.jpg";
import discGolfImg from "./images/disc_golf_ace.jpg";
import odinImg from "./images/odin.jpg";
import {
BrowserRouter as Router,
Routes,
@@ -28,9 +31,7 @@ import {
} from "react-icons/fa";
import type { Blog } from "./utils/types";
import { countWords } from "./utils/countWords";
// Base API URL from env
const API_URL = import.meta.env.VITE_API_URL || "http://localhost:8000";
import { API_URL } from "./utils/constants";
// Auth Context
interface AuthContextProps {
@@ -82,7 +83,12 @@ function BlogPage() {
const [blogs, setBlogs] = useState<Blog[]>([]);
useEffect(() => {
fetch(`${API_URL}/blogs`)
fetch(`${API_URL}/blogs`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((res) => res.json())
.then((data: Blog[]) => setBlogs(data))
.catch((err) => console.error(err));
@@ -418,32 +424,36 @@ function LandingPage() {
function About() {
return (
<div className="py-10">
<div className="flex justify-center items-end space-x-4">
<div className="flex justify-center items-end space-x-4 flex-wrap">
{[cruiseImg, discGolfImg, odinImg].map((src, i) => (
<img
src="/images/photo1.jpg"
alt="Photo 1"
className="w-24 h-24 rounded-full"
/>
<img
src="/images/photo2.jpg"
alt="Photo 2"
className="w-24 h-24 rounded-full transform translate-y-4"
/>
<img
src="/images/photo3.jpg"
alt="Photo 3"
className="w-24 h-24 rounded-full"
key={i}
src={src}
alt={["Cruise", "Disc golf ace", "Odin"][i]}
className="
rounded-full
aspect-square
object-cover
w-1/3 max-w-[120px] /* small screens: 33% of container, up to 120px */
sm:w-1/4 sm:max-w-[150px] /* ≥640px: 25% up to 150px */
md:w-1/6 md:max-w-[200px] /* ≥768px: ~16% up to 200px */
lg:w-1/8 lg:max-w-[250px] /* ≥1024px: 12.5% up to 250px */
"
/>
))}
</div>
<div className="text-center mt-8 px-4">
<h2 className="text-3xl font-bold mb-4">About Me</h2>
<p className="text-lg text-gray-700 dark:text-gray-300 max-w-2xl mx-auto">
I am a software engineer at Whisker who designs and implements
whatever is highest priority. I work with every team in the
engineering organization to coordinate mission-critical projects
across backend, mobile, and firmware. Im comfortable in many tech
stacks and learn new ones quicklynever afraid to jump in the deep end
and adapt on the fly.
Im Alex, a full-stack engineer at Whisker, working on backend one
minute, mobile tweaks the next, and firmware the day after. Learning
new tech is something I'm passionate about, and Im all about
spreading that knowledge fast. Off-duty youll catch me reading a
bunch, writing (ironically, on my blog, which you are currently
viewing), exploring the outdoors with my dogs (and my girlfriend,
trust me shes real!), or rolling dice as a D&amp;D sorcerer. Here
youll find book thoughts, code experiments, and random shower
thoughts. Thanks for stopping by!
</p>
</div>
<div className="mt-8 flex flex-col items-center space-y-2">
Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

+7 -1
View File
@@ -1,9 +1,15 @@
import { useState, useEffect } from "react";
import { API_URL } from "./constants";
export function BlogList() {
const [content, setContent] = useState("");
useEffect(() => {
fetch(`localhost:8000/get-blogs`)
fetch(`${API_URL}/get-blogs`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((res) => res.text())
.then(setContent);
}, []);
+6 -1
View File
@@ -16,7 +16,12 @@ export function BlogViewer() {
useEffect(() => {
if (!slug) return;
fetch(`${API_URL}/blogs/${slug}`)
fetch(`${API_URL}/blogs/${slug}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((res) => res.json())
.then((data: Blog) => setBlog(data))
.catch((err) => console.error(err));
+6 -1
View File
@@ -16,7 +16,12 @@ export function EditBlog() {
useEffect(() => {
if (!slug) return;
fetch(`${API_URL}/blogs/${slug}`)
fetch(`${API_URL}/blogs/${slug}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((res) => res.json())
.then((data: Blog) => {
setBlog(data);
View File