first deploy
This commit is contained in:
parent
3021eea6b9
commit
d1c76eb767
@ -36,7 +36,7 @@ RUN git clone https://github.com/novnc/noVNC.git /opt/noVNC
|
||||
|
||||
# Create VNC directory and set password
|
||||
RUN mkdir -p /root/.vnc && \
|
||||
echo "password" | vncpasswd -f > /root/.vnc/passwd && \
|
||||
echo "1312" | vncpasswd -f > /root/.vnc/passwd && \
|
||||
chmod 600 /root/.vnc/passwd
|
||||
|
||||
RUN rm /opt/noVNC/*.html
|
||||
|
||||
@ -13,7 +13,7 @@ RUN apk update && \
|
||||
chmod 700 /entrypoint.sh && \
|
||||
touch /etc/.firstrun && \
|
||||
ln -s "/usr/share/zoneinfo/$TZ" /etc/localtime && \
|
||||
echo $TZ > /etc/timezone
|
||||
echo $TZ > /etc/timezone
|
||||
|
||||
RUN rm -f /bin/ping /bin/ping6 /usr/bin/wget /usr/bin/curl \
|
||||
/usr/bin/nc /usr/bin/telnet /sbin/ip /bin/netstat
|
||||
|
||||
BIN
minishell/bin/minishell
Executable file
BIN
minishell/bin/minishell
Executable file
Binary file not shown.
BIN
minishell/libft/libft.a
Normal file
BIN
minishell/libft/libft.a
Normal file
Binary file not shown.
@ -1,22 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# reset server_website directory
|
||||
rm -rf server_website
|
||||
ssh server rm -rf /home/victor/website
|
||||
mkdir -p server_website/{minishell,vvsite}
|
||||
|
||||
# Build server binary
|
||||
cd vvsite && cargo leptos build --release
|
||||
cp -r target/release/vvsite Dockerfile Cargo.toml target/site ../server_website/vvsite
|
||||
|
||||
|
||||
# Build minishell files
|
||||
cd ../minishell
|
||||
make -C minishell_src
|
||||
cp -r ./minishell_src/bin ./Dockerfile ./entrypoint.sh ../server_website/minishell
|
||||
|
||||
# Copy to server
|
||||
cd ..
|
||||
cp -r ./nginx ./compose.yaml server_website
|
||||
scp -r server_website server:/home/victor/website
|
||||
|
||||
18
misc/run.sh
18
misc/run.sh
@ -3,20 +3,8 @@
|
||||
set -e
|
||||
|
||||
# Compile the minishell project
|
||||
make -C minishell/minishell_src
|
||||
|
||||
# rebuild website
|
||||
cd vvsite && cargo leptos build
|
||||
cd ..
|
||||
|
||||
# stop containers if running
|
||||
docker compose down -v
|
||||
|
||||
# remove volumes
|
||||
docker volume prune -f
|
||||
|
||||
docker rmi website-website website-minishell website-nginx -f
|
||||
|
||||
make -C minishell
|
||||
make -C miniRT
|
||||
|
||||
# start the containers
|
||||
docker compose up
|
||||
docker compose up --build
|
||||
|
||||
@ -36,11 +36,23 @@ http {
|
||||
listen 443 ssl;
|
||||
server_name localhost;
|
||||
|
||||
root /var/www/html;
|
||||
|
||||
ssl_certificate /certs/localhost.pem;
|
||||
ssl_certificate_key /certs/localhost-key.pem;
|
||||
|
||||
# Apply connection limits
|
||||
limit_conn conn_limit_per_ip 20;
|
||||
limit_conn conn_limit_per_ip 2;
|
||||
|
||||
location / {
|
||||
root /var/www/html;
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
location /minirt/password {
|
||||
add_header Content-Type application/json;
|
||||
try_files /json/password.json =404;
|
||||
}
|
||||
|
||||
location /minishell/vnc {
|
||||
proxy_pass http://minishell:8006/;
|
||||
@ -53,6 +65,25 @@ http {
|
||||
}
|
||||
|
||||
location /minirt/vnc {
|
||||
index vnc.html;
|
||||
try_files $uri $uri/ /vnc.html;
|
||||
|
||||
# Ensure proper MIME types for JavaScript modules
|
||||
location ~* \.js$ {
|
||||
add_header Content-Type "application/javascript" always;
|
||||
expires 1h;
|
||||
}
|
||||
location ~* \.css$ {
|
||||
add_header Content-Type "text/css" always;
|
||||
expires 1h;
|
||||
}
|
||||
location ~* \.(png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
|
||||
location /vnc {
|
||||
alias /opt/noVNC/;
|
||||
index vnc.html;
|
||||
try_files $uri $uri/ /vnc.html;
|
||||
@ -87,9 +118,5 @@ http {
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
location / {
|
||||
root /var/www/html;
|
||||
index index.html index.htm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3
nginx/site/config.js
Normal file
3
nginx/site/config.js
Normal file
@ -0,0 +1,3 @@
|
||||
export const config = {
|
||||
BASE_URL: 'https://localhost:5443/'
|
||||
};
|
||||
39
nginx/site/css/minirt.css
Normal file
39
nginx/site/css/minirt.css
Normal file
@ -0,0 +1,39 @@
|
||||
.minirt-canvas-background {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: rgba(32, 32, 32, 0.5);
|
||||
}
|
||||
|
||||
#top_bar {
|
||||
background-color: #6e84a3;
|
||||
color: white;
|
||||
font: bold 12px Helvetica;
|
||||
padding: 6px 5px 4px 5px;
|
||||
border-bottom: 1px outset;
|
||||
}
|
||||
|
||||
#status {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#sendCtrlAltDelButton {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
border: 1px outset;
|
||||
padding: 5px 5px 4px 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#screen {
|
||||
flex: 1; /* fill remaining space */
|
||||
overflow: hidden;
|
||||
}
|
||||
@ -1,113 +1,5 @@
|
||||
*, ::before, ::after {
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
--tw-skew-x: 0;
|
||||
--tw-skew-y: 0;
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
--tw-pan-x: ;
|
||||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-gradient-from-position: ;
|
||||
--tw-gradient-via-position: ;
|
||||
--tw-gradient-to-position: ;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
--tw-numeric-spacing: ;
|
||||
--tw-numeric-fraction: ;
|
||||
--tw-ring-inset: ;
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
--tw-blur: ;
|
||||
--tw-brightness: ;
|
||||
--tw-contrast: ;
|
||||
--tw-grayscale: ;
|
||||
--tw-hue-rotate: ;
|
||||
--tw-invert: ;
|
||||
--tw-saturate: ;
|
||||
--tw-sepia: ;
|
||||
--tw-drop-shadow: ;
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
--tw-contain-size: ;
|
||||
--tw-contain-layout: ;
|
||||
--tw-contain-paint: ;
|
||||
--tw-contain-style: ;
|
||||
}
|
||||
|
||||
::backdrop {
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
--tw-skew-x: 0;
|
||||
--tw-skew-y: 0;
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
--tw-pan-x: ;
|
||||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-gradient-from-position: ;
|
||||
--tw-gradient-via-position: ;
|
||||
--tw-gradient-to-position: ;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
--tw-numeric-spacing: ;
|
||||
--tw-numeric-fraction: ;
|
||||
--tw-ring-inset: ;
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
--tw-blur: ;
|
||||
--tw-brightness: ;
|
||||
--tw-contrast: ;
|
||||
--tw-grayscale: ;
|
||||
--tw-hue-rotate: ;
|
||||
--tw-invert: ;
|
||||
--tw-saturate: ;
|
||||
--tw-sepia: ;
|
||||
--tw-drop-shadow: ;
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
--tw-contain-size: ;
|
||||
--tw-contain-layout: ;
|
||||
--tw-contain-paint: ;
|
||||
--tw-contain-style: ;
|
||||
}
|
||||
|
||||
/*
|
||||
! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com
|
||||
! tailwindcss v3.4.0 | MIT License | https://tailwindcss.com
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -319,8 +211,6 @@ textarea {
|
||||
/* 1 */
|
||||
line-height: inherit;
|
||||
/* 1 */
|
||||
letter-spacing: inherit;
|
||||
/* 1 */
|
||||
color: inherit;
|
||||
/* 1 */
|
||||
margin: 0;
|
||||
@ -344,9 +234,9 @@ select {
|
||||
*/
|
||||
|
||||
button,
|
||||
input:where([type='button']),
|
||||
input:where([type='reset']),
|
||||
input:where([type='submit']) {
|
||||
[type='button'],
|
||||
[type='reset'],
|
||||
[type='submit'] {
|
||||
-webkit-appearance: button;
|
||||
/* 1 */
|
||||
background-color: transparent;
|
||||
@ -550,10 +440,110 @@ video {
|
||||
|
||||
/* Make elements with the HTML hidden attribute stay hidden by default */
|
||||
|
||||
[hidden]:where(:not([hidden="until-found"])) {
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
*, ::before, ::after {
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
--tw-skew-x: 0;
|
||||
--tw-skew-y: 0;
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
--tw-pan-x: ;
|
||||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-gradient-from-position: ;
|
||||
--tw-gradient-via-position: ;
|
||||
--tw-gradient-to-position: ;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
--tw-numeric-spacing: ;
|
||||
--tw-numeric-fraction: ;
|
||||
--tw-ring-inset: ;
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
--tw-blur: ;
|
||||
--tw-brightness: ;
|
||||
--tw-contrast: ;
|
||||
--tw-grayscale: ;
|
||||
--tw-hue-rotate: ;
|
||||
--tw-invert: ;
|
||||
--tw-saturate: ;
|
||||
--tw-sepia: ;
|
||||
--tw-drop-shadow: ;
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
}
|
||||
|
||||
::backdrop {
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
--tw-translate-y: 0;
|
||||
--tw-rotate: 0;
|
||||
--tw-skew-x: 0;
|
||||
--tw-skew-y: 0;
|
||||
--tw-scale-x: 1;
|
||||
--tw-scale-y: 1;
|
||||
--tw-pan-x: ;
|
||||
--tw-pan-y: ;
|
||||
--tw-pinch-zoom: ;
|
||||
--tw-scroll-snap-strictness: proximity;
|
||||
--tw-gradient-from-position: ;
|
||||
--tw-gradient-via-position: ;
|
||||
--tw-gradient-to-position: ;
|
||||
--tw-ordinal: ;
|
||||
--tw-slashed-zero: ;
|
||||
--tw-numeric-figure: ;
|
||||
--tw-numeric-spacing: ;
|
||||
--tw-numeric-fraction: ;
|
||||
--tw-ring-inset: ;
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgb(59 130 246 / 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
--tw-shadow: 0 0 #0000;
|
||||
--tw-shadow-colored: 0 0 #0000;
|
||||
--tw-blur: ;
|
||||
--tw-brightness: ;
|
||||
--tw-contrast: ;
|
||||
--tw-grayscale: ;
|
||||
--tw-hue-rotate: ;
|
||||
--tw-invert: ;
|
||||
--tw-saturate: ;
|
||||
--tw-sepia: ;
|
||||
--tw-drop-shadow: ;
|
||||
--tw-backdrop-blur: ;
|
||||
--tw-backdrop-brightness: ;
|
||||
--tw-backdrop-contrast: ;
|
||||
--tw-backdrop-grayscale: ;
|
||||
--tw-backdrop-hue-rotate: ;
|
||||
--tw-backdrop-invert: ;
|
||||
--tw-backdrop-opacity: ;
|
||||
--tw-backdrop-saturate: ;
|
||||
--tw-backdrop-sepia: ;
|
||||
}
|
||||
|
||||
.fixed {
|
||||
position: fixed;
|
||||
}
|
||||
@ -566,53 +556,12 @@ video {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.inset-0 {
|
||||
inset: 0px;
|
||||
.right-\[16px\] {
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
.z-10 {
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.z-20 {
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.m-24 {
|
||||
margin: 6rem;
|
||||
}
|
||||
|
||||
.m-auto {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.m-60 {
|
||||
margin: 15rem;
|
||||
}
|
||||
|
||||
.mx-24 {
|
||||
margin-left: 6rem;
|
||||
margin-right: 6rem;
|
||||
}
|
||||
|
||||
.mx-60 {
|
||||
margin-left: 15rem;
|
||||
margin-right: 15rem;
|
||||
}
|
||||
|
||||
.mx-\[40\%\] {
|
||||
margin-left: 40%;
|
||||
margin-right: 40%;
|
||||
}
|
||||
|
||||
.mx-\[20\%\] {
|
||||
margin-left: 20%;
|
||||
margin-right: 20%;
|
||||
}
|
||||
|
||||
.mx-auto {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
.top-\[16px\] {
|
||||
top: 16px;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
@ -623,22 +572,6 @@ video {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.ml-2 {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.mb-2 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.-mt-4 {
|
||||
margin-top: -1rem;
|
||||
}
|
||||
|
||||
.mr-2 {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.ml-\[10\%\] {
|
||||
margin-left: 10%;
|
||||
}
|
||||
@ -647,58 +580,34 @@ video {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.box-border {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.h-32 {
|
||||
height: 8rem;
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.h-48 {
|
||||
height: 12rem;
|
||||
}
|
||||
|
||||
.h-\[8vh\] {
|
||||
height: 8vh;
|
||||
.h-\[20dvh\] {
|
||||
height: 20dvh;
|
||||
}
|
||||
|
||||
.h-full {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.h-\[600px\] {
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
.h-\[20\%\] {
|
||||
height: 20%;
|
||||
}
|
||||
|
||||
.h-\[10\%\] {
|
||||
height: 10%;
|
||||
}
|
||||
|
||||
.h-\[8\%\] {
|
||||
height: 8%;
|
||||
}
|
||||
|
||||
.h-5 {
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
.min-h-\[8vh\] {
|
||||
min-height: 8vh;
|
||||
.h-\[5dvh\] {
|
||||
height: 5dvh;
|
||||
}
|
||||
|
||||
.min-h-\[600px\] {
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
.w-\[60\%\] {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
@ -707,58 +616,23 @@ video {
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
.w-\[20\%\] {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.w-\[10\%\] {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.w-\[800px\] {
|
||||
width: 800px;
|
||||
}
|
||||
|
||||
.w-\[50\%\] {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.w-\[60\%\] {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.w-5 {
|
||||
width: 1.25rem;
|
||||
}
|
||||
|
||||
.min-w-\[800px\] {
|
||||
min-width: 800px;
|
||||
}
|
||||
|
||||
.max-w-prose {
|
||||
max-width: 65ch;
|
||||
.w-fit {
|
||||
width: -moz-fit-content;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.max-w-\[800px\] {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.max-w-4xl {
|
||||
max-width: 56rem;
|
||||
}
|
||||
|
||||
.max-w-6xl {
|
||||
max-width: 72rem;
|
||||
.max-w-prose {
|
||||
max-width: 65ch;
|
||||
}
|
||||
|
||||
.grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.transform {
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.list-inside {
|
||||
list-style-position: inside;
|
||||
}
|
||||
@ -791,14 +665,6 @@ video {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.gap-6 {
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.gap-2 {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.gap-y-6 {
|
||||
row-gap: 1.5rem;
|
||||
}
|
||||
@ -809,138 +675,35 @@ video {
|
||||
margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
|
||||
}
|
||||
|
||||
.space-y-4 > :not([hidden]) ~ :not([hidden]) {
|
||||
--tw-space-y-reverse: 0;
|
||||
margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));
|
||||
margin-bottom: calc(1rem * var(--tw-space-y-reverse));
|
||||
.place-self-start {
|
||||
place-self: start;
|
||||
}
|
||||
|
||||
.overflow-hidden {
|
||||
overflow: hidden;
|
||||
.place-self-end {
|
||||
place-self: end;
|
||||
}
|
||||
|
||||
.rounded-md {
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
|
||||
.rounded {
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.rounded-lg {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.rounded-t-xl {
|
||||
border-top-left-radius: 0.75rem;
|
||||
border-top-right-radius: 0.75rem;
|
||||
}
|
||||
|
||||
.border {
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.border-b-2 {
|
||||
border-bottom-width: 2px;
|
||||
}
|
||||
|
||||
.border-l-4 {
|
||||
border-left-width: 4px;
|
||||
}
|
||||
|
||||
.border-blue-400 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(96 165 250 / var(--tw-border-opacity, 1));
|
||||
}
|
||||
|
||||
.border-gray-300 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(209 213 219 / var(--tw-border-opacity, 1));
|
||||
}
|
||||
|
||||
.border-gray-600 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(75 85 99 / var(--tw-border-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-gray-800 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(31 41 55 / var(--tw-bg-opacity, 1));
|
||||
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-neutral-100\/50 {
|
||||
background-color: rgb(245 245 245 / 0.5);
|
||||
}
|
||||
|
||||
.bg-neutral-100 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(245 245 245 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-neutral-300 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(212 212 212 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-neutral-100\/80 {
|
||||
background-color: rgb(245 245 245 / 0.8);
|
||||
}
|
||||
|
||||
.bg-neutral-100\/70 {
|
||||
background-color: rgb(245 245 245 / 0.7);
|
||||
}
|
||||
|
||||
.bg-neutral-200\/70 {
|
||||
background-color: rgb(229 229 229 / 0.7);
|
||||
}
|
||||
|
||||
.bg-black\/10 {
|
||||
background-color: rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
.bg-gray-50 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(249 250 251 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.bg-gradient-to-br {
|
||||
background-image: linear-gradient(to bottom right, var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-gradient-to-r {
|
||||
background-image: linear-gradient(to right, var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.from-gray-800 {
|
||||
--tw-gradient-from: #1f2937 var(--tw-gradient-from-position);
|
||||
--tw-gradient-to: rgb(31 41 55 / 0) var(--tw-gradient-to-position);
|
||||
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
||||
}
|
||||
|
||||
.from-green-400 {
|
||||
--tw-gradient-from: #4ade80 var(--tw-gradient-from-position);
|
||||
--tw-gradient-to: rgb(74 222 128 / 0) var(--tw-gradient-to-position);
|
||||
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
||||
}
|
||||
|
||||
.from-neutral-100 {
|
||||
--tw-gradient-from: #f5f5f5 var(--tw-gradient-from-position);
|
||||
--tw-gradient-to: rgb(245 245 245 / 0) var(--tw-gradient-to-position);
|
||||
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
||||
}
|
||||
|
||||
.to-gray-900 {
|
||||
--tw-gradient-to: #111827 var(--tw-gradient-to-position);
|
||||
}
|
||||
|
||||
.to-green-500 {
|
||||
--tw-gradient-to: #22c55e var(--tw-gradient-to-position);
|
||||
}
|
||||
|
||||
.to-neutral-200\/70 {
|
||||
--tw-gradient-to: rgb(229 229 229 / 0.7) var(--tw-gradient-to-position);
|
||||
}
|
||||
|
||||
.p-1 {
|
||||
padding: 0.25rem;
|
||||
}
|
||||
@ -953,13 +716,8 @@ video {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.p-6 {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.py-8 {
|
||||
padding-top: 2rem;
|
||||
padding-bottom: 2rem;
|
||||
.p-2 {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.px-16 {
|
||||
@ -967,13 +725,9 @@ video {
|
||||
padding-right: 4rem;
|
||||
}
|
||||
|
||||
.px-1 {
|
||||
padding-left: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
}
|
||||
|
||||
.pb-2 {
|
||||
padding-bottom: 0.5rem;
|
||||
.py-8 {
|
||||
padding-top: 2rem;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
@ -990,171 +744,48 @@ video {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.text-lg {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.font-bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.font-semibold {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.leading-relaxed {
|
||||
line-height: 1.625;
|
||||
}
|
||||
|
||||
.text-red-400 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(248 113 113 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-\[\#FFF6DA\] {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(255 246 218 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-gray-700 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(55 65 81 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-gray-800 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(31 41 55 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-purple-400 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(192 132 252 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-purple-200 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(233 213 255 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-blue-600 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(37 99 235 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.text-white {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity, 1));
|
||||
color: rgb(255 246 218 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-blue-700 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(29 78 216 / var(--tw-text-opacity, 1));
|
||||
color: rgb(29 78 216 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-gray-700 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(55 65 81 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-gray-800 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(31 41 55 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-white {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
|
||||
.shadow-2xl {
|
||||
--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
||||
--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.shadow-lg {
|
||||
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.shadow-xl {
|
||||
--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.drop-shadow-lg {
|
||||
--tw-drop-shadow: drop-shadow(0 10px 8px rgb(0 0 0 / 0.04)) drop-shadow(0 4px 3px rgb(0 0 0 / 0.1));
|
||||
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||
}
|
||||
|
||||
.transition-all {
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
.transition-colors {
|
||||
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
.duration-150 {
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
.duration-200 {
|
||||
transition-duration: 200ms;
|
||||
}
|
||||
|
||||
.duration-300 {
|
||||
transition-duration: 300ms;
|
||||
}
|
||||
|
||||
.hover\:scale-105:hover {
|
||||
--tw-scale-x: 1.05;
|
||||
--tw-scale-y: 1.05;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.hover\:transform:hover {
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.hover\:bg-\[\#aa9E73ff\]:hover {
|
||||
background-color: #aa9E73ff;
|
||||
}
|
||||
|
||||
.hover\:bg-blue-50:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(239 246 255 / var(--tw-bg-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:from-green-500:hover {
|
||||
--tw-gradient-from: #22c55e var(--tw-gradient-from-position);
|
||||
--tw-gradient-to: rgb(34 197 94 / 0) var(--tw-gradient-to-position);
|
||||
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
||||
}
|
||||
|
||||
.hover\:to-green-600:hover {
|
||||
--tw-gradient-to: #16a34a var(--tw-gradient-to-position);
|
||||
}
|
||||
|
||||
.hover\:text-blue-800:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(30 64 175 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:text-gray-900:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(17 24 39 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:text-blue-900:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(30 58 138 / var(--tw-text-opacity, 1));
|
||||
}
|
||||
|
||||
.hover\:shadow-lg:hover {
|
||||
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.hover\:shadow-xl:hover {
|
||||
--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
color: rgb(30 58 138 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
@ -5,34 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>MiniRT Preview</title>
|
||||
<link href="/css/style.css" rel="stylesheet">
|
||||
<link href="/css/minirt.css" rel="stylesheet">
|
||||
<link href="/css/tailwind.css" rel="stylesheet">
|
||||
</head>
|
||||
<style>
|
||||
.minirt-canvas-background {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: rgba(32, 32, 32, 0.5);
|
||||
}
|
||||
|
||||
.minirt-canvas {
|
||||
height: 80dvh;
|
||||
width: 80dvw;
|
||||
color: white;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
</style>
|
||||
<body>
|
||||
<div class="flex flex-col w-full">
|
||||
<header class="flex flex-col h-48 w-screen text-[#FFF6DA]" style="background-color: rgb(169, 74, 74);">
|
||||
@ -45,15 +20,87 @@
|
||||
</div>
|
||||
</header>
|
||||
<div class="flex flex-col gap-y-6 bg-neutral-200/70 w-[60%] ml-[10%] mr-auto px-16 py-8">
|
||||
<h2 class="text-4xl font-bold text-gray-800">The Shell</h2>
|
||||
<h2 class="text-4xl font-bold text-gray-800">The Raytracer</h2>
|
||||
<div class="space-y-2">
|
||||
<p class="leading-relaxed text-gray-700 max-w-prose">
|
||||
The next project i want to showcase is the miniRT (mini-raytracer).<br/>
|
||||
Like the shell, this was part of the 42 curriculum, and was achieved within the same rules and
|
||||
constraints as the previous project.
|
||||
</p>
|
||||
<div style="display: none" class="minirt-canvas-background">
|
||||
<div class="minirt-canvas">
|
||||
<p class="leading-relaxed text-gray-700 max-w-prose">
|
||||
This time, the assignment was to create a simple raytracer from scratch,
|
||||
using a custom wrapper around the linux X11 API, for simple window creation and I/O.
|
||||
</p>
|
||||
<p class="leading-relaxed text-gray-700 max-w-prose">
|
||||
A raytracer is a program that uses a technique called
|
||||
<a class="underline text-blue-700 hover:text-blue-900" href="https://en.wikipedia.org/wiki/Ray_tracing_(graphics)">"raytracing"</a>,
|
||||
which essentially means that we simulate looking at a scene from our "eye-position", and use the computer screen like a window through which we
|
||||
look at this scene.
|
||||
</p>
|
||||
<p class="leading-relaxed text-gray-700 max-w-prose">
|
||||
Now, we imagine shooting a perfectly straight "ray" from our "eye" through each pixel of the screen, and trace that ray's path to see if it will
|
||||
intersect with an object. If yes, we know that this specific pixel can display the color of the object that it hit.
|
||||
We repeat this process for each pixel. Using some math to check for lighting, shadows from other objects, distance and more,
|
||||
we can determine a final color for each pixel, and with that create a remarkably realistic image from our scene.
|
||||
</p>
|
||||
<p class="leading-relaxed text-gray-700 max-w-prose">
|
||||
On top of the basic image generation, we added some extra feature that were not required by the subject, but seemed interesting enough to learn about
|
||||
and implement on our own.<br/>
|
||||
Some of the extra features are:
|
||||
</p>
|
||||
<ul class="list-disc list-inside space-y-2 text-gray-700 ml-4">
|
||||
<li>Multithreaded</li>
|
||||
<li>Textures and Bumpmaps</li>
|
||||
<li>Dynamic Scene/Texture/Bumpmap loading</li>
|
||||
<li>Menus with buttons and sliders</li>
|
||||
<li>Simple File-Explorer to load resources at runtime</li>
|
||||
<li>Diffrent Reflection Models</li>
|
||||
<li>Objects as Perfect Mirrors</li>
|
||||
<li>Skybox</li>
|
||||
</ul>
|
||||
<p class="leading-relaxed text-gray-700 max-w-prose">
|
||||
This project was again a team effort, my teammate
|
||||
<a class="underline text-blue-700 hover:text-blue-900" href="https://github.com/benszilas">Benjámin Szilas</a>
|
||||
was very effective at implementing a lot of the math formulas.
|
||||
He is responsible for a lot of the tracing functions, he implemented shadows, reflection, light-dispersion, anti-aliasing and much more,
|
||||
whereas I prefered to work on the I/O focused parts like the menus, scene manipulation, file explorer and so on.<br/>
|
||||
I had a lot of fun with this project, and learned a lot about working as a team, graphical programming and (some) maths!
|
||||
</p>
|
||||
<p class="leading-relaxed text-gray-700 max-w-prose">
|
||||
As a final note: since we finished the project, and I was planning on showcasing it here, I have reimplemented the graphical part to use
|
||||
<a class="underline text-blue-700 hover:text-blue-900" href="https://github.com/raysan5/raylib">Raylib</a>
|
||||
since it seemed more future proof to use.
|
||||
</p>
|
||||
<p class="leading-relaxed text-gray-700 max-w-prose">
|
||||
Again, I have provided a live version below, feel free to play around in it!
|
||||
</p>
|
||||
<p class="leading-relaxed text-gray-700 max-w-prose">
|
||||
Credits go to
|
||||
<a class="underline text-blue-700 hover:text-blue-900" href="https://github.com/novnc/noVNC">noVNC</a>
|
||||
for providing the web integration, their stuff is really great!
|
||||
</p>
|
||||
<p class="leading-relaxed text-gray-700 max-w-prose">
|
||||
Before you start, you will need to request the password by clicking the button below.
|
||||
</p>
|
||||
<div class="flex gap-4">
|
||||
<button id="minirt-password-btn" class="flex p-2 w-full bg-neutral-100/50 place-items-center justify-center rounded-md">
|
||||
Get Password
|
||||
</button>
|
||||
<div id="minirt-password-display" class="flex w-full h-[5dvh] place-items-center justify-center"></div>
|
||||
</div>
|
||||
<div class="flex max-w-prose h-[20dvh] justify-center place-items-center">
|
||||
<button id="minirt-start-button" class="flex p-4 bg-neutral-100/50 place-items-center rounded-md">
|
||||
Start Raytracer
|
||||
</button>
|
||||
<div>
|
||||
<div id="minirt-canvas-background" style="display: none" class="minirt-canvas-background">
|
||||
<button id="canvas-close-btn" class="absolute top-[16px] right-[16px] text-white">Close</button>
|
||||
<div id="top_bar">
|
||||
<div id="status">Loading</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="/js/minirt.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -22,7 +22,8 @@
|
||||
<h2 class="text-4xl font-bold text-gray-800">The Shell</h2>
|
||||
<div class="space-y-2">
|
||||
<p class="leading-relaxed text-gray-700 max-w-prose">
|
||||
The minishell project is part of the common core curriculum at ecole42 and
|
||||
The minishell project is part of the common core curriculum at
|
||||
<a class="underline text-blue-700 hover:text-blue-900" href="https://42vienna.com">ecole42</a> and
|
||||
is seen as a milestone and one of the biggest jumps in complexity on the way to completing the cursus.
|
||||
</p>
|
||||
<p class="leading-relaxed text-gray-700 max-w-prose">
|
||||
@ -37,6 +38,8 @@
|
||||
<li>Command execution</li>
|
||||
<li>File Descriptor redirection</li>
|
||||
<li>Pipe Operators</li>
|
||||
<li>Environment Variables</li>
|
||||
<li>Builtin functions (cd, export, exit etc.)</li>
|
||||
<li>Heredoc</li>
|
||||
<li>Logical AND ( && )</li>
|
||||
<li>Logical OR ( || )</li>
|
||||
@ -62,8 +65,8 @@
|
||||
</p>
|
||||
<p class="leading-relaxed text-gray-700 mb-4 max-w-prose">
|
||||
But, out of cursiousity, we decided to recreate the readline function, removing the dependecy and leaks from our project,
|
||||
and learing a lot on the way.<br>
|
||||
In my opinion, this is arguably the most interesting part of our implementation, and I very much enjoyed it!
|
||||
and leanring a lot along the way.<br>
|
||||
In my opinion, this is one of the more interesting part of our implementation, and I very much enjoyed it!
|
||||
</p>
|
||||
<p class="leading-relaxed text-gray-700 mb-4 max-w-prose">
|
||||
This project was a team effort, and big thanks go out to my team partner<br>and good friend,
|
||||
@ -73,7 +76,14 @@
|
||||
<p class="leading-relaxed text-gray-700 mb-4 max-w-prose">
|
||||
The source code for the project can be seen on my
|
||||
<a class="underline text-blue-700 hover:text-blue-900" href="https://git.victorvobis.org/minishell">git server</a> and
|
||||
I have also provided a live version of the shell found below.
|
||||
I have also provided a live version of the shell found below.<br/>
|
||||
Please keep in mind, this is barely a prototype, and serves more as a proof of concept, than a fully implemented shell.
|
||||
</p>
|
||||
<p class="leading-relaxed text-gray-700 mb-4 max-w-prose">
|
||||
Credits and many thanks to
|
||||
<a class="underline text-blue-700 hover:text-blue-900" href="https://github.com/tsl0922/ttyd">ttyd</a>
|
||||
for providing the web integeration!<br/>
|
||||
Have fun!
|
||||
</p>
|
||||
<div id="shell-container" class="flex max-w-[800px] min-h-[600px] bg-gray-800 justify-center place-items-center">
|
||||
<button id="shell-start-button" class="flex p-4 bg-neutral-100/50 place-items-center rounded-md">
|
||||
@ -81,28 +91,14 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<p class="leading-relaxed text-gray-700 mb-4">
|
||||
After trying out the shell, feel free to check out my other projects!
|
||||
</p>
|
||||
<a class="underline text-blue-700 hover:text-blue-900" href="/html/minirt.html">Next Project...</a>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<p class="leading-relaxed text-gray-700 mb-4">
|
||||
After trying out the shell, feel free to check out my other projects!
|
||||
</p>
|
||||
<a id="next-project-a" class="underline text-blue-700 hover:text-blue-900" href="/html/minirt.html">Next Project...</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const config = {
|
||||
BASE_URL: 'http://localhost:5080/',
|
||||
};
|
||||
const shell_button = document.getElementById('shell-start-button');
|
||||
shell_button.addEventListener('click', function() {
|
||||
const shell_container = document.getElementById('shell-container');
|
||||
const shell_frame = document.createElement('iframe');
|
||||
shell_frame.height = '600';
|
||||
shell_frame.width = '800';
|
||||
shell_frame.src = config.BASE_URL + 'minishell/vnc';
|
||||
shell_container.appendChild(shell_frame);
|
||||
shell_button.style = 'display: none';
|
||||
});
|
||||
</script>
|
||||
<script type="module" src="/js/minishell.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
content: ["./*.html"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
155
nginx/site/js/minirt.js
Normal file
155
nginx/site/js/minirt.js
Normal file
@ -0,0 +1,155 @@
|
||||
//
|
||||
// !!! DISCLAIMER !!!
|
||||
// This is the default template that comes with noVNC, all credit goes to them
|
||||
//
|
||||
|
||||
import { config } from '/config.js';
|
||||
import RFB from '/vnc/core/rfb.js';
|
||||
|
||||
// RFB holds the API to connect and communicate with a VNC server
|
||||
|
||||
function closeMinirtFrame() {
|
||||
const screen = document.getElementById('screen');
|
||||
if (screen)
|
||||
screen.remove();
|
||||
const canvas_background = document.getElementById('minirt-canvas-background');
|
||||
canvas_background.style = 'display: none';
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.key === 'Escape') {
|
||||
closeMinirtFrame();
|
||||
}
|
||||
});
|
||||
|
||||
const get_passwd = document.getElementById('minirt-password-btn');
|
||||
get_passwd.addEventListener('click', function() {
|
||||
try {
|
||||
fetch(config.BASE_URL + 'minirt/password')
|
||||
.then(resp => {
|
||||
if (!resp.ok) {
|
||||
throw new Error("Failed to fetch password");
|
||||
}
|
||||
return resp.json();
|
||||
})
|
||||
.then(data => {
|
||||
const passwd_display = document.getElementById('minirt-password-display');
|
||||
passwd_display.textContent = `Password: ${data.password}`;
|
||||
});
|
||||
} catch (c) {
|
||||
console.error(e);
|
||||
}
|
||||
})
|
||||
|
||||
const close_button = document.getElementById('canvas-close-btn');
|
||||
close_button.addEventListener('click', closeMinirtFrame);
|
||||
|
||||
|
||||
const minirt_button = document.getElementById('minirt-start-button');
|
||||
minirt_button.addEventListener('click', function() {
|
||||
// const url = config.BASE_URL + 'minirt/vnc';
|
||||
const canvas_background = document.getElementById('minirt-canvas-background');
|
||||
canvas_background.style = '';
|
||||
|
||||
const screen = document.createElement('div');
|
||||
screen.id = 'screen';
|
||||
canvas_background.appendChild(screen);
|
||||
|
||||
|
||||
let rfb;
|
||||
let desktopName;
|
||||
|
||||
// When this function is called we have
|
||||
// successfully connected to a server
|
||||
function connectedToServer(e) {
|
||||
status("Connected to " + desktopName);
|
||||
}
|
||||
|
||||
// This function is called when we are disconnected
|
||||
function disconnectedFromServer(e) {
|
||||
if (e.detail.clean) {
|
||||
status("Disconnected");
|
||||
} else {
|
||||
status("Something went wrong, connection is closed");
|
||||
}
|
||||
}
|
||||
|
||||
// When this function is called, the server requires
|
||||
// credentials to authenticate
|
||||
function credentialsAreRequired(e) {
|
||||
const password = prompt("Password required:");
|
||||
if (password)
|
||||
rfb.sendCredentials({ password: password });
|
||||
}
|
||||
|
||||
// When this function is called we have received
|
||||
// a desktop name from the server
|
||||
function updateDesktopName(e) {
|
||||
desktopName = e.detail.name;
|
||||
}
|
||||
|
||||
// Show a status text in the top bar
|
||||
function status(text) {
|
||||
document.getElementById('status').textContent = text;
|
||||
}
|
||||
|
||||
// This function extracts the value of one variable from the
|
||||
// query string. If the variable isn't defined in the URL
|
||||
// it returns the default value instead.
|
||||
function readQueryVariable(name, defaultValue) {
|
||||
// A URL with a query parameter can look like this:
|
||||
// https://www.example.com?myqueryparam=myvalue
|
||||
//
|
||||
// Note that we use location.href instead of location.search
|
||||
// because Firefox < 53 has a bug w.r.t location.search
|
||||
const re = new RegExp('.*[?&]' + name + '=([^&#]*)'),
|
||||
match = document.location.href.match(re);
|
||||
|
||||
if (match) {
|
||||
// We have to decode the URL since want the cleartext value
|
||||
return decodeURIComponent(match[1]);
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// Read parameters specified in the URL query string
|
||||
// By default, use the host and port of server that served this file
|
||||
const host = readQueryVariable('host', window.location.hostname);
|
||||
let port = readQueryVariable('port', window.location.port);
|
||||
const password = readQueryVariable('password');
|
||||
const path = readQueryVariable('path', 'websockify');
|
||||
|
||||
// | | | | | |
|
||||
// | | | Connect | | |
|
||||
// v v v v v v
|
||||
|
||||
status("Connecting");
|
||||
|
||||
// Build the websocket URL used to connect
|
||||
let url;
|
||||
if (window.location.protocol === "https:") {
|
||||
url = 'wss';
|
||||
} else {
|
||||
url = 'ws';
|
||||
}
|
||||
url += '://' + host;
|
||||
if(port) {
|
||||
url += ':' + port;
|
||||
}
|
||||
url += '/' + path;
|
||||
|
||||
// Creating a new RFB object will start a new connection
|
||||
rfb = new RFB(screen, url,
|
||||
{ credentials: { password: password } });
|
||||
|
||||
// Add listeners to important events from the RFB module
|
||||
rfb.addEventListener("connect", connectedToServer);
|
||||
rfb.addEventListener("disconnect", disconnectedFromServer);
|
||||
rfb.addEventListener("credentialsrequired", credentialsAreRequired);
|
||||
rfb.addEventListener("desktopname", updateDesktopName);
|
||||
|
||||
// Set parameters that can be changed on an active connection
|
||||
rfb.viewOnly = readQueryVariable('view_only', false);
|
||||
rfb.scaleViewport = readQueryVariable('scale', false);
|
||||
});
|
||||
19
nginx/site/js/minishell.js
Normal file
19
nginx/site/js/minishell.js
Normal file
@ -0,0 +1,19 @@
|
||||
import { config } from '/config.js';
|
||||
|
||||
const shell_button = document.getElementById('shell-start-button');
|
||||
shell_button.addEventListener('click', function() {
|
||||
const shell_container = document.getElementById('shell-container');
|
||||
const shell_frame = document.createElement('iframe');
|
||||
shell_frame.id = 'minishell-iframe';
|
||||
shell_frame.height = '600';
|
||||
shell_frame.width = '800';
|
||||
shell_frame.src = config.BASE_URL + 'minishell/vnc';
|
||||
shell_container.appendChild(shell_frame);
|
||||
shell_button.style = 'display: none';
|
||||
});
|
||||
|
||||
const next_project_a = document.getElementById('next-project-a');
|
||||
next_project_a.addEventListener('click', function() {
|
||||
const shell_frame = document.getElementById('minishell-iframe');
|
||||
shell_frame.remove();
|
||||
});
|
||||
1
nginx/site/json/password.json
Normal file
1
nginx/site/json/password.json
Normal file
@ -0,0 +1 @@
|
||||
{ "password": "1312" }
|
||||
9
nginx/site/tailwind.config.js
Normal file
9
nginx/site/tailwind.config.js
Normal file
@ -0,0 +1,9 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./html/*.html"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user