aboutsummaryrefslogtreecommitdiff
path: root/services/docker/nginx/sites/www/src
diff options
context:
space:
mode:
Diffstat (limited to 'services/docker/nginx/sites/www/src')
-rw-r--r--services/docker/nginx/sites/www/src/main.ts47
-rw-r--r--services/docker/nginx/sites/www/src/style.css148
2 files changed, 195 insertions, 0 deletions
diff --git a/services/docker/nginx/sites/www/src/main.ts b/services/docker/nginx/sites/www/src/main.ts
new file mode 100644
index 0000000..09e8661
--- /dev/null
+++ b/services/docker/nginx/sites/www/src/main.ts
@@ -0,0 +1,47 @@
+import "./style.css";
+
+class Emotion {
+ static opposite_map = new Map<Emotion, Emotion>();
+
+ constructor(public readonly name: string) {
+ }
+
+ get opposite(): Emotion {
+ return Emotion.opposite_map.get(this)!;
+ }
+
+ get element(): HTMLDivElement {
+ return document.querySelector<HTMLDivElement>(`.slogan.${this.name}`)!
+ }
+
+ get elementHeight(): number {
+ return this.element.clientHeight;
+ }
+
+ apply() {
+ localStorage.setItem(emotionKey, this.name);
+ document.body.dataset.emotion = this.name;
+ document.body.style.paddingTop = `${this.elementHeight}px`;
+ }
+}
+
+const happy = new Emotion("happy")
+const angry = new Emotion("angry")
+Emotion.opposite_map.set(happy, angry)
+Emotion.opposite_map.set(angry, happy)
+
+const emotionKey = "emotion";
+const savedEmotionName = localStorage.getItem(emotionKey) ?? happy.name;
+
+for (const emotion of [happy, angry]) {
+ if (emotion.name == savedEmotionName) {
+ emotion.apply();
+ }
+ emotion.element.addEventListener("click", () => {
+ emotion.opposite.apply();
+ });
+}
+
+setTimeout(() => {
+ document.body.style.transition = "padding-top 0.8s";
+});
diff --git a/services/docker/nginx/sites/www/src/style.css b/services/docker/nginx/sites/www/src/style.css
new file mode 100644
index 0000000..05c98a0
--- /dev/null
+++ b/services/docker/nginx/sites/www/src/style.css
@@ -0,0 +1,148 @@
+html {
+ width: 100%;
+}
+
+body {
+ width: 100%;
+ margin: 0;
+ display: flex;
+ flex-direction: column;
+}
+
+a {
+ font-family: monospace;
+}
+
+.fake-link {
+ font-family: monospace;
+}
+
+#main-article {
+ max-width: 880px;
+ margin-top: 1em;
+ padding: 0 1em;
+ align-self: center;
+}
+
+#title-name {
+ font-family: monospace;
+ background-color: black;
+ color: white;
+}
+
+@keyframes content-enter {
+ from {
+ opacity: 0;
+ transform: translateY(100px);
+ }
+
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes avatar-enter {
+ from {
+ opacity: 0;
+ transform: translateX(100%);
+ }
+
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+#main-article > * {
+ animation: content-enter 0.8s;
+}
+
+#avatar {
+ float: right;
+ animation: avatar-enter 0.8s;
+}
+
+.slogan-container {
+ width: 100vw;
+ top: 0;
+ position: fixed;
+}
+
+.slogan {
+ width: 100%;
+ padding: 0.5em 1em;
+ text-align: center;
+ box-sizing: border-box;
+ color: white;
+ position: absolute;
+ transform: translateY(-100%);
+ transition: transform 0.8s;
+}
+
+.slogan.happy {
+ background-color: dodgerblue;
+}
+
+.slogan.angry {
+ background-color: orangered;
+}
+
+body[data-emotion="happy"] .slogan.happy {
+ transform: translateY(0);
+}
+
+body[data-emotion="angry"] .slogan.angry {
+ transform: translateY(0);
+}
+
+#friends-container {
+ display: flex;
+ gap: 1em;
+}
+
+.friend {
+ flex-grow: 0;
+ text-align: center;
+}
+
+.friend a {
+ font-family: unset;
+}
+
+.friend-avatar {
+ object-fit: cover;
+}
+
+.friend-github {
+ width: 1em;
+ vertical-align: middle;
+ margin-right: -0.5em;
+}
+
+.friend-tag {
+ font-size: 0.8em;
+}
+
+.citation {
+ margin: auto;
+}
+
+.citation figcaption {
+ text-align: right;
+}
+
+#license a {
+ font-family: initial;
+ text-decoration: none;
+}
+
+#license-text {
+ font-family: monospace;
+ text-decoration: initial;
+}
+
+#license-img-container img {
+ height: 1em;
+ vertical-align: middle;
+}