Initial attempt
|
|
@ -0,0 +1,229 @@
|
|||
* { margin: 0; padding: 0 }
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
iframe {
|
||||
display: block !important;
|
||||
background-color: #fff;
|
||||
height: calc(100vh - 4rem);
|
||||
top: var(--loadProgress);
|
||||
position: absolute;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
/* The bed of the Machine */
|
||||
|
||||
.machine {
|
||||
background: url('/images/Metal Panel.svg');
|
||||
background-repeat: repeat-x;
|
||||
bottom: 0;
|
||||
height: 4rem;
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
z-index: 9000;
|
||||
}
|
||||
|
||||
/* Labels */
|
||||
|
||||
label {
|
||||
background-color: #202123;
|
||||
text-shadow: 1px -1px 0px #42464dFF, -1px 1px 0px #ffffff1A;
|
||||
color: #eeeeee;
|
||||
display: block;
|
||||
font: 0.625rem 'Arial Rounded MT Bold';
|
||||
padding: 0.0625rem 0.3125rem;
|
||||
text-transform: uppercase;
|
||||
transform: rotate(-5deg);
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
/* The URL grater and indicators */
|
||||
|
||||
.link-grater {
|
||||
position: absolute;
|
||||
left: 4rem;
|
||||
top: 0;
|
||||
|
||||
.grater-bed {
|
||||
background: url('/images/Grater Bed.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-position: bottom;
|
||||
position: absolute;
|
||||
height: 4rem;
|
||||
top: -4rem;
|
||||
width: 8.5rem;
|
||||
|
||||
&::before {
|
||||
background: url('/images/Sausage.svg');
|
||||
background-repeat: no-repeat;
|
||||
content: ' ';
|
||||
display: block;
|
||||
height: 3em;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
transition: all 0.5s;
|
||||
width: 8.125em;
|
||||
}
|
||||
&.drag-over::before {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.grater-blade {
|
||||
background: url('/images/Grater Blade.svg');
|
||||
height: 0.625rem;
|
||||
left: var(--graterTravel);
|
||||
position: absolute;
|
||||
bottom: 0.625rem;
|
||||
width: 3.4375rem;
|
||||
z-index: 10;
|
||||
}
|
||||
.lever {
|
||||
bottom: -2.75rem;
|
||||
height: 3.4375rem;
|
||||
position: absolute;
|
||||
left: 12rem;
|
||||
width: 6.125rem;
|
||||
|
||||
.stem {
|
||||
background: url('/images/Lever Handle.svg');
|
||||
height: 3.4375rem;
|
||||
position: absolute;
|
||||
width: 3.0625rem;
|
||||
transform: rotate(var(--leverRotation));
|
||||
transform-origin: calc(100% - 3px) calc(100% - 2px);
|
||||
|
||||
.handle {
|
||||
cursor: pointer;
|
||||
height: 2.75rem;
|
||||
position: absolute;
|
||||
left: -0.75rem;
|
||||
top: -1rem;
|
||||
width: 2.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
background: url('/images/Lever Back.svg');
|
||||
bottom: -0.5rem;
|
||||
content: '';
|
||||
height: 1.375rem;
|
||||
left: 2.25rem;
|
||||
position: absolute;
|
||||
width: 1.375rem;
|
||||
}
|
||||
|
||||
&::after {
|
||||
background: url('/images/Lever Front.svg');
|
||||
bottom: -0.5rem;
|
||||
content: '';
|
||||
height: 1.0625rem;
|
||||
left: 2.40625rem;
|
||||
position: absolute;
|
||||
width: 1.0625rem;
|
||||
}
|
||||
}
|
||||
|
||||
.indicator-leds {
|
||||
position: absolute;
|
||||
width: max-content;
|
||||
|
||||
bottom: -3.3125rem;
|
||||
left: 10rem;
|
||||
|
||||
.indicator {
|
||||
display: inline-block;
|
||||
height: 0.6875rem;
|
||||
width: 0.6875rem;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
position: absolute;
|
||||
bottom: -3rem;
|
||||
left: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.ready-to-grate {
|
||||
background: url('/images/Red Unlit Light.svg');
|
||||
}
|
||||
.ready-to-load {
|
||||
background: url('/images/Green Unlit Light.svg');
|
||||
}
|
||||
[data-current-state="readyToGrate"] .ready-to-grate {
|
||||
background: url('/images/Red Lit Light.svg');
|
||||
}
|
||||
[data-current-state="readyToLoad"] .ready-to-load {
|
||||
background: url('/images/Green Lit Light.svg');
|
||||
}
|
||||
|
||||
/* The Link Loader Wheel and Chain Mechanism */
|
||||
|
||||
.chain {
|
||||
background: url('/images/Chain Link.svg');
|
||||
background-position-y: var(--chainOffset);
|
||||
background-repeat: repeat-y;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
right: 1rem;
|
||||
top: 0;
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
.url-loader {
|
||||
position: absolute;
|
||||
right: 1.5rem;
|
||||
top: -3rem;
|
||||
|
||||
.wheel {
|
||||
height: 6rem;
|
||||
width: 6rem;
|
||||
|
||||
.body {
|
||||
background: url('/images/Wheel.svg');
|
||||
height: 6rem;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
transform: rotate(var(--wheelRotation));
|
||||
width: 6rem;
|
||||
}
|
||||
|
||||
.handle {
|
||||
cursor: pointer;
|
||||
height: 2.75rem;
|
||||
position: absolute;
|
||||
right: -1.125rem;
|
||||
top: 1.625rem;
|
||||
width: 2.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: -4rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make a Sausage */
|
||||
.sausage {
|
||||
background: url('/images/Sausage.svg');
|
||||
background-position: top;
|
||||
background-repeat: no-repeat;
|
||||
color: #fff;
|
||||
display: block;
|
||||
font: 0.625rem 'Arial Rounded MT Bold';
|
||||
height: calc(3rem - var(--grateLevel));
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: var(--grateLevel);
|
||||
left: 0;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
width: 8.125rem;
|
||||
z-index: 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/* TEAM */
|
||||
Maintainer: Ruben Beltran del Rio
|
||||
Site: contact@r.bdr.sh
|
||||
Mastodon: https://friendship.quest/@ruben
|
||||
From: Berlin, Germany
|
||||
|
||||
/* SITE */
|
||||
Language: English
|
||||
|
|
@ -0,0 +1 @@
|
|||
<svg width="8" xmlns="http://www.w3.org/2000/svg" height="12" id="screenshot-d28dab85-57b8-80fc-8007-7280f8b3c887" viewBox="0 0 8 12" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1"><g id="shape-d28dab85-57b8-80fc-8007-7280f8b3c887"><defs><clipPath id="frame-clip-d28dab85-57b8-80fc-8007-7280f8b3c887-render-11" class="frame-clip frame-clip-def"><rect rx="0" ry="0" x="0" y="0" width="8" height="12" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)"/></clipPath></defs><g class="frame-container-wrapper"><g class="frame-container-blur"><g class="frame-container-shadows"><g clip-path="url(#frame-clip-d28dab85-57b8-80fc-8007-7280f8b3c887-render-11)" fill="none"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7280f8b3c887"><rect rx="0" ry="0" x="0" y="0" width="8" height="12" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" class="frame-background"/></g><g class="frame-children"><g id="shape-d28dab85-57b8-80fc-8007-72810e62b280"><defs><filter id="filter-render-12" x="0" y="0" width="1" height="1" filterUnits="objectBoundingBox" color-interpolation-filters="sRGB"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/><feOffset dx="0" dy="2"/><feGaussianBlur stdDeviation="0"/><feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/><feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.2 0"/><feBlend mode="normal" in2="shape" result="filter_d28dab85-57b8-80fc-8007-728098e4ea0a"/><feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/><feOffset dx="0" dy="-2"/><feGaussianBlur stdDeviation="0"/><feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/><feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"/><feBlend mode="normal" in2="filter_d28dab85-57b8-80fc-8007-728098e4ea0a" result="filter_d28dab85-57b8-80fc-8007-7280c08c96a4"/></filter><filter id="filter-shadow-render-12" x="0" y="0" width="1" height="1" filterUnits="objectBoundingBox" color-interpolation-filters="sRGB"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/><feOffset dx="0" dy="2"/><feGaussianBlur stdDeviation="0"/><feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/><feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.2 0"/><feBlend mode="normal" in2="shape" result="filter_d28dab85-57b8-80fc-8007-728098e4ea0a"/><feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/><feOffset dx="0" dy="-2"/><feGaussianBlur stdDeviation="0"/><feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/><feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0"/><feBlend mode="normal" in2="filter_d28dab85-57b8-80fc-8007-728098e4ea0a" result="filter_d28dab85-57b8-80fc-8007-7280c08c96a4"/></filter></defs><g class="fills" id="fills-d28dab85-57b8-80fc-8007-72810e62b280"><path d="M0,4C0,1.7923583984375,1.7923583984375,0,4,0L4,0C6.2076416015625,0,8,1.7923583984375,8,4L8,8C8,10.2076416015625,6.2076416015625,12,4,12L4,12C1.7923583984375,12,0,10.2076416015625,0,8L0,4M2,4L2,8C2,9.10382080078125,2.89617919921875,10,4,10L4,10C5.10382080078125,10,6,9.10382080078125,6,8L6,4C6,2.89617919921875,5.10382080078125,2,4,2L4,2C2.89617919921875,2,2,2.89617919921875,2,4" filter="url(#filter-render-12)" style="fill: rgb(202, 211, 237); fill-opacity: 1;"/></g></g></g></g></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg width="136" xmlns="http://www.w3.org/2000/svg" height="17" id="screenshot-d28dab85-57b8-80fc-8007-7293859b0261" viewBox="0 0 136 17" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1"><g id="shape-d28dab85-57b8-80fc-8007-7293859b0261"><defs><clipPath id="frame-clip-d28dab85-57b8-80fc-8007-7293859b0261-render-1" class="frame-clip frame-clip-def"><rect rx="0" ry="0" x="0" y="0" width="136" height="17" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)"/></clipPath></defs><g class="frame-container-wrapper"><g class="frame-container-blur"><g class="frame-container-shadows"><g clip-path="url(#frame-clip-d28dab85-57b8-80fc-8007-7293859b0261-render-1)" fill="none"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7293859b0261"><rect rx="0" ry="0" x="0" y="0" width="136" height="17" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" class="frame-background"/></g><g class="frame-children"><g id="shape-d28dab85-57b8-80fc-8007-7293859b6ed6"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7293859b6ed6"><path d="M2,0 h126 a2,2 0 0 1 2,2 v15 a0,0 0 0 1 0,0 h-128 a2,2 0 0 1 -2,-2 v-13 a2,2 0 0 1 2,-2 z" x="0" y="0" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" width="130" height="17" style="fill: rgb(160, 143, 134); fill-opacity: 1;"/></g></g><g id="shape-d28dab85-57b8-80fc-8007-7293859b6ed7"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7293859b6ed7"><path d="M130,2 h4 a2,2 0 0 1 2,2 v11 a2,2 0 0 1 -2,2 h-4 a0,0 0 0 1 0,0 v-15 a0,0 0 0 1 0,0 z" x="130" y="2" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" width="6" height="15" style="fill: rgb(148, 133, 123); fill-opacity: 1;"/></g></g><g id="shape-d28dab85-57b8-80fc-8007-7293859b6ed8" style="opacity: 0.1;"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7293859b6ed8"><path d="M2,0 h126 a2,2 0 0 1 2,2 v0 a0,0 0 0 1 0,0 h-130 a0,0 0 0 1 0,0 v0 a2,2 0 0 1 2,-2 z" x="0" y="0" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" width="130" height="2" style="fill: rgb(255, 255, 255); fill-opacity: 1;"/></g></g></g></g></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg width="55" xmlns="http://www.w3.org/2000/svg" height="10" id="screenshot-d28dab85-57b8-80fc-8007-729346f2c37f" viewBox="0 0 55 10" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1"><g id="shape-d28dab85-57b8-80fc-8007-729346f2c37f"><defs><clipPath id="frame-clip-d28dab85-57b8-80fc-8007-729346f2c37f-render-17" class="frame-clip frame-clip-def"><rect rx="0" ry="0" x="0" y="0" width="55" height="10" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)"/></clipPath></defs><g class="frame-container-wrapper"><g class="frame-container-blur"><g class="frame-container-shadows"><g clip-path="url(#frame-clip-d28dab85-57b8-80fc-8007-729346f2c37f-render-17)" fill="none"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-729346f2c37f"><rect rx="0" ry="0" x="0" y="0" width="55" height="10" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" class="frame-background"/></g><g class="frame-children"><g id="shape-d28dab85-57b8-80fc-8007-729346f2c389" style="opacity: 0.1;"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-729346f2c389"><path d="M2,3 h126 a2,2 0 0 1 2,2 v0 a0,0 0 0 1 0,0 h-130 a0,0 0 0 1 0,0 v0 a2,2 0 0 1 2,-2 z" x="0" y="3" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" width="130" height="2" style="fill: rgb(255, 255, 255); fill-opacity: 1;"/></g></g><g id="shape-d28dab85-57b8-80fc-8007-729346f2c38a"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-729346f2c38a"><rect rx="2" ry="2" x="0" y="0" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" width="55" height="10" style="fill: rgb(160, 143, 134); fill-opacity: 1;"/></g></g><g id="shape-d28dab85-57b8-80fc-8007-729346f2c38b" style="opacity: 0.1;"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-729346f2c38b"><path d="M2,0 h51 a2,2 0 0 1 2,2 v0 a0,0 0 0 1 0,0 h-55 a0,0 0 0 1 0,0 v0 a2,2 0 0 1 2,-2 z" x="0" y="0" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" width="55" height="2" style="fill: rgb(255, 255, 255); fill-opacity: 1;"/></g></g><g id="shape-d28dab85-57b8-80fc-8007-729346f2c38c" style="opacity: 0.05;"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-729346f2c38c"><path d="M0,8 h55 a0,0 0 0 1 0,0 v0 a2,2 0 0 1 -2,2 h-51 a2,2 0 0 1 -2,-2 v0 a0,0 0 0 1 0,0 z" x="0" y="8" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" width="55" height="2" style="fill: rgb(0, 0, 0); fill-opacity: 1;"/></g></g></g></g></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg width="22" xmlns="http://www.w3.org/2000/svg" height="22" id="screenshot-d28dab85-57b8-80fc-8007-7296918de646" viewBox="0 0 22 22" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1"><g id="shape-d28dab85-57b8-80fc-8007-7296918de646"><defs><clipPath id="frame-clip-d28dab85-57b8-80fc-8007-7296918de646-render-34" class="frame-clip frame-clip-def"><rect rx="0" ry="0" x="0" y="0" width="22" height="22" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)"/></clipPath></defs><g class="frame-container-wrapper"><g class="frame-container-blur"><g class="frame-container-shadows"><g clip-path="url(#frame-clip-d28dab85-57b8-80fc-8007-7296918de646-render-34)" fill="none"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7296918de646"><rect rx="0" ry="0" x="0" y="0" width="22" height="22" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" class="frame-background"/></g><g class="frame-children"><g id="shape-d28dab85-57b8-80fc-8007-7296918e1ec4"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7296918e1ec4"><ellipse cx="11" cy="11" rx="11" ry="11" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" style="fill: rgb(41, 35, 25); fill-opacity: 1;"/></g></g><g id="shape-d28dab85-57b8-80fc-8007-7296918e67ba"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7296918e67ba"><path d="M8.342041015625,1.9999923706054688L8.939697265625,3.2817306518554688"/></g><g id="strokes-d5fe543c-f897-80e6-8007-72977611550c-d28dab85-57b8-80fc-8007-7296918e67ba" class="strokes"><g class="stroke-shape"><path d="M8.342041015625,1.9999923706054688L8.939697265625,3.2817306518554688" style="fill: none; stroke-width: 2; stroke: rgb(255, 255, 255); stroke-opacity: 0.05; stroke-linecap: round;"/></g></g></g></g></g></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg width="17" xmlns="http://www.w3.org/2000/svg" height="17" id="screenshot-d28dab85-57b8-80fc-8007-7296fe542348" viewBox="0 0 17 17" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1"><g id="shape-d28dab85-57b8-80fc-8007-7296fe542348"><defs><clipPath id="frame-clip-d28dab85-57b8-80fc-8007-7296fe542348-render-22" class="frame-clip frame-clip-def"><rect rx="0" ry="0" x="0" y="0" width="17" height="17" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)"/></clipPath></defs><g class="frame-container-wrapper"><g class="frame-container-blur"><g class="frame-container-shadows"><g clip-path="url(#frame-clip-d28dab85-57b8-80fc-8007-7296fe542348-render-22)" fill="none"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7296fe542348"><rect rx="0" ry="0" x="0" y="0" width="17" height="17" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" class="frame-background"/></g><g class="frame-children"><g id="shape-d28dab85-57b8-80fc-8007-7296fe5448f2"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7296fe5448f2"><ellipse cx="8.5" cy="8.5" rx="8.5" ry="8.5" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" style="fill: rgb(48, 38, 21); fill-opacity: 1;"/></g></g><g id="shape-d28dab85-57b8-80fc-8007-7296fe5448f3" style="opacity: 0.1;"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7296fe5448f3"><path d="M6,1.4444503784179688C6,1.4444503784179688,8,0.44445037841796875,11,1.4444503784179688"/></g><g id="strokes-d5fe543c-f897-80e6-8007-729776079807-d28dab85-57b8-80fc-8007-7296fe5448f3" class="strokes"><g class="stroke-shape"><path d="M6,1.4444503784179688C6,1.4444503784179688,8,0.44445037841796875,11,1.4444503784179688" style="fill: none; stroke-width: 1; stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-linecap: round;"/></g></g></g></g></g></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg width="49" xmlns="http://www.w3.org/2000/svg" height="55" id="screenshot-d28dab85-57b8-80fc-8007-7296675b78ed" viewBox="0 0 49 55" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1"><g id="shape-d28dab85-57b8-80fc-8007-7296675b78ed"><defs><clipPath id="frame-clip-d28dab85-57b8-80fc-8007-7296675b78ed-render-5" class="frame-clip frame-clip-def"><rect rx="0" ry="0" x="0" y="0" width="49" height="55" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)"/></clipPath></defs><g class="frame-container-wrapper"><g class="frame-container-blur"><g class="frame-container-shadows"><g clip-path="url(#frame-clip-d28dab85-57b8-80fc-8007-7296675b78ed-render-5)" fill="none"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7296675b78ed"><rect rx="0" ry="0" x="0" y="0" width="49" height="55" transform="matrix(1.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000)" class="frame-background"/></g><g class="frame-children"><g id="shape-d28dab85-57b8-80fc-8007-7296675ba9b6"><defs><radialGradient id="fill-color-gradient-render-6-0" cx="0.16799355935575022" cy="0.7100719012795145" r="0.4407795129732544" gradientTransform="matrix(-0.657762, 0.753226, -0.753226, -0.657762, 0.813338, 1.050593)"><stop offset="0.64" stop-color="#000000" stop-opacity="0.5"/><stop offset="1" stop-color="#000000" stop-opacity="0"/></radialGradient><pattern patternUnits="userSpaceOnUse" x="27.948235617059424" y="10.905810760497303" width="5.000000000000057" height="48" id="fill-0-render-6"><g><rect width="5.000000000000057" height="48" style="fill: rgb(30, 23, 13); fill-opacity: 1;"/><rect width="5.000000000000057" height="48" style="fill: url("#fill-color-gradient-render-6-0");"/></g></pattern></defs><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7296675ba9b6"><rect rx="0" ry="0" x="27.948235617059424" y="10.905810760497303" transform="matrix(0.761946, -0.647641, 0.647641, 0.761946, -15.358098, 28.029000)" width="5.000000000000057" height="48" fill="url(#fill-0-render-6)"/></g></g><g id="shape-d28dab85-57b8-80fc-8007-7296675ba9b7" style="opacity: 0.1;"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7296675ba9b7"><rect rx="0" ry="0" x="31.426007460126357" y="9.610494375291125" transform="matrix(0.761946, -0.647641, 0.647641, 0.761946, -14.167826, 28.676641)" width="0.996673460154625" height="48.00006918759399" style="fill: rgb(255, 255, 255); fill-opacity: 1;"/></g></g><g id="shape-d28dab85-57b8-80fc-8007-7296675ba9b9" style="opacity: 0.1;"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7296675ba9b9"><path d="M47,52.00001525878906C47,52.00001525878906,49,51.00001525878906,52,52.00001525878906"/></g><g id="strokes-d5fe543c-f897-80e6-8007-729775fdf08f-d28dab85-57b8-80fc-8007-7296675ba9b9" class="strokes"><g class="stroke-shape"><path d="M47,52.00001525878906C47,52.00001525878906,49,51.00001525878906,52,52.00001525878906" style="fill: none; stroke-width: 1; stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-linecap: round;"/></g></g></g><g id="shape-d28dab85-57b8-80fc-8007-7296675ba9ba"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7296675ba9ba"><path d="M47.201171875,47.85914611816406L47.798828125,49.14088439941406"/></g><g id="strokes-d5fe543c-f897-80e6-8007-729775fefb49-d28dab85-57b8-80fc-8007-7296675ba9ba" class="strokes"><g class="stroke-shape"><path d="M47.201171875,47.85914611816406L47.798828125,49.14088439941406" style="fill: none; stroke-width: 2; stroke: rgb(255, 255, 255); stroke-opacity: 0.05; stroke-linecap: round;"/></g></g></g><g id="shape-d28dab85-57b8-80fc-8007-7296675ba9bb"><g class="fills" id="fills-d28dab85-57b8-80fc-8007-7296675ba9bb"><path d="M1.295166015625,7.3522796630859375C0.580322265625,6.5111846923828125,0.682861328125,5.247966766357422,1.52398681640625,4.533123016357422L5.333984375,1.2951774597167969C6.175048828125,0.5803642272949219,7.43829345703125,0.6828727722167969,8.153076171875,1.5239677429199219L17.10491943359375,13.601425170898438C17.81976318359375,14.442550659179688,17.71722412109375,15.705764770507812,16.8760986328125,16.420578002929688L14.59014892578125,18.363357543945312C13.7490234375,19.078201293945312,12.48583984375,18.975662231445312,11.77099609375,18.134536743164062L1.295166015625,7.3522796630859375" style="fill: rgb(48, 38, 21); fill-opacity: 1;"/></g></g></g></g></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
|
@ -0,0 +1,48 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="author" content="Rubén Beltrán del Río">
|
||||
<meta name="description" content="{{ description }}">
|
||||
<meta name="fediverse:creator" content="@ruben@friendship.quest" />
|
||||
|
||||
<title>Internet Machine.</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/style.css">
|
||||
<link rel="author" href="humans.txt">
|
||||
|
||||
<script type="module" src="/js/machine.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<main class="web-content">
|
||||
</main>
|
||||
<nav class="machine">
|
||||
<section class="link-grater">
|
||||
<article class="grater-bed">
|
||||
<article class="grater-blade"></article>
|
||||
</article>
|
||||
<section class="indicator-leds">
|
||||
<article class="indicator ready-to-grate"></article>
|
||||
<article class="indicator ready-to-load"></article>
|
||||
</section>
|
||||
<article class="lever">
|
||||
<article class="stem">
|
||||
<article class="handle"></article>
|
||||
</article>
|
||||
</article>
|
||||
<label>Link Grater</label>
|
||||
</section>
|
||||
<section class="url-loader">
|
||||
<article class="chain"></article>
|
||||
<article class="wheel">
|
||||
<article class="body">
|
||||
<article class="handle"></article>
|
||||
</article>
|
||||
</article>
|
||||
<label>URL Loader</label>
|
||||
</section
|
||||
</nav>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,351 @@
|
|||
// Constants ///////////////////////////////////////////////////////////////////
|
||||
const kDimensions = {
|
||||
wheelSize: 96,
|
||||
leverWidth: 98,
|
||||
sausageHeight: 48,
|
||||
};
|
||||
const kState = {
|
||||
waiting: 'waiting',
|
||||
readyToGrate: 'readyToGrate',
|
||||
readyToLoad: 'readyToLoad'
|
||||
};
|
||||
const kAction = {
|
||||
completeLoading: Symbol('completeLoading'),
|
||||
startPullingLever: Symbol('startPullingLever'),
|
||||
stopPullingLever: Symbol('stopPullingLever'),
|
||||
pullLever: Symbol('pullLever'),
|
||||
startTurningWheel: Symbol('startTurningWheel'),
|
||||
stopTurningWheel: Symbol('stopTurningWheel'),
|
||||
turnWheel: Symbol('turnWheel'),
|
||||
setIsWaitingForFrame: Symbol('setIsWaitingForFrame'),
|
||||
createSausage: Symbol('createSausage'),
|
||||
completeGrating: Symbol('completeGrating'),
|
||||
};
|
||||
const kRotationDirection = {
|
||||
clockwise: Symbol('clockwise'),
|
||||
counterClockwise: Symbol('counterClockwise'),
|
||||
};
|
||||
const kPullDirection = {
|
||||
right: Symbol('right'),
|
||||
left: Symbol('left'),
|
||||
};
|
||||
|
||||
// Configuration ///////////////////////////////////////////////////////////////
|
||||
const configuration = {
|
||||
wheelStrength: 1,
|
||||
maxLoad: 100,
|
||||
leverTravel: 80.72,
|
||||
graterTravel: 69,
|
||||
chainSpeed: 0.5,
|
||||
grateStrength: 0.01,
|
||||
defaultUrl: '/example.html'
|
||||
};
|
||||
|
||||
// App State ///////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* The main app state
|
||||
*/
|
||||
let appState = null;
|
||||
|
||||
/**
|
||||
* Functions to handle side effects
|
||||
*/
|
||||
const middleware = [
|
||||
function completeLoading(state, action) {
|
||||
if (action === kAction.turnWheel && state.currentState === kState.readyToLoad && parseFloat(state.load) >= configuration.maxLoad) {
|
||||
send(kAction.completeLoading);
|
||||
}
|
||||
},
|
||||
function updateIframe(state, action) {
|
||||
if (action === kAction.turnWheel && state.currentState === kState.readyToLoad && parseFloat(state.load) <= configuration.maxLoad) {
|
||||
state.currentIframe?.style.setProperty('--loadProgress', `${100 - state.load}vh`);
|
||||
}
|
||||
},
|
||||
function completeGrating(state, action) {
|
||||
if (action === kAction.pullLever && state.currentState === kState.readyToGrate && parseFloat(state.grateLevel) >= kDimensions.sausageHeight) {
|
||||
removeSausages();
|
||||
const $iframe = loadIframe(state.currentUrl, 0);
|
||||
send(kAction.completeGrating, { iframe: $iframe });
|
||||
}
|
||||
},
|
||||
function createSausageIfWaiting(state, action, data) {
|
||||
if (action === kAction.createSausage && state.currentState === kState.waiting) {
|
||||
createSausage(data.href, data.label);
|
||||
}
|
||||
},
|
||||
function log(state, action, data) {
|
||||
//console.log(state.load);
|
||||
}
|
||||
];
|
||||
|
||||
const $stateContainer = document.querySelector('.machine');
|
||||
const updateState = function updateState(state) {
|
||||
for (const [key, value] of Object.entries(state)) {
|
||||
$stateContainer.style.setProperty(`--${key}`, value);
|
||||
$stateContainer.dataset[key] = value;
|
||||
}
|
||||
appState = state;
|
||||
};
|
||||
|
||||
const reduce = function reduce(stateReference, action, data) {
|
||||
let state = Object.assign({}, stateReference);
|
||||
|
||||
switch (action) {
|
||||
case kAction.turnWheel:
|
||||
state.wheelRotation = `${data.angle}rad`;
|
||||
if (state.currentState === kState.readyToLoad) {
|
||||
const sign = data.direction === kRotationDirection.clockwise ? 1 : -1;
|
||||
const load = Math.max(Math.min(state.load - sign * data.magnitude * configuration.wheelStrength, configuration.maxLoad), 0);
|
||||
state.load = load;
|
||||
if (load < configuration.maxLoad && load > 0) {
|
||||
const chainOffset = parseFloat(state.chainOffset) + sign * data.magnitude * configuration.chainSpeed;
|
||||
state.chainOffset = `${chainOffset}%`;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kAction.pullLever:
|
||||
const diff = Math.abs(state.leverTravel - data.magnitude);
|
||||
state.leverTravel = data.magnitude;
|
||||
const rotation = data.magnitude * configuration.leverTravel / 100;
|
||||
state.leverRotation = `${rotation}deg`
|
||||
const gratingTravel = data.magnitude * configuration.graterTravel / 100;
|
||||
state.graterTravel = `${gratingTravel}px`
|
||||
if (state.currentState === kState.readyToGrate) {
|
||||
const grateLevel = Math.min(parseFloat(state.grateLevel) + diff * configuration.grateStrength, kDimensions.sausageHeight);
|
||||
state.grateLevel = `${grateLevel}px`;
|
||||
}
|
||||
break;
|
||||
case kAction.createSausage:
|
||||
state.currentUrl = data.href;
|
||||
state.grateLevel = '0%';
|
||||
state.currentState = kState.readyToGrate;
|
||||
break;
|
||||
case kAction.startTurningWheel:
|
||||
state.isTurningWheel = true;
|
||||
break;
|
||||
case kAction.stopTurningWheel:
|
||||
state.isTurningWheel = false;
|
||||
break;
|
||||
case kAction.startPullingLever:
|
||||
state.isPullingLever = true;
|
||||
break;
|
||||
case kAction.stopPullingLever:
|
||||
state.isPullingLever = false;
|
||||
break;
|
||||
case kAction.completeLoading:
|
||||
state.currentState = kState.waiting;
|
||||
state.load = 0;
|
||||
break;
|
||||
case kAction.completeGrating:
|
||||
state.currentState = kState.readyToLoad;
|
||||
state.currentIframe = data.iframe;
|
||||
state.grateLevel = '0%';
|
||||
state.load = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
/**
|
||||
* The main mechanism for view changes to trigger updates.
|
||||
* It receives an action and its payload.
|
||||
* It queues the middleware to run after this.
|
||||
*/
|
||||
const send = function send(action, data) {
|
||||
const state = Object.assign({}, appState);
|
||||
for (const m of middleware) {
|
||||
setTimeout(() => m(state, action, data), 0);
|
||||
}
|
||||
const newState = reduce(state, action, data);
|
||||
updateState(newState);
|
||||
};
|
||||
|
||||
// Initializzation /////////////////////////////////////////////////////////////
|
||||
|
||||
const initialize = function initialize() {
|
||||
|
||||
const state = {
|
||||
currentState: kState.waiting,
|
||||
isPullingLever: false,
|
||||
isTurningWheel: false,
|
||||
leverTravel: 0,
|
||||
grateLevel: 0,
|
||||
leverRotation: '0deg',
|
||||
graterTravel: '0rem',
|
||||
wheelRotation: '0deg',
|
||||
chainOffset: '0%',
|
||||
load: 0,
|
||||
};
|
||||
updateState(state);
|
||||
|
||||
// Reset interaction with widgets if we lift a mouse button.
|
||||
document.addEventListener('mouseup', () => {
|
||||
send(kAction.stopTurningWheel)
|
||||
send(kAction.stopPullingLever)
|
||||
});
|
||||
|
||||
// The lever handle initiates interactions with the lever.
|
||||
document.querySelector('.lever .handle')?.addEventListener('mousedown', () => {
|
||||
send(kAction.startPullingLever)
|
||||
});
|
||||
|
||||
// The wheel handle initiates interactions with the wheel.
|
||||
document.querySelector('.wheel .handle')?.addEventListener('mousedown', () => {
|
||||
send(kAction.startTurningWheel)
|
||||
});
|
||||
|
||||
// Rotation is calculated relatively to the whole wheel.
|
||||
// And travel based no the full arc of the lever
|
||||
const $wheel = document.querySelector('.wheel');
|
||||
const $lever = document.querySelector('.lever');
|
||||
document.addEventListener('mousemove', (event) => {
|
||||
if (appState.isTurningWheel && !appState.waitingForFrame) {
|
||||
requestAnimationFrame(() => {
|
||||
const elementPosition = $wheel.getBoundingClientRect();
|
||||
const x = event.clientX - elementPosition.left;
|
||||
const y = event.clientY - elementPosition.top;
|
||||
const angle = angleFromCenter(x, y, kDimensions.wheelSize, kDimensions.wheelSize)
|
||||
const oldAngle = parseFloat(appState.wheelRotation);
|
||||
const { direction, magnitude } = rotationDirection(oldAngle, angle);
|
||||
send(kAction.turnWheel, { angle, direction, magnitude });
|
||||
send(kAction.setIsWaitingForFrame, { state: false })
|
||||
});
|
||||
send(kAction.setIsWaitingForFrame, { state: true })
|
||||
}
|
||||
if (appState.isPullingLever && !appState.waitingForFrame) {
|
||||
requestAnimationFrame(() => {
|
||||
const elementPosition = $lever.getBoundingClientRect();
|
||||
const x = event.clientX - elementPosition.left;
|
||||
const magnitude = Math.max(Math.min(x * 100 / kDimensions.leverWidth, 100), 0);
|
||||
const direction = magnitude >= appState.leverTravel ? kPullDirection.right : kPullDirection.left;
|
||||
send(kAction.pullLever, { magnitude, direction });
|
||||
send(kAction.setIsWaitingForFrame, { state: false })
|
||||
});
|
||||
send(kAction.setIsWaitingForFrame, { state: true })
|
||||
}
|
||||
});
|
||||
|
||||
// The URL Grater is the drop area.
|
||||
const $grater = document.querySelector('.grater-bed');
|
||||
$grater.addEventListener('dragenter', (event) => {
|
||||
event.preventDefault();
|
||||
if (appState.currentState === kState.waiting) {
|
||||
$grater.classList.add('drag-over');
|
||||
}
|
||||
});
|
||||
$grater.addEventListener('dragover', (event) => event.preventDefault());
|
||||
$grater.addEventListener('dragleave', (event) => {
|
||||
if (!$grater.contains(event.relatedTarget)) {
|
||||
$grater.classList.remove('drag-over');
|
||||
}
|
||||
});
|
||||
$grater.addEventListener('drop', (event) => {
|
||||
event.preventDefault();
|
||||
if (appState.currentState !== kState.waiting) {
|
||||
return;
|
||||
}
|
||||
const href = event.dataTransfer.getData('text/uri-list');
|
||||
const label = event.dataTransfer.getData('text/plain');
|
||||
$grater.classList.remove('drag-over');
|
||||
send(kAction.createSausage, { href, label });
|
||||
});
|
||||
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const urlFromQuery = params.get("url");
|
||||
const url = urlFromQuery ?? configuration.defaultUrl;
|
||||
loadIframe(url, 100);
|
||||
};
|
||||
|
||||
// Utility Functions ///////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Calculates the angle of a point (x,y) relative to the center of a square
|
||||
* with dimensions (w, h). The result is in radians.
|
||||
*/
|
||||
const angleFromCenter = function angleFromCenter(x, y, w, h) {
|
||||
const centerX = w / 2;
|
||||
const centerY = h / 2;
|
||||
const dx = x - centerX;
|
||||
const dy = y - centerY;
|
||||
return Math.atan2(dy, dx);
|
||||
};
|
||||
|
||||
/**
|
||||
* Given two angles, calculates the direction of the rotation.
|
||||
*/
|
||||
const rotationDirection = function rotationDirection(angle1, angle2) {
|
||||
let diff = angle2 - angle1;
|
||||
|
||||
if (diff > Math.PI) diff -= 2 * Math.PI;
|
||||
if (diff < -Math.PI) diff += 2 * Math.PI;
|
||||
|
||||
const magnitude = Math.abs(diff);
|
||||
const direction = diff > 0 ? kRotationDirection.counterClockwise : kRotationDirection.clockwise;
|
||||
|
||||
return {
|
||||
direction,
|
||||
magnitude
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads an iframe and appends it into the body.
|
||||
*/
|
||||
const $iframeContainer = document.querySelector('.web-content');
|
||||
const loadIframe = function loadIframe(url, loadProgress) {
|
||||
const $iframe = document.createElement('iframe');
|
||||
$iframe.src = url;
|
||||
$iframe.style.setProperty('--loadProgress', `${100 - loadProgress}vh`);
|
||||
$iframeContainer.appendChild($iframe);
|
||||
|
||||
$iframe.addEventListener('load', () => {
|
||||
const iframeDocument = $iframe.contentDocument;
|
||||
|
||||
iframeDocument.querySelectorAll('a').forEach(($link) => {
|
||||
$link.addEventListener('click', (event) => event.preventDefault());
|
||||
$link.draggable = true;
|
||||
$link.addEventListener('dragstart', (event) => {
|
||||
event.dataTransfer.setData('text/uri-list', $link.href);
|
||||
event.dataTransfer.setData('text/plain', $link.textContent);
|
||||
const ghost = $link.cloneNode(true);
|
||||
ghost.style.background = 'url(\'/images/Sausage.svg\')';
|
||||
ghost.style.backgroundRepeat = 'no-repeat';
|
||||
ghost.style.cursor = 'grabbing';
|
||||
ghost.style.display = 'block';
|
||||
ghost.style.height = '3rem';
|
||||
ghost.style.width = '8.125rem';
|
||||
ghost.style.color = '#fff';
|
||||
ghost.style.textAlign = 'center';
|
||||
ghost.style.fontSize = '0.625rem';
|
||||
ghost.style.fontFamily = 'sans-serif';
|
||||
ghost.style.textTransform = 'uppercase';
|
||||
ghost.style.paddingTop = '1rem';
|
||||
|
||||
document.body.appendChild(ghost);
|
||||
event.dataTransfer.setDragImage(ghost, 10, 10);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return $iframe;
|
||||
};
|
||||
|
||||
const createSausage = function createSausage(href, label) {
|
||||
const $sausage = document.createElement('article');
|
||||
$sausage.classList.add('sausage');
|
||||
$sausage.dataset.href = href;
|
||||
$sausage.innerText = label;
|
||||
const $graterBed = document.querySelector('.grater-bed');
|
||||
$graterBed?.appendChild($sausage);
|
||||
};
|
||||
|
||||
const removeSausages = function removeSausages() {
|
||||
const $graterBed = document.querySelector('.grater-bed');
|
||||
const $existingSausages = $graterBed.querySelectorAll('.sausage');
|
||||
for (const $existingSausage of $existingSausages) {
|
||||
$graterBed?.removeChild($existingSausage);
|
||||
}
|
||||
}
|
||||
|
||||
initialize();
|
||||