Intial commit.
This commit is contained in:
commit
349d0ad4ff
11 changed files with 1676 additions and 0 deletions
77
.forgejo/workflows/build-and-dockerise.yml
Normal file
77
.forgejo/workflows/build-and-dockerise.yml
Normal 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
|
35
.forgejo/workflows/deploy.yml
Normal file
35
.forgejo/workflows/deploy.yml
Normal 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
24
.gitignore
vendored
Normal 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
11
Dockerfile
Normal 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
54
entrypoint.sh
Normal 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
93
index.html
Normal 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
22
package.json
Normal 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
1239
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load diff
3
pnpm-workspace.yaml
Normal file
3
pnpm-workspace.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
onlyBuiltDependencies:
|
||||
- '@tailwindcss/oxide'
|
||||
- esbuild
|
102
src/style.css
Normal file
102
src/style.css
Normal 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
16
vite.config.js
Normal 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,
|
||||
},
|
||||
})
|
||||
],
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue