feat: move top screen components to own folder, and implement calendar
This commit is contained in:
53
app/app.vue
53
app/app.vue
@@ -1,45 +1,24 @@
|
|||||||
<!-- <template>
|
<script setup lang="ts">
|
||||||
|
const showStats = ref(false);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
<div
|
<div
|
||||||
:style="{
|
:style="{
|
||||||
position: 'relative',
|
display: 'flex',
|
||||||
width: '256px',
|
flexDirection: 'column',
|
||||||
transformOrigin: 'top left',
|
gap: '4px',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div
|
<div :style="{ display: 'flex', alignItems: 'center', gap: '4px' }">
|
||||||
:style="{
|
<input id="statsCheckbox" type="checkbox" v-model="showStats" />
|
||||||
boxSizing: 'border-box',
|
<label for="statsCheckbox">Stats</label>
|
||||||
width: '256px',
|
</div>
|
||||||
height: '192px',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<img src="/assets/background.png" />
|
|
||||||
|
|
||||||
<div
|
<div>
|
||||||
:style="{
|
<TopScreen>
|
||||||
position: 'absolute',
|
<Stats v-if="showStats" />
|
||||||
display: 'grid',
|
</TopScreen>
|
||||||
gap: '1px',
|
|
||||||
top: 'calc(4 * 16px)',
|
|
||||||
right: 'calc(1 * 16px + 1px)',
|
|
||||||
gridTemplateRows: 'repeat(5, 15px)',
|
|
||||||
gridTemplateColumns: 'repeat(7, 15px)',
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-for="i in 5 * 7"
|
|
||||||
:key="i"
|
|
||||||
:style="{ display: 'flex', flexDirection: 'column' }"
|
|
||||||
>
|
|
||||||
<span :style="{ fontSize: '12px' }">8</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template> -->
|
|
||||||
<template>
|
|
||||||
<Screen>
|
|
||||||
<Background />
|
|
||||||
<Stats />
|
|
||||||
</Screen>
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -36,7 +36,11 @@ const renderFrame = (timestamp: number) => {
|
|||||||
ctx.clearRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
ctx.clearRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
|
|
||||||
for (const callback of renderCallbacks) {
|
for (const callback of renderCallbacks) {
|
||||||
|
ctx.save();
|
||||||
|
|
||||||
callback(ctx);
|
callback(ctx);
|
||||||
|
|
||||||
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
lastRealFrameTime = Date.now() - start;
|
lastRealFrameTime = Date.now() - start;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ useRender((ctx) => {
|
|||||||
const LINE_HEIGHT = 12;
|
const LINE_HEIGHT = 12;
|
||||||
|
|
||||||
ctx.fillStyle = "red";
|
ctx.fillStyle = "red";
|
||||||
ctx.fillRect(props.x - 2, props.y, 140, LINE_COUNT * LINE_HEIGHT + 3);
|
ctx.fillRect(props.x - 2, props.y, 120, LINE_COUNT * LINE_HEIGHT + 3);
|
||||||
|
|
||||||
let textY = props.y;
|
let textY = props.y;
|
||||||
|
|
||||||
@@ -59,5 +59,3 @@ useRender((ctx) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template></template>
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<script lang="ts" setup>
|
<script setup lang="ts">
|
||||||
const backgroundImage = useTemplateRef("backgroundImage");
|
const backgroundImage = useTemplateRef("backgroundImage");
|
||||||
|
|
||||||
useRender((ctx) => {
|
useRender((ctx) => {
|
||||||
75
app/components/TopScreen/Calendar.vue
Normal file
75
app/components/TopScreen/Calendar.vue
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// NOTE: calendar background is handled by TopScreenBackground
|
||||||
|
|
||||||
|
const lastRowImage = useTemplateRef("lastRowImage");
|
||||||
|
const daySelectorImage = useTemplateRef("daySelectorImage");
|
||||||
|
|
||||||
|
useRender((ctx) => {
|
||||||
|
if (!lastRowImage.value || !daySelectorImage.value) return;
|
||||||
|
|
||||||
|
ctx.fillStyle = "black";
|
||||||
|
ctx.font = "7px NDS7";
|
||||||
|
|
||||||
|
const CALENDAR_COLS = 7;
|
||||||
|
const CALENDAR_ROWS = 5;
|
||||||
|
const CALENDAR_LEFT = 128;
|
||||||
|
const CALENDAR_TOP = 64;
|
||||||
|
|
||||||
|
ctx.fillStyle = "#343434";
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
const year = now.getFullYear();
|
||||||
|
const month = now.getMonth();
|
||||||
|
|
||||||
|
const firstDay = new Date(year, month, 1).getDay();
|
||||||
|
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
||||||
|
|
||||||
|
const extraRow = CALENDAR_COLS * CALENDAR_ROWS - daysInMonth - firstDay < 0;
|
||||||
|
if (extraRow) {
|
||||||
|
ctx.drawImage(lastRowImage.value, CALENDAR_LEFT - 3, CALENDAR_TOP + 79);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let col = 0; col < CALENDAR_ROWS + (extraRow ? 1 : 0); col += 1) {
|
||||||
|
for (let row = 0; row < CALENDAR_COLS; row += 1) {
|
||||||
|
const cellIndex = col * CALENDAR_COLS + row;
|
||||||
|
const day = cellIndex - firstDay + 1;
|
||||||
|
|
||||||
|
if (day > 0 && day <= daysInMonth) {
|
||||||
|
const dayText = day.toString();
|
||||||
|
const { actualBoundingBoxRight: width } = ctx.measureText(dayText);
|
||||||
|
|
||||||
|
const cellLeft = CALENDAR_LEFT + row * 16;
|
||||||
|
const cellTop = CALENDAR_TOP + col * 16;
|
||||||
|
|
||||||
|
if (now.getDate() === day) {
|
||||||
|
ctx.drawImage(daySelectorImage.value, cellLeft, cellTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.fillText(
|
||||||
|
dayText,
|
||||||
|
cellLeft + Math.floor((15 - width) / 2),
|
||||||
|
cellTop + 11,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.fillStyle = "black";
|
||||||
|
ctx.font = "9px NDS9";
|
||||||
|
ctx.letterSpacing = "2px";
|
||||||
|
|
||||||
|
const timeText = `${month}/${year}`;
|
||||||
|
const { actualBoundingBoxRight: width } = ctx.measureText(timeText);
|
||||||
|
|
||||||
|
ctx.fillText(
|
||||||
|
timeText,
|
||||||
|
CALENDAR_LEFT + Math.floor((111 - width) / 2),
|
||||||
|
CALENDAR_TOP - 20,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<img ref="lastRowImage" src="/assets/calendar_last-row.png" hidden />
|
||||||
|
<img ref="daySelectorImage" src="/assets/calendar_day-selector.png" hidden />
|
||||||
|
</template>
|
||||||
8
app/components/TopScreen/TopScreen.vue
Normal file
8
app/components/TopScreen/TopScreen.vue
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<template>
|
||||||
|
<Screen>
|
||||||
|
<TopScreenBackground />
|
||||||
|
<TopScreenCalendar />
|
||||||
|
|
||||||
|
<slot />
|
||||||
|
</Screen>
|
||||||
|
</template>
|
||||||
Reference in New Issue
Block a user