initial commit
1
.dockerignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
node_modules
|
25
.github/workflows/merge-main-into-small-image.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
name: merge-main-into-small-image.yml
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
types:
|
||||||
|
- closed
|
||||||
|
jobs:
|
||||||
|
merge-main-into-small-image:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event.pull_request.merged == true
|
||||||
|
timeout-minutes: 3
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Merge with main
|
||||||
|
run: |
|
||||||
|
git config user.name github-actions
|
||||||
|
git config user.email github-actions@github.com
|
||||||
|
git fetch
|
||||||
|
git checkout small-image
|
||||||
|
git merge main --no-ff --no-edit
|
||||||
|
git push origin small-image
|
104
.gitignore
vendored
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
BIN
img/logos/favicon-dark.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
img/logos/favicon-light.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
img/logos/favicon-mid.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
img/logos/favicon-t-dark.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
img/logos/favicon-t-light.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
img/logos/favicon-t-mid.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
img/logos/logo-dark.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
img/logos/logo-large.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
img/logos/logo-light.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
img/logos/logo-mid.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
img/logos/logo-white.png
Normal file
After Width: | Height: | Size: 14 KiB |
23
kube/Dockerfile
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Start your image with a node base image
|
||||||
|
FROM node:18-alpine
|
||||||
|
|
||||||
|
# The /app directory should act as the main application directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy the app package and package-lock.json file
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Copy local directories to the current local directory of our docker image (/app)
|
||||||
|
COPY ./src ./src
|
||||||
|
COPY ./public ./public
|
||||||
|
|
||||||
|
# Install node packages, install serve, build the app, and remove dependencies at the end
|
||||||
|
RUN npm install \
|
||||||
|
&& npm install -g serve \
|
||||||
|
&& npm run build \
|
||||||
|
&& rm -fr node_modules
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Start the app using serve command
|
||||||
|
CMD [ "serve", "-s", "build" ]
|
107
kube/deploy-tomcode.yaml
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: sites
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolume
|
||||||
|
metadata:
|
||||||
|
name: tomcode-pv
|
||||||
|
labels:
|
||||||
|
type: local
|
||||||
|
spec:
|
||||||
|
storageClassName: manual
|
||||||
|
capacity:
|
||||||
|
storage: 128Mi
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteMany
|
||||||
|
hostPath:
|
||||||
|
path: "/var/lib/rancher/k3s/storage/tomcode"
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: tomcode-pvc
|
||||||
|
namespace: sites
|
||||||
|
spec:
|
||||||
|
volumeName: tomcode-pv
|
||||||
|
storageClassName: manual
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteMany
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 128Mi
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: tomcode
|
||||||
|
namespace: sites
|
||||||
|
labels:
|
||||||
|
app: tomcode
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: tomcode
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: tomcode
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: tomcode
|
||||||
|
image: tommansfield/tomcode:latest
|
||||||
|
imagePullPolicy: Always
|
||||||
|
ports:
|
||||||
|
- containerPort: 3000
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "1"
|
||||||
|
volumeMounts:
|
||||||
|
- name: tomcode-volume
|
||||||
|
mountPath: /data
|
||||||
|
subPath: ./web
|
||||||
|
volumes:
|
||||||
|
- name: tomcode-volume
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: tomcode-pvc
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: tomcode
|
||||||
|
namespace: sites
|
||||||
|
labels:
|
||||||
|
app: tomcode
|
||||||
|
spec:
|
||||||
|
type: LoadBalancer
|
||||||
|
ports:
|
||||||
|
- name: tomcode
|
||||||
|
port: 80
|
||||||
|
targetPort: 3000
|
||||||
|
nodePort: 30800
|
||||||
|
selector:
|
||||||
|
app: tomcode
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: tomcode
|
||||||
|
namespace: sites
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- kind: Rule
|
||||||
|
match: Host(`tomcode.io`, `www.tomcode.io`)
|
||||||
|
services:
|
||||||
|
- name: tomcode
|
||||||
|
port: 80
|
||||||
|
tls:
|
||||||
|
certResolver: letsencrypt
|
||||||
|
domains:
|
||||||
|
- main: "tomcode.io"
|
||||||
|
sans:
|
||||||
|
- "*.tomcode.io"
|
16967
package-lock.json
generated
Normal file
36
package.json
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"name": "welcome-to-docker",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"react-particles": "^2.9.3",
|
||||||
|
"react-scripts": "5.0.1",
|
||||||
|
"tsparticles": "^2.9.3"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "react-scripts start",
|
||||||
|
"build": "react-scripts build",
|
||||||
|
"test": "react-scripts test",
|
||||||
|
"eject": "react-scripts eject"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": [
|
||||||
|
"react-app",
|
||||||
|
"react-app/jest"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
],
|
||||||
|
"development": [
|
||||||
|
"last 1 chrome version",
|
||||||
|
"last 1 firefox version",
|
||||||
|
"last 1 safari version"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
BIN
public/favicon-dark.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
public/favicon-light.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
18
public/index.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<meta name="theme-color" content="#000000" />
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"
|
||||||
|
/>
|
||||||
|
<title>tomcode.io</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
<div id="root"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
public/logo-white.png
Normal file
After Width: | Height: | Size: 14 KiB |
3
public/robots.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# https://www.robotstxt.org/robotstxt.html
|
||||||
|
User-agent: *
|
||||||
|
Disallow:
|
36
src/App.css
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
.App {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.App-logo {
|
||||||
|
height: 40vmin;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.App-header {
|
||||||
|
background-color: #003f8c;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: calc(10px + 3vmin);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.App-header h1 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.App-header p {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.App-header .logo {
|
||||||
|
width: 40vw;
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blue {
|
||||||
|
color:#269cfc
|
||||||
|
}
|
19
src/App.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import "./App.css";
|
||||||
|
import Confetti from "./Confetti";
|
||||||
|
|
||||||
|
const App = () => {
|
||||||
|
return (
|
||||||
|
<div className="App">
|
||||||
|
<Confetti />
|
||||||
|
<header className="App-header">
|
||||||
|
<img className="logo" src="logo-white.png" alt="tomcode.io computer logo"></img>
|
||||||
|
<h1 style={{ marginBottom: "0px" }}>tomcode<span className="blue">.io</span></h1>
|
||||||
|
<p style={{ marginTop: "10px", marginBottom: "50px" }}>
|
||||||
|
Love the web 💻
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
177
src/Confetti.js
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
import Particles from "react-particles";
|
||||||
|
import { useCallback } from "react";
|
||||||
|
import { loadFull } from "tsparticles";
|
||||||
|
|
||||||
|
const Confetti = () => {
|
||||||
|
|
||||||
|
const particlesInit = useCallback(async engine => {
|
||||||
|
console.log(engine);
|
||||||
|
// you can initiate the tsParticles instance (engine) here, adding custom shapes or presets
|
||||||
|
// this loads the tsparticles package bundle, it's the easiest method for getting everything ready
|
||||||
|
// starting from v2 you can add only the features you need reducing the bundle size
|
||||||
|
await loadFull(engine);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const particlesLoaded = useCallback(async container => {
|
||||||
|
await console.log(container);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Particles
|
||||||
|
id="tsparticles"
|
||||||
|
init={particlesInit}
|
||||||
|
loaded={particlesLoaded}
|
||||||
|
options={{
|
||||||
|
fullScreen: {
|
||||||
|
zIndex: 1
|
||||||
|
},
|
||||||
|
emitters: [
|
||||||
|
{
|
||||||
|
position: {
|
||||||
|
x: 0,
|
||||||
|
y: 30
|
||||||
|
},
|
||||||
|
rate: {
|
||||||
|
quantity: 5,
|
||||||
|
delay: 0.15
|
||||||
|
},
|
||||||
|
particles: {
|
||||||
|
move: {
|
||||||
|
direction: "top-right",
|
||||||
|
outModes: {
|
||||||
|
top: "none",
|
||||||
|
left: "none",
|
||||||
|
default: "destroy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: {
|
||||||
|
x: 100,
|
||||||
|
y: 30
|
||||||
|
},
|
||||||
|
rate: {
|
||||||
|
quantity: 5,
|
||||||
|
delay: 0.15
|
||||||
|
},
|
||||||
|
particles: {
|
||||||
|
move: {
|
||||||
|
direction: "top-left",
|
||||||
|
outModes: {
|
||||||
|
top: "none",
|
||||||
|
right: "none",
|
||||||
|
default: "destroy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
particles: {
|
||||||
|
color: {
|
||||||
|
value: [
|
||||||
|
"#ffffff",
|
||||||
|
"#FF0000"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
move: {
|
||||||
|
decay: 0.05,
|
||||||
|
direction: "top",
|
||||||
|
enable: true,
|
||||||
|
gravity: {
|
||||||
|
"enable": true
|
||||||
|
},
|
||||||
|
outModes: {
|
||||||
|
top: "none",
|
||||||
|
default: "destroy"
|
||||||
|
},
|
||||||
|
speed: {
|
||||||
|
min: 10,
|
||||||
|
max: 50
|
||||||
|
}
|
||||||
|
},
|
||||||
|
number: {
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
opacity: {
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
rotate: {
|
||||||
|
value: {
|
||||||
|
min: 0,
|
||||||
|
max: 360
|
||||||
|
},
|
||||||
|
direction: "random",
|
||||||
|
animation: {
|
||||||
|
enable: true,
|
||||||
|
speed: 30
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tilt: {
|
||||||
|
direction: "random",
|
||||||
|
enable: true,
|
||||||
|
value: {
|
||||||
|
min: 0,
|
||||||
|
max: 360
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
enable: true,
|
||||||
|
speed: 30
|
||||||
|
}
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
value: {
|
||||||
|
min: 0,
|
||||||
|
max: 7
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
enable: true,
|
||||||
|
startValue: "min",
|
||||||
|
count: 1,
|
||||||
|
speed: 16,
|
||||||
|
sync: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
roll: {
|
||||||
|
darken: {
|
||||||
|
enable: true,
|
||||||
|
value: 25
|
||||||
|
},
|
||||||
|
enable: true,
|
||||||
|
speed: {
|
||||||
|
min: 5,
|
||||||
|
max: 15
|
||||||
|
}
|
||||||
|
},
|
||||||
|
wobble: {
|
||||||
|
distance: 30,
|
||||||
|
enable: true,
|
||||||
|
speed: {
|
||||||
|
min: -7,
|
||||||
|
max: 7
|
||||||
|
}
|
||||||
|
},
|
||||||
|
shape: {
|
||||||
|
type: [
|
||||||
|
"square",
|
||||||
|
"triangle",
|
||||||
|
"polygon"
|
||||||
|
],
|
||||||
|
options: {
|
||||||
|
polygon: [
|
||||||
|
{
|
||||||
|
sides: 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sides: 6
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Confetti;
|
13
src/index.css
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||||
|
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||||
|
sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Roboto',
|
||||||
|
monospace;
|
||||||
|
}
|
11
src/index.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom/client';
|
||||||
|
import './index.css';
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||||
|
root.render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>
|
||||||
|
);
|