Intial commit.

This commit is contained in:
Cameron Redmore 2025-08-07 23:35:10 +01:00
commit 349d0ad4ff
No known key found for this signature in database
11 changed files with 1676 additions and 0 deletions

View file

@ -0,0 +1,77 @@
name: Build and Push Docker Image
on:
push:
branches:
- main # Adjust if your main branch is different
tags:
- 'v*.*.*' # Trigger on version tags
env:
REGISTRY: git.cmzi.uk
# Use 'github' context variables as fallbacks for repo owner and name
IMAGE_BASE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: alpine-latest # Or your preferred runner with Docker
permissions:
contents: read
packages: write # Still required for pushing to the registry
steps:
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Recommended for metadata action
- name: Install pnpm dependencies
run: pnpm i
shell: sh
- name: Build project
run: pnpm run build
shell: sh
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Forgejo Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }} # Use the registry URL defined above
# Use 'github.actor' as a fallback for the username context
username: ${{ github.repository_owner }}
# Use the Forgejo-specific token - this SHOULD still work if Actions are enabled
password: ${{ secrets.RUNNER_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
# Construct the full image name using the defined REGISTRY and IMAGE_BASE_NAME
images: ${{ env.REGISTRY }}/${{ env.IMAGE_BASE_NAME }}
tags: |
# Use 'github.ref' for branch/tag detection
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }} # Adjust 'main' if needed
type=ref,event=branch
type=ref,event=tag
type=sha,format=short # Tag with short Git SHA
# Add standard OCI labels using github context
labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.ref.name=${{ github.ref_name }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }} # Use tags from metadata step
labels: ${{ steps.meta.outputs.labels }} # Use labels from metadata step
cache-from: type=gha
cache-to: type=gha,mode=max

View file

@ -0,0 +1,35 @@
name: Deploy
# Trigger the workflow manually from the Forgejo UI
on:
workflow_dispatch:
jobs:
run_remote_command:
name: Execute Command on Server
runs-on: alpine-latest
steps:
- name: Setup SSH Agent
uses: webfactory/ssh-agent@v0.9.0
shell: sh
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Add known hosts
if: ${{ secrets.SSH_KNOWN_HOSTS != '' }} # Only run if the secret is set
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: Run Command via SSH
run: |
ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} '
echo "Running remote deployment..."
cd /home/public/ || exit 1
docker compose pull && docker compose up -d --force-recreate
echo "Remote deployment finished."
' # End of commands for the remote server
echo "SSH command sent."

24
.gitignore vendored Normal file
View file

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

11
Dockerfile Normal file
View file

@ -0,0 +1,11 @@
FROM nginx:latest
COPY www /usr/share/nginx/html
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
STOPSIGNAL SIGQUIT
CMD ["nginx", "-g", "daemon off;"]

54
entrypoint.sh Normal file
View file

