Compare commits
5 Commits
6bda5876ba
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 7ff55c4679 | |||
| a41d1ceaea | |||
| 60c9cec7aa | |||
| c0eae42daf | |||
| afe6c08101 |
@@ -26,3 +26,5 @@ dist-ssr
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
.env
|
||||
|
||||
+14
-2
@@ -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
@@ -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
@@ -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;"]
|
||||
|
||||
+3
-20
@@ -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 {
|
||||
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
@@ -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. I’m comfortable in many tech
|
||||
stacks and learn new ones quickly—never afraid to jump in the deep end
|
||||
and adapt on the fly.
|
||||
I’m 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 I’m all about
|
||||
spreading that knowledge fast. Off-duty you’ll 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 she’s real!), or rolling dice as a D&D sorcerer. Here
|
||||
you’ll 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 |
@@ -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);
|
||||
}, []);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user