new components and stamps

This commit is contained in:
2026-02-04 16:44:15 +00:00
parent 227fcadda6
commit 2c553bc0d9
19 changed files with 195 additions and 61 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -205,28 +205,28 @@ td {
@media (max-width: 850px) {
.a4page-portrait {
width: 100%; /* fill mobile width */
height: auto; /* adjust height automatically */
height: fit-content;
margin: 0 auto; /* center horizontally */
box-sizing: border-box;
}
.a4page-landscape {
width: 100%; /* fill mobile width */
height: auto; /* adjust height automatically */
height: fit-content;
margin: 0 auto; /* center horizontally */
box-sizing: border-box;
}
}
@media (max-width: 600px) {
.a5page-portrait {
width: 100%; /* fill mobile width */
height: auto; /* adjust height automatically */
margin: 0 auto; /* center horizontally */
width: 100%;
height: fit-content;
margin: 0 auto;
box-sizing: border-box;
}
.a5page-landscape {
width: 100%; /* fill mobile width */
height: auto; /* adjust height automatically */
margin: 0 auto; /* center horizontally */
width: 100%;
height: fit-content;
margin: 0 auto;
box-sizing: border-box;
}
}

View File

@@ -4,6 +4,29 @@ import OptionalLinkTable from "@/components/util/OptionalLinkTable.vue";
import Header from "@/components/text/Header.vue";
const data = [
{
type: "Anime",
name: "Cowboy bebop",
},
{
type: "Game",
name: "Rounds",
link: "https://store.steampowered.com/app/1557740/ROUNDS/",
},
{
type: "Boardgame",
name: "Root",
},
{
type: "Game",
name: "The farmer was replaced",
link: "https://store.steampowered.com/app/2060160/The_Farmer_Was_Replaced/",
},
{
type: "Game",
name: "Higurashi When They Cry Hou - Ch.1",
link: "https://store.steampowered.com/app/310360/Higurashi_When_They_Cry_Hou__Ch1_Onikakushi/",
},
{
type: "Substack",
name: "By Ellie",

View File

@@ -9,10 +9,11 @@ const gym = [
</script>
<template>
<div class="flex flex-col items-center">
<div class="flex flex-col place-content-between items-center">
<Header>Gym</Header>
<p class="m-3">I'm not a gym geek but I always do:</p>
<div class="overflow-scroll w-full flex-1 border-box">
<p>I'm not a gym geek</p>
<p>4/7 days I do:</p>
<div class="overflow-scroll w-full border-box">
<OptionalLinkTable class="w-full" :data="gym" />
</div>
</div>

View File

@@ -1,18 +1,40 @@
<script setup>
import { ref } from "vue";
import Touchscreen from "@/components/util/Touchscreen.vue";
import { shuffleArray } from "@/js/utils.js";
let srcs = [
"/img/stamps/portal.gif",
"/img/stamps/miku.gif",
"/img/stamps/utau.gif",
"/img/stamps/teto.webp",
"/img/stamps/3ds.jpg",
"/img/stamps/fry.png",
"/img/stamps/ai.png",
"/img/stamps/rei.png",
"/img/stamps/tetris.gif",
"/img/stamps/tf2.gif",
"/img/stamps/demo.gif",
];
shuffleArray(srcs);
</script>
<template>
<div class="grid grid-cols-4 overflow-scroll gap-0">
<a href="https://www.adam-french.co.uk">
<img src="https://www.adam-french.co.uk/img/stamps/mine.gif" />
</a>
<a href="https://jacobbarron.xyz">
<img
src="https://jacobbarron.xyz/Banneh.gif"
alt="jacobbarron.xyz"
/>
</a>
<img src="/img/stamps/portal.gif" />
<img src="/img/stamps/miku.gif" />
<img src="/img/stamps/utau.gif" />
</div>
<Touchscreen>
<div class="flex flex-wrap tst">
<a href="https://www.adam-french.co.uk">
<img src="https://www.adam-french.co.uk/img/stamps/mine.gif" />
</a>
<a href="https://jacobbarron.xyz">
<img
src="https://jacobbarron.xyz/Banneh.gif"
alt="jacobbarron.xyz"
/>
</a>
<img v-for="src in srcs" :src="src" />
</div>
</Touchscreen>
</template>
<style scoped>
@@ -20,4 +42,7 @@ img {
width: 89px;
height: 59px;
}
.tst {
width: calc(89px * 4);
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<div ref="container" class="overflow-y-auto">
<div ref="container" @mouseover="handleHover" class="overflow-y-auto">
<slot />
</div>
</template>
@@ -14,38 +14,37 @@ const PAUSE = 2000; // ms at top/bottom
const FRAME_TIME = 50; // ms at top/bottom
let direction = 1; // 1 = down, -1 = up
let paused = false;
let rafId;
let timeoutId;
function handleHover() {
clearTimeout(timeoutId);
timeoutId = setTimeout(tick, PAUSE);
}
function tick() {
const el = container.value;
el.scrollTop += SPEED * direction;
const reachedBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 1;
const reachedBottom = el.scrollTop + el.clientHeight >= el.scrollHeight;
const reachedTop = el.scrollTop <= 0;
if (reachedBottom || reachedTop) {
direction *= -1;
timeoutId = setTimeout(() => {
paused = false;
rafId = setTimeout(tick, FRAME_TIME);
}, PAUSE);
timeoutId = setTimeout(tick, PAUSE);
return;
}
rafId = setTimeout(tick, FRAME_TIME);
timeoutId = setTimeout(tick, FRAME_TIME);
}
onMounted(() => {
rafId = setTimeout(tick, FRAME_TIME);
timeoutId = setTimeout(tick, FRAME_TIME);
});
onBeforeUnmount(() => {
clearTimeout(rafId);
clearTimeout(timeoutId);
});
</script>

View File

@@ -67,9 +67,9 @@ function playFinishedSound() {
>
<h2 class="items-center">Timer</h2>
<div v-if="finished && paused" class="flex flex-col">
<div class="flex flex-row p-2">
<div class="flex flex-row p-2 place-content-around">
<input
class="w-full"
class="w-2/3"
v-model="minutesInput"
type="range"
min="0"
@@ -77,9 +77,9 @@ function playFinishedSound() {
/>
<p>{{ minutesInput }}m</p>
</div>
<div class="flex flex-row p-2">
<div class="flex flex-row p-2 place-content-around">
<input
class="w-full"
class="w-2/3"
v-model="secondsInput"
type="range"
min="0"

View File

@@ -0,0 +1,67 @@
<template>
<div
ref="container"
class="overflow-auto w-full h-full"
@mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
@mouseleave="handleMouseLeave"
:style="{ cursor: isDragging ? 'grabbing' : 'grab' }"
>
<slot />
</div>
</template>
<script setup>
import { ref } from "vue";
const container = ref(null);
const isDragging = ref(false);
const startX = ref(0);
const startY = ref(0);
const scrollLeft = ref(0);
const scrollTop = ref(0);
const handleMouseDown = (e) => {
isDragging.value = true;
startX.value = e.pageX - container.value.offsetLeft;
startY.value = e.pageY - container.value.offsetTop;
scrollLeft.value = container.value.scrollLeft;
scrollTop.value = container.value.scrollTop;
// Prevent text selection while dragging
e.preventDefault();
};
const handleMouseMove = (e) => {
if (!isDragging.value) return;
e.preventDefault();
const x = e.pageX - container.value.offsetLeft;
const y = e.pageY - container.value.offsetTop;
const walkX = (x - startX.value) * 1; // Multiply by scroll speed factor
const walkY = (y - startY.value) * 1;
container.value.scrollLeft = scrollLeft.value - walkX;
container.value.scrollTop = scrollTop.value - walkY;
};
const handleMouseUp = () => {
isDragging.value = false;
};
const handleMouseLeave = () => {
isDragging.value = false;
};
</script>
<style scoped>
/* Prevent text selection while dragging */
div[style*="cursor: grabbing"] {
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
</style>

View File

@@ -0,0 +1,8 @@
export function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}

View File

@@ -17,32 +17,40 @@ import Consumption from "@/components/home/Consumption.vue";
<template>
<main class="halftone justify-center flex flex-row w-full h-full p-10">
<div class="page a4page-portrait bdr-1 homeGrid relative">
<Intro class="intro" />
<Listening class="listening" />
<Stamps class="stamps" />
<Feed class="feed" />
<Links class="links" />
<Collage class="collage" />
<Consumption class="consumption" />
<Favorites class="favorites" />
<Gym class="gym" />
</div>
<div
class="flex flex-col w-1/12 sidebar border-primary place-content-between h-full sticky m-10"
>
<div class="flex flex-col">
<Time />
<Timer />
<!-- <Chat class="bdr-2 bg-bg_primary" /> -->
<!-- <MusicPlayer /> -->
<div class="a4height flex flex-row">
<div class="a4page-portrait bdr-1 homeGrid relative">
<Intro class="intro" />
<Listening class="listening" />
<Stamps class="stamps" />
<Feed class="feed" />
<Links class="links" />
<Collage class="collage" />
<Consumption class="consumption" />
<Favorites class="favorites" />
<Gym class="gym" />
</div>
<div
class="flex flex-col sidebar border-primary place-content-between h-full sticky m-10 w-60"
>
<div class="flex flex-col">
<Time />
<Timer />
<!-- <Chat class="bdr-2 bg-bg_primary" /> -->
<!-- <MusicPlayer /> -->
</div>
<img
src="/img/memes/fire-woman.gif"
class="border-tertiary border"
/>
</div>
<img src="/img/memes/fire-woman.gif" class="w-80" />
</div>
</main>
</template>
<style scoped>
.a4height {
height: 297mm;
}
.homeGrid > * {
@apply border-2 border-dotted;
border-color: var(--primary);
@@ -56,12 +64,15 @@ import Consumption from "@/components/home/Consumption.vue";
grid-template-rows: repeat(10, 1fr);
}
@media (max-width: 1000px) {
@media (max-width: 800px) {
.homeGrid {
width: 100%;
display: flex;
flex-direction: column;
}
}
@media (max-width: 1200px) {
.tr,
.br,
.sidebar {