@ -0,0 +1,54 @@
#!/bin/sh
# vim:sw=4:ts=4:et
set -e
entrypoint_log() {
if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then
echo "$@"
fi
}
if [ "$1" = "nginx" ] || [ "$1" = "nginx-debug" ]; then
if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then
entrypoint_log "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration"
entrypoint_log "$0: Looking for shell scripts in /docker-entrypoint.d/"
find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do
case "$f" in
*.envsh)
if [ -x "$f" ]; then
entrypoint_log "$0: Sourcing $f";
. "$f"
else
# warn on shell scripts without exec bit
entrypoint_log "$0: Ignoring $f, not executable";
fi
;;
*.sh)
if [ -x "$f" ]; then
entrypoint_log "$0: Launching $f";
"$f"
else
# warn on shell scripts without exec bit
entrypoint_log "$0: Ignoring $f, not executable";
fi
;;
*) entrypoint_log "$0: Ignoring $f";;
esac
done
entrypoint_log "$0: Configuration complete; ready for start up"
else
entrypoint_log "$0: No files found in /docker-entrypoint.d/, skipping configuration"
fi
fi
# Check if the folder /extra exists, if so, copy all files from /extra to /usr/share/nginx/html
if [ -d "/extra" ]; then
echo "Copying files from /extra to /usr/share/nginx/html"
cp -r /extra/* /usr/share/nginx/html/
fi
echo "Executing command: $@"
exec "$@"

93
index.html Normal file
View file

@ -0,0 +1,93 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cameron B. R. Redmore - Software Developer</title>
<link rel="stylesheet" href="/src/style.css">
</head>
<body class="text-gray-200">
<script type="module">
import '~icons/mdi/github'
import '~icons/mdi/git'
</script>
<!-- Decorative background shapes -->
<div class="shape shape-1"></div>
<div class="shape shape-2"></div>
<div class="shape shape-3"></div>
<!-- Main container -->
<main class="min-h-screen w-full flex items-center justify-center p-4 sm:p-6 lg:p-8">
<!-- The Glass Card -->
<div class="glass-card w-full max-w-4xl rounded-2xl p-6 sm:p-8 md:p-10">
<div class="flex flex-col md:flex-row items-center md:items-start md:space-x-10">
<!-- Left Column: Profile Picture and Social Links -->
<div class="flex-shrink-0 text-center mb-6 md:mb-0">
<img src="https://avatars.githubusercontent.com/u/5846077?v=4" alt="Cameron B. R. Redmore" class="rounded-full w-32 h-32 md:w-40 md:h-40 mx-auto border-4 border-white/20 shadow-lg">
<div class="mt-6 flex justify-center space-x-4">
<a href="https://github.com/CameronRedmore" target="_blank" class="skill-tag p-3 rounded-full" aria-label="GitHub Profile">
<icon-mdi-github class="w-8 h-8 text-2xl" />
</a>
<a href="https://git.cmzi.uk/" target="_blank" class="skill-tag p-3 rounded-full" aria-label="Personal Git Hosting">
<icon-mdi-git class="w-8 h-8 text-2xl" />
</a>
</div>
</div>
<!-- Right Column: Main Content -->
<div class="w-full">
<h1 class="text-4xl md:text-5xl font-bold text-white animated-gradient">Cameron B. R. Redmore</h1>
<p class="mt-2 text-lg text-cyan-200">26-year-old Software Developer from Kingston-Upon-Hull, UK</p>
<p class="mt-6 text-gray-200 leading-relaxed">
With 8 years of professional experience and over 15 years of passion-driven coding, I build robust and efficient software solutions. My journey has taken me from recreational projects to developing complex professional applications.
</p>
<!-- Interests & Hobbies Section -->
<div class="mt-8">
<h2 class="text-xl font-semibold text-white mb-3">Interests & Hobbies</h2>
<p class="text-gray-200 leading-relaxed">
Beyond my core work, I have a deep interest in the broader field of computing and programming. I'm particularly passionate about the AI and Machine Learning space, focusing on integrating Large Language Models (LLMs) in novel ways. In my spare time, I also enjoy the logical challenge of puzzles like Sudoku and Nonograms.
</p>
</div>
<div class="mt-8">
<h2 class="text-xl font-semibold text-white mb-3">Programming Skills</h2>
<div class="flex flex-wrap gap-2">
<span class="skill-tag text-sm font-medium px-4 py-1 rounded-full">HTML</span>
<span class="skill-tag text-sm font-medium px-4 py-1 rounded-full">CSS</span>
<span class="skill-tag text-sm font-medium px-4 py-1 rounded-full">JavaScript</span>
<span class="skill-tag text-sm font-medium px-4 py-1 rounded-full">TypeScript</span>
<span class="skill-tag text-sm font-medium px-4 py-1 rounded-full">C#</span>
<span class="skill-tag text-sm font-medium px-4 py-1 rounded-full">C++</span>
<span class="skill-tag text-sm font-medium px-4 py-1 rounded-full">C</span>
<span class="skill-tag text-sm font-medium px-4 py-1 rounded-full">Java</span>
</div>
</div>
<!-- Current Project Section -->
<div class="mt-8">
<h2 class="text-xl font-semibold text-white mb-3">Current Hobby Project</h2>
<a href="https://weaver.cmzi.uk/" target="_blank" class="block p-4 rounded-lg skill-tag transition-all duration-300 ease-in-out hover:bg-white/30">
<div class="flex items-center space-x-4">
<div class="flex-shrink-0">
<svg class="w-8 h-8 text-cyan-300" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"></path></svg>
</div>
<div>
<p class="font-bold text-white">Word Weaver</p>
<p class="text-sm text-cyan-200">An AI-powered web game of "Alchemy" with infinite, wacky combinations.</p>
</div>
</div>
</a>
</div>
</div>
</div>
</div>
</main>
</body>
</html>

22
package.json Normal file
View file

@ -0,0 +1,22 @@
{
"name": "homepage",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"@iconify/json": "^2.2.367",
"unplugin-icons": "^22.2.0",
"vite": "^7.1.0"
},
"dependencies": {
"@fontsource-variable/exo-2": "^5.2.6",
"@fontsource-variable/inter": "^5.2.6",
"@tailwindcss/vite": "^4.1.11",
"tailwindcss": "^4.1.11"
}
}

1239
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load diff

3
pnpm-workspace.yaml Normal file
View file

@ -0,0 +1,3 @@
onlyBuiltDependencies:
- '@tailwindcss/oxide'
- esbuild

102
src/style.css Normal file
View file

@ -0,0 +1,102 @@
@import "tailwindcss";
@import "@fontsource-variable/exo-2";
/* Custom styles for the glassmorphism effect and background */
body {
font-family: 'Exo 2 Variable', sans-serif;
/* Deep blue theme */
background: linear-gradient(135deg, #2c3e50 0%, #4ca1af 100%);
overflow: hidden;
}
/* The main card with the glass effect */
.glass-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(25px);
-webkit-backdrop-filter: blur(25px);
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.2);
}
/* Decorative background shapes */
.shape {
position: absolute;
border-radius: 50%;
filter: blur(100px);
z-index: -1;
animation: float 20s infinite ease-in-out alternate;
}
.shape-1 {
width: 300px;
height: 300px;
background: rgba(76, 161, 175, 0.4);
top: -50px;
left: -50px;
animation-duration: 25s;
}
.shape-2 {
width: 400px;
height: 400px;
background: rgba(108, 99, 255, 0.3);
bottom: -100px;
right: -100px;
animation-duration: 20s;
}
.shape-3 {
width: 250px;
height: 250px;
background: rgba(67, 209, 217, 0.3);
bottom: 20%;
left: 10%;
animation-duration: 30s;
}
@keyframes float {
0% {
transform: translateY(0px) translateX(0px);
}
50% {
transform: translateY(-40px) translateX(20px);
}
100% {
transform: translateY(0px) translateX(0px);
}
}
/* Custom styling for skill tags and buttons */
.skill-tag {
background: rgba(255, 255, 255, 0.15);
transition: background 0.3s ease, transform 0.3s ease;
}
.skill-tag:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
}
/* Animated gradient for text */
.animated-gradient {
background: linear-gradient(90deg, #4dd0e1, #818cf8, #a5f3fc, #4dd0e1);
background-size: 200% auto;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
animation: gradient-animation 5s ease infinite;
}
@keyframes gradient-animation {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}

16
vite.config.js Normal file
View file

@ -0,0 +1,16 @@
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
import Icons from 'unplugin-icons/vite'
export default defineConfig({
plugins: [
tailwindcss(),
Icons({
compiler: 'web-components',
webComponents: {
autoDefine: true,
},
})
],
})