feat(assets): new assets loading system (currently only for images)
6
.gitignore
vendored
@@ -1,8 +1,6 @@
|
||||
# generated
|
||||
public/images/projects
|
||||
|
||||
# temporary
|
||||
__old
|
||||
public/images/projects/pokemons
|
||||
app/composables/useAssets.ts
|
||||
|
||||
# ESlint
|
||||
.eslintcache
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import CORNER_IMAGE from "/assets/images/home/bottom-screen/buttons/corner.webp";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
rect: [x: number, y: number, width: number, height: number];
|
||||
@@ -11,7 +9,7 @@ const props = withDefaults(
|
||||
},
|
||||
);
|
||||
|
||||
const [cornerImage] = useImages(CORNER_IMAGE);
|
||||
const { assets } = useAssets();
|
||||
|
||||
const ANIMATION_SPEED = 0.25;
|
||||
|
||||
@@ -45,21 +43,21 @@ useRender((ctx) => {
|
||||
|
||||
ctx.globalAlpha = props.opacity;
|
||||
|
||||
ctx.drawImage(cornerImage!, x, y);
|
||||
ctx.drawImage(assets.home.bottomScreen.buttons.corner, x, y);
|
||||
|
||||
ctx.save();
|
||||
ctx.scale(-1, 1);
|
||||
ctx.drawImage(cornerImage!, -(x + w), y);
|
||||
ctx.drawImage(assets.home.bottomScreen.buttons.corner, -(x + w), y);
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.scale(1, -1);
|
||||
ctx.drawImage(cornerImage!, x, -(y + h));
|
||||
ctx.drawImage(assets.home.bottomScreen.buttons.corner, x, -(y + h));
|
||||
ctx.restore();
|
||||
|
||||
ctx.save();
|
||||
ctx.scale(-1, -1);
|
||||
ctx.drawImage(cornerImage!, -(x + w), -(y + h));
|
||||
ctx.drawImage(assets.home.bottomScreen.buttons.corner, -(x + w), -(y + h));
|
||||
ctx.restore();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import HOME_BACKGROUND_IMAGE from "/assets/images/home/bottom-screen/background.webp";
|
||||
import CONTACT_BACKGROUND_IMAGE from "/assets/images/contact/bottom-screen/background.webp";
|
||||
|
||||
const store = useContactStore();
|
||||
|
||||
const [homeBackgroundImage, contactBackgroundImage] = useImages(
|
||||
HOME_BACKGROUND_IMAGE,
|
||||
CONTACT_BACKGROUND_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.drawImage(homeBackgroundImage!, 0, 0);
|
||||
ctx.drawImage(assets.home.bottomScreen.background, 0, 0);
|
||||
ctx.globalAlpha = store.isIntro
|
||||
? store.intro.stage2Opacity
|
||||
: store.outro.stage3Opacity;
|
||||
|
||||
ctx.drawImage(contactBackgroundImage!, 0, 0);
|
||||
ctx.drawImage(assets.contact.bottomScreen.background, 0, 0);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import TOP_BAR_IMAGE from "/assets/images/contact/bottom-screen/top-bar.webp";
|
||||
import BOTTOM_BAR_IMAGE from "/assets/images/contact/bottom-screen/bottom-bar.webp";
|
||||
import BOTTOM_BAR_OK_IMAGE from "/assets/images/contact/bottom-screen/ok-button.webp";
|
||||
|
||||
const props = defineProps<{
|
||||
okLabel: "Copy" | "Open";
|
||||
}>();
|
||||
|
||||
const store = useContactStore();
|
||||
|
||||
const [topBarImage, bottomBarImage, bottomBarOkImage] = useImages(
|
||||
TOP_BAR_IMAGE,
|
||||
BOTTOM_BAR_IMAGE,
|
||||
BOTTOM_BAR_OK_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.globalAlpha = store.isIntro
|
||||
@@ -21,13 +13,17 @@ useRender((ctx) => {
|
||||
: store.outro.stage2Opacity;
|
||||
|
||||
// top bar
|
||||
ctx.drawImage(topBarImage!, 0, store.isIntro ? store.intro.topBarY : 0);
|
||||
ctx.drawImage(
|
||||
assets.contact.bottomScreen.topBar,
|
||||
0,
|
||||
store.isIntro ? store.intro.topBarY : 0,
|
||||
);
|
||||
|
||||
// bottom bar
|
||||
ctx.translate(0, store.isIntro ? store.intro.bottomBarY : SCREEN_HEIGHT - 24);
|
||||
ctx.drawImage(bottomBarImage!, 0, 0);
|
||||
ctx.drawImage(assets.contact.bottomScreen.bottomBar, 0, 0);
|
||||
|
||||
ctx.drawImage(bottomBarOkImage!, 144, 4);
|
||||
ctx.drawImage(assets.contact.bottomScreen.okButton, 144, 4);
|
||||
ctx.font = "10px NDS10";
|
||||
ctx.fillStyle = "#000000";
|
||||
ctx.fillText(props.okLabel, 144 + 35, 4 + 13);
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import BUTTONS_IMAGE from "/assets/images/contact/bottom-screen/buttons.webp";
|
||||
|
||||
const store = useContactStore();
|
||||
|
||||
const [buttonsImage] = useImages(BUTTONS_IMAGE);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.globalAlpha = store.isIntro
|
||||
? store.intro.stage3Opacity
|
||||
: store.outro.stage1Opacity;
|
||||
ctx.drawImage(buttonsImage!, 31, 32);
|
||||
ctx.drawImage(assets.contact.bottomScreen.buttons, 31, 32);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import HOME_BACKGROUND_IMAGE from "/assets/images/home/top-screen/background.webp";
|
||||
import CONTACT_BACKGROUND_IMAGE from "/assets/images/contact/top-screen/background.webp";
|
||||
|
||||
const store = useContactStore();
|
||||
|
||||
const [homeBackgroundImage, contactBackgroundImage] = useImages(
|
||||
HOME_BACKGROUND_IMAGE,
|
||||
CONTACT_BACKGROUND_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.drawImage(homeBackgroundImage!, 0, 0);
|
||||
ctx.drawImage(assets.home.topScreen.background, 0, 0);
|
||||
ctx.globalAlpha = store.isIntro
|
||||
? store.intro.stage2Opacity
|
||||
: store.outro.stage3Opacity;
|
||||
|
||||
ctx.drawImage(contactBackgroundImage!, 0, 0);
|
||||
ctx.drawImage(assets.contact.topScreen.background, 0, 0);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import BACKGROUND_IMAGE from "/assets/images/contact/top-screen/left-bar.webp";
|
||||
import THINGS_IMAGE from "/assets/images/contact/top-screen/left-bar-things.webp";
|
||||
|
||||
const store = useContactStore();
|
||||
|
||||
const [backgroundImage, thingsImage] = useImages(
|
||||
BACKGROUND_IMAGE,
|
||||
THINGS_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.globalAlpha = store.isIntro
|
||||
? store.intro.stage1Opacity
|
||||
: store.outro.stage2Opacity;
|
||||
ctx.drawImage(backgroundImage!, 0, 0);
|
||||
ctx.drawImage(assets.contact.topScreen.leftBar, 0, 0);
|
||||
|
||||
ctx.globalAlpha = store.isIntro
|
||||
? store.intro.stage3Opacity
|
||||
: store.outro.stage1Opacity;
|
||||
ctx.drawImage(thingsImage!, 0, 0);
|
||||
ctx.drawImage(assets.contact.topScreen.leftBarThings, 0, 0);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import NOTIFICATION_IMAGE from "/assets/images/contact/bottom-screen/notification.webp";
|
||||
import TITLE_IMAGE from "/assets/images/contact/top-screen/title.webp";
|
||||
|
||||
// text color:
|
||||
const store = useContactStore();
|
||||
|
||||
const [notificationImage, titleImage] = useImages(
|
||||
NOTIFICATION_IMAGE,
|
||||
TITLE_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.globalAlpha = store.outro.stage2Opacity;
|
||||
@@ -20,7 +14,7 @@ useRender((ctx) => {
|
||||
const y = 169 - 24 * index + store.notificationsYOffset;
|
||||
if (y < -24) break;
|
||||
|
||||
ctx.drawImage(notificationImage!, 21, y);
|
||||
ctx.drawImage(assets.contact.bottomScreen.notification, 21, y);
|
||||
|
||||
const content = store.notifications[i]!;
|
||||
ctx.fillStyle = content.includes("opened") ? "#00fbba" : "#e3f300";
|
||||
@@ -32,7 +26,7 @@ useRender((ctx) => {
|
||||
? store.intro.stage1Opacity
|
||||
: store.outro.stage2Opacity;
|
||||
ctx.drawImage(
|
||||
titleImage!,
|
||||
assets.contact.topScreen.title,
|
||||
21,
|
||||
store.isIntro
|
||||
? store.intro.titleY
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import BACKGROUND_IMAGE from "/assets/images/home/bottom-screen/background.webp";
|
||||
|
||||
const store = useHomeStore();
|
||||
const app = useAppStore();
|
||||
|
||||
const [backgroundImage] = useImages(BACKGROUND_IMAGE);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.globalAlpha = app.booted ? 1 : store.intro.stage1Opacity;
|
||||
ctx.drawImage(backgroundImage!, 0, 0);
|
||||
ctx.drawImage(assets.home.bottomScreen.background, 0, 0);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import BUTTON_IMAGE from "/assets/images/home/bottom-screen/buttons/contact.webp";
|
||||
|
||||
const props = defineProps<{
|
||||
x: number;
|
||||
y: number;
|
||||
opacity: number;
|
||||
}>();
|
||||
|
||||
const [buttonImage] = useImages(BUTTON_IMAGE);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.globalAlpha = props.opacity;
|
||||
ctx.drawImage(buttonImage!, props.x, props.y);
|
||||
ctx.drawImage(assets.home.bottomScreen.buttons.contact, props.x, props.y);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import BUTTON_IMAGE from "/assets/images/home/bottom-screen/buttons/downloadPlay.webp";
|
||||
|
||||
const props = defineProps<{
|
||||
x: number;
|
||||
y: number;
|
||||
opacity: number;
|
||||
}>();
|
||||
|
||||
const [buttonImage] = useImages(BUTTON_IMAGE);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.globalAlpha = props.opacity;
|
||||
ctx.drawImage(buttonImage!, props.x, props.y);
|
||||
ctx.drawImage(
|
||||
assets.home.bottomScreen.buttons.downloadPlay,
|
||||
props.x,
|
||||
props.y,
|
||||
);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import BUTTON_IMAGE from "/assets/images/home/bottom-screen/buttons/game.webp";
|
||||
|
||||
const props = defineProps<{
|
||||
x: number;
|
||||
y: number;
|
||||
opacity: number;
|
||||
}>();
|
||||
|
||||
const [buttonImage] = useImages(BUTTON_IMAGE);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.globalAlpha = props.opacity;
|
||||
ctx.drawImage(buttonImage!, props.x, props.y);
|
||||
ctx.drawImage(assets.home.bottomScreen.buttons.game, props.x, props.y);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import BUTTON_IMAGE from "/assets/images/home/bottom-screen/buttons/settings.webp";
|
||||
|
||||
const props = defineProps<{
|
||||
x: number;
|
||||
y: number;
|
||||
opacity: number;
|
||||
}>();
|
||||
|
||||
const [buttonImage] = useImages(BUTTON_IMAGE);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.globalAlpha = props.opacity;
|
||||
ctx.drawImage(buttonImage!, props.x, props.y);
|
||||
ctx.drawImage(assets.home.bottomScreen.buttons.settings, props.x, props.y);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import BACKGROUND_IMAGE from "/assets/images/home/top-screen/background.webp";
|
||||
|
||||
const store = useHomeStore();
|
||||
const app = useAppStore();
|
||||
|
||||
const [backgroundImage] = useImages(BACKGROUND_IMAGE);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.globalAlpha = app.booted ? 1 : store.intro.stage1Opacity;
|
||||
ctx.drawImage(backgroundImage!, 0, 0);
|
||||
ctx.drawImage(assets.home.topScreen.background, 0, 0);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import CALENDAR_IMAGE from "/assets/images/home/top-screen/calendar/calendar.webp";
|
||||
import LAST_ROW_IMAGE from "/assets/images/home/top-screen/calendar/last-row.webp";
|
||||
import DAY_SELECTOR_IMAGE from "/assets/images/home/top-screen/calendar/day-selector.webp";
|
||||
|
||||
// NOTE: calendar background is handled by TopScreenBackground
|
||||
const store = useHomeStore();
|
||||
|
||||
const [calendarImage, lastRowImage, daySelectorImage] = useImages(
|
||||
CALENDAR_IMAGE,
|
||||
LAST_ROW_IMAGE,
|
||||
DAY_SELECTOR_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.fillStyle = "black";
|
||||
@@ -35,11 +27,19 @@ useRender((ctx) => {
|
||||
: store.isOutro && store.outro.animateTop
|
||||
? store.outro.stage1Opacity
|
||||
: 1;
|
||||
ctx.drawImage(calendarImage!, CALENDAR_LEFT - 3, CALENDAR_TOP - 33);
|
||||
ctx.drawImage(
|
||||
assets.home.topScreen.calendar.calendar,
|
||||
CALENDAR_LEFT - 3,
|
||||
CALENDAR_TOP - 33,
|
||||
);
|
||||
|
||||
const extraRow = CALENDAR_COLS * CALENDAR_ROWS - daysInMonth - firstDay < 0;
|
||||
if (extraRow) {
|
||||
ctx.drawImage(lastRowImage!, CALENDAR_LEFT - 3, CALENDAR_TOP + 79);
|
||||
ctx.drawImage(
|
||||
assets.home.topScreen.calendar.lastRow,
|
||||
CALENDAR_LEFT - 3,
|
||||
CALENDAR_TOP + 79,
|
||||
);
|
||||
}
|
||||
|
||||
ctx.globalAlpha = store.isIntro
|
||||
@@ -60,7 +60,11 @@ useRender((ctx) => {
|
||||
const cellTop = CALENDAR_TOP + col * 16;
|
||||
|
||||
if (now.getDate() === day) {
|
||||
ctx.drawImage(daySelectorImage!, cellLeft, cellTop);
|
||||
ctx.drawImage(
|
||||
assets.home.topScreen.calendar.daySelector,
|
||||
cellLeft,
|
||||
cellTop,
|
||||
);
|
||||
}
|
||||
|
||||
ctx.fillText(
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import CLOCK_IMAGE from "/assets/images/home/top-screen/clock.webp";
|
||||
|
||||
const CENTER_X = 63;
|
||||
const CENTER_Y = 95;
|
||||
|
||||
const store = useHomeStore();
|
||||
|
||||
const [clockImage] = useImages(CLOCK_IMAGE);
|
||||
const { assets } = useAssets();
|
||||
|
||||
function drawLine(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
@@ -59,7 +57,7 @@ useRender((ctx) => {
|
||||
: store.isOutro && store.outro.animateTop
|
||||
? store.outro.stage1Opacity
|
||||
: 1;
|
||||
ctx.drawImage(clockImage!, 13, 45);
|
||||
ctx.drawImage(assets.home.topScreen.clock, 13, 45);
|
||||
|
||||
ctx.globalAlpha = store.isIntro
|
||||
? store.intro.stage1Opacity
|
||||
|
||||
@@ -1,18 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import STATUS_BAR_IMAGE from "/assets/images/home/top-screen/status-bar/status-bar.webp";
|
||||
import GBA_DISPLAY_IMAGE from "/assets/images/home/top-screen/status-bar/gba-display.webp";
|
||||
import STARTUP_MODE_IMAGE from "/assets/images/home/top-screen/status-bar/startup-mode.webp";
|
||||
import BATTERY_IMAGE from "/assets/images/home/top-screen/status-bar/battery.webp";
|
||||
|
||||
const store = useHomeStore();
|
||||
|
||||
const [statusBarImage, gbaDisplayImage, startupModeImage, batteryImage] =
|
||||
useImages(
|
||||
STATUS_BAR_IMAGE,
|
||||
GBA_DISPLAY_IMAGE,
|
||||
STARTUP_MODE_IMAGE,
|
||||
BATTERY_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
const TEXT_Y = 11;
|
||||
@@ -21,7 +10,7 @@ useRender((ctx) => {
|
||||
|
||||
ctx.globalAlpha =
|
||||
store.isOutro && store.outro.animateTop ? store.outro.stage2Opacity : 1;
|
||||
ctx.drawImage(statusBarImage!, 0, 0);
|
||||
ctx.drawImage(assets.home.topScreen.statusBar.statusBar, 0, 0);
|
||||
|
||||
ctx.fillStyle = "#ffffff";
|
||||
ctx.font = "7px NDS7";
|
||||
@@ -51,9 +40,9 @@ useRender((ctx) => {
|
||||
fillNumberCell(now.getMonth() + 1, 12, -1);
|
||||
|
||||
// icons
|
||||
ctx.drawImage(gbaDisplayImage!, 210, 2);
|
||||
ctx.drawImage(startupModeImage!, 226, 2);
|
||||
ctx.drawImage(batteryImage!, 242, 4);
|
||||
ctx.drawImage(assets.home.topScreen.statusBar.gbaDisplay, 210, 2);
|
||||
ctx.drawImage(assets.home.topScreen.statusBar.startupMode, 226, 2);
|
||||
ctx.drawImage(assets.home.topScreen.statusBar.battery, 242, 4);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import BACKGROUND_IMAGE from "~/assets/images/projects/bottom-screen/background.webp";
|
||||
|
||||
const [backgroundImage] = useImages(BACKGROUND_IMAGE);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.drawImage(backgroundImage!, 0, 0);
|
||||
ctx.drawImage(assets.projects.bottomScreen.background, 0, 0);
|
||||
});
|
||||
defineOptions({
|
||||
render: () => null,
|
||||
|
||||
@@ -1,37 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
import PREV_PRESSED_IMAGE from "~/assets/images/projects/bottom-screen/prev-pressed.webp";
|
||||
import QUIT_PRESSED_IMAGE from "~/assets/images/projects/bottom-screen/quit-pressed.webp";
|
||||
import LINK_PRESSED_IMAGE from "~/assets/images/projects/bottom-screen/link-pressed.webp";
|
||||
import NEXT_PRESSED_IMAGE from "~/assets/images/projects/bottom-screen/next-pressed.webp";
|
||||
import CIRCLE_SMALL_IMAGE from "~/assets/images/projects/bottom-screen/circle_small.webp";
|
||||
import CIRCLE_BIG_IMAGE from "~/assets/images/projects/bottom-screen/circle_big.webp";
|
||||
import gsap from "gsap";
|
||||
|
||||
const store = useProjectsStore();
|
||||
|
||||
const [
|
||||
prevPressedImage,
|
||||
quitPressedImage,
|
||||
linkPressedImage,
|
||||
nextPressedImage,
|
||||
circleSmallImagee,
|
||||
circleBigImage,
|
||||
] = useImages(
|
||||
PREV_PRESSED_IMAGE,
|
||||
QUIT_PRESSED_IMAGE,
|
||||
LINK_PRESSED_IMAGE,
|
||||
NEXT_PRESSED_IMAGE,
|
||||
CIRCLE_SMALL_IMAGE,
|
||||
CIRCLE_BIG_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
const CLICK_RADIUS = 22;
|
||||
|
||||
const BUTTONS = {
|
||||
prev: { position: [36, 100], image: prevPressedImage! },
|
||||
quit: { position: [88, 156], image: quitPressedImage! },
|
||||
link: { position: [168, 156], image: linkPressedImage! },
|
||||
next: { position: [220, 100], image: nextPressedImage! },
|
||||
prev: {
|
||||
position: [36, 100],
|
||||
image: assets.projects.bottomScreen.prevPressed,
|
||||
},
|
||||
quit: {
|
||||
position: [88, 156],
|
||||
image: assets.projects.bottomScreen.quitPressed,
|
||||
},
|
||||
link: {
|
||||
position: [168, 156],
|
||||
image: assets.projects.bottomScreen.linkPressed,
|
||||
},
|
||||
next: {
|
||||
position: [220, 100],
|
||||
image: assets.projects.bottomScreen.nextPressed,
|
||||
},
|
||||
} as const satisfies Record<
|
||||
string,
|
||||
{ position: Point; image: HTMLImageElement }
|
||||
@@ -123,7 +115,7 @@ useRender((ctx) => {
|
||||
|
||||
if (currentAnimation.showSmallCircle) {
|
||||
ctx.drawImage(
|
||||
circleSmallImagee!,
|
||||
assets.projects.bottomScreen.circleSmall,
|
||||
currentAnimation.position[0] - 28,
|
||||
currentAnimation.position[1] - 28,
|
||||
);
|
||||
@@ -131,7 +123,7 @@ useRender((ctx) => {
|
||||
|
||||
if (currentAnimation.showBigCircle) {
|
||||
ctx.drawImage(
|
||||
circleBigImage!,
|
||||
assets.projects.bottomScreen.circleBig,
|
||||
currentAnimation.position[0] - 44,
|
||||
currentAnimation.position[1] - 44,
|
||||
);
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import BACKGROUND_IMAGE from "/assets/images/projects/top-screen/background.webp";
|
||||
|
||||
const [backgroundImage] = useImages(BACKGROUND_IMAGE);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.drawImage(backgroundImage!, 0, 0);
|
||||
ctx.drawImage(assets.projects.topScreen.background, 0, 0);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import BACKGROUND_IMAGE from "~/assets/images/projects/top-screen/background.webp";
|
||||
|
||||
const store = useProjectsStore();
|
||||
|
||||
const [backgroundImage, ...projectImages] = useImages(
|
||||
BACKGROUND_IMAGE,
|
||||
...store.projects.map((project) => `/images/projects/${project.id}.webp`),
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
const drawTextWithShadow = (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
@@ -60,7 +55,7 @@ const drawTextWithShadow2Lines = (
|
||||
};
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.drawImage(backgroundImage!, 0, 0);
|
||||
ctx.drawImage(assets.projects.topScreen.background, 0, 0);
|
||||
|
||||
ctx.textBaseline = "hanging";
|
||||
ctx.font = "16px Pokemon DP Pro";
|
||||
@@ -69,7 +64,10 @@ useRender((ctx) => {
|
||||
if (!project) return;
|
||||
|
||||
// image
|
||||
const projectImage = projectImages[store.currentProject]!;
|
||||
const projectImage =
|
||||
assets.projects.pokemons[
|
||||
project.id as keyof typeof assets.projects.pokemons
|
||||
];
|
||||
ctx.drawImage(
|
||||
projectImage,
|
||||
Math.floor(52 - projectImage.width / 2),
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import BACKGROUND_IMAGE from "/assets/images/home/bottom-screen/background.webp";
|
||||
import TOP_BAR_IMAGE from "/assets/images/settings/bottom-screen/top-bar.webp";
|
||||
import BOTTOM_BAR_IMAGE from "/assets/images/settings/bottom-screen/bottom-bar.webp";
|
||||
|
||||
const [backgroundImage, topBarImage, bottomBarImage] = useImages(
|
||||
BACKGROUND_IMAGE,
|
||||
TOP_BAR_IMAGE,
|
||||
BOTTOM_BAR_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.drawImage(backgroundImage!, 0, 0);
|
||||
ctx.drawImage(topBarImage!, 0, 0);
|
||||
ctx.drawImage(bottomBarImage!, 0, 168);
|
||||
ctx.drawImage(assets.home.bottomScreen.background, 0, 0);
|
||||
ctx.drawImage(assets.settings.bottomScreen.topBar, 0, 0);
|
||||
ctx.drawImage(assets.settings.bottomScreen.bottomBar, 0, 168);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import MENU_IMAGE from "/assets/images/settings/top-screen/clock/clock.webp";
|
||||
import MENU_ACTIVE_IMAGE from "/assets/images/settings/top-screen/clock/clock-active.webp";
|
||||
import MENU_DISABLED_IMAGE from "/assets/images/settings/top-screen/clock/clock-disabled.png";
|
||||
import ALARM_IMAGE from "/assets/images/settings/top-screen/clock/alarm.webp";
|
||||
import TIME_IMAGE from "/assets/images/settings/top-screen/clock/time.webp";
|
||||
import DATE_IMAGE from "/assets/images/settings/top-screen/clock/date.webp";
|
||||
|
||||
const props = defineProps<{
|
||||
x: number;
|
||||
y: number;
|
||||
@@ -13,21 +6,7 @@ const props = defineProps<{
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const [
|
||||
menuImage,
|
||||
menuActiveImage,
|
||||
menuDisabledImage,
|
||||
alarmImage,
|
||||
timeImage,
|
||||
dateImage,
|
||||
] = useImages(
|
||||
MENU_IMAGE,
|
||||
MENU_ACTIVE_IMAGE,
|
||||
MENU_DISABLED_IMAGE,
|
||||
ALARM_IMAGE,
|
||||
TIME_IMAGE,
|
||||
DATE_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
const isOpen = computed(() => settingsStore.isMenuOpen("clock"));
|
||||
const isAnyOtherMenuOpen = computed(() =>
|
||||
@@ -41,22 +20,26 @@ useRender((ctx) => {
|
||||
|
||||
if (isOpen.value || animation.playing) {
|
||||
ctx.drawImage(
|
||||
timeImage!,
|
||||
assets.settings.topScreen.clock.time,
|
||||
48 - animation.stage2Offset,
|
||||
-48 + animation.stage1Offset,
|
||||
);
|
||||
ctx.drawImage(
|
||||
dateImage!,
|
||||
assets.settings.topScreen.clock.date,
|
||||
0,
|
||||
-96 + animation.stage2Offset + animation.stage1Offset,
|
||||
);
|
||||
ctx.drawImage(alarmImage!, 0, -48 + animation.stage1Offset);
|
||||
ctx.drawImage(
|
||||
assets.settings.topScreen.clock.alarm,
|
||||
0,
|
||||
-48 + animation.stage1Offset,
|
||||
);
|
||||
|
||||
ctx.drawImage(menuActiveImage!, 0, 0);
|
||||
ctx.drawImage(assets.settings.topScreen.clock.clockActive, 0, 0);
|
||||
} else if (isAnyOtherMenuOpen.value) {
|
||||
ctx.drawImage(menuDisabledImage!, 0, 0);
|
||||
ctx.drawImage(assets.settings.topScreen.clock.clockDisabled, 0, 0);
|
||||
} else {
|
||||
ctx.drawImage(menuImage!, 0, 0);
|
||||
ctx.drawImage(assets.settings.topScreen.clock.clock, 0, 0);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import MENU_IMAGE from "/assets/images/settings/top-screen/options/options.webp";
|
||||
import MENU_ACTIVE_IMAGE from "/assets/images/settings/top-screen/options/options-active.png";
|
||||
import MENU_DISABLED_IMAGE from "/assets/images/settings/top-screen/options/options-disabled.png";
|
||||
import GBA_MODE_IMAGE from "/assets/images/settings/top-screen/options/gba-mode.webp";
|
||||
import LANGUAGE_IMAGE from "/assets/images/settings/top-screen/options/language.webp";
|
||||
import START_UP_IMAGE from "/assets/images/settings/top-screen/options/start-up.webp";
|
||||
|
||||
const props = defineProps<{
|
||||
x: number;
|
||||
y: number;
|
||||
@@ -13,21 +6,7 @@ const props = defineProps<{
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const [
|
||||
menuImage,
|
||||
menuActiveImage,
|
||||
menuDisabledImage,
|
||||
gbaModeImage,
|
||||
languageImage,
|
||||
startUpImage,
|
||||
] = useImages(
|
||||
MENU_IMAGE,
|
||||
MENU_ACTIVE_IMAGE,
|
||||
MENU_DISABLED_IMAGE,
|
||||
GBA_MODE_IMAGE,
|
||||
LANGUAGE_IMAGE,
|
||||
START_UP_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
const isOpen = computed(() => settingsStore.isMenuOpen("options"));
|
||||
const isAnyOtherMenuOpen = computed(() =>
|
||||
@@ -40,23 +19,27 @@ useRender((ctx) => {
|
||||
ctx.translate(props.x, props.y);
|
||||
|
||||
if (isOpen.value || animation.playing) {
|
||||
ctx.drawImage(languageImage!, 0, -48 + animation.stage1Offset);
|
||||
ctx.drawImage(
|
||||
gbaModeImage!,
|
||||
assets.settings.topScreen.options.language,
|
||||
0,
|
||||
-48 + animation.stage1Offset,
|
||||
);
|
||||
ctx.drawImage(
|
||||
assets.settings.topScreen.options.gbaMode,
|
||||
48 - animation.stage2Offset,
|
||||
-48 + animation.stage1Offset,
|
||||
);
|
||||
ctx.drawImage(
|
||||
startUpImage!,
|
||||
assets.settings.topScreen.options.startUp,
|
||||
0,
|
||||
-96 + animation.stage2Offset + animation.stage1Offset,
|
||||
);
|
||||
|
||||
ctx.drawImage(menuActiveImage!, 0, 0);
|
||||
ctx.drawImage(assets.settings.topScreen.options.optionsActive, 0, 0);
|
||||
} else if (isAnyOtherMenuOpen.value) {
|
||||
ctx.drawImage(menuDisabledImage!, 0, 0);
|
||||
ctx.drawImage(assets.settings.topScreen.options.optionsDisabled, 0, 0);
|
||||
} else {
|
||||
ctx.drawImage(menuImage!, 0, 0);
|
||||
ctx.drawImage(assets.settings.topScreen.options.options, 0, 0);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import MENU_IMAGE from "/assets/images/settings/top-screen/touch_screen/touch-screen.webp";
|
||||
import MENU_DISABLED_IMAGE from "/assets/images/settings/top-screen/touch_screen/touch-screen-disabled.png";
|
||||
|
||||
const props = defineProps<{
|
||||
x: number;
|
||||
y: number;
|
||||
@@ -9,10 +6,7 @@ const props = defineProps<{
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const [menuImage, menuDisabledImage] = useImages(
|
||||
MENU_IMAGE,
|
||||
MENU_DISABLED_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
const isAnyOtherMenuOpen = computed(() =>
|
||||
settingsStore.isAnyOtherMenuOpen("touchScreen"),
|
||||
@@ -20,9 +14,17 @@ const isAnyOtherMenuOpen = computed(() =>
|
||||
|
||||
useRender((ctx) => {
|
||||
if (isAnyOtherMenuOpen.value) {
|
||||
ctx.drawImage(menuDisabledImage!, props.x, props.y);
|
||||
ctx.drawImage(
|
||||
assets.settings.topScreen.touchScreen.touchScreenDisabled,
|
||||
props.x,
|
||||
props.y,
|
||||
);
|
||||
} else {
|
||||
ctx.drawImage(menuImage!, props.x, props.y);
|
||||
ctx.drawImage(
|
||||
assets.settings.topScreen.touchScreen.touchScreen,
|
||||
props.x,
|
||||
props.y,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import MENU_IMAGE from "/assets/images/settings/top-screen/user/user.webp";
|
||||
import MENU_ACTIVE_IMAGE from "/assets/images/settings/top-screen/user/user-active.webp";
|
||||
import MENU_DISABLED_IMAGE from "/assets/images/settings/top-screen/user/user-disabled.png";
|
||||
import BIRTHDAY_IMAGE from "/assets/images/settings/top-screen/user/birthday.webp";
|
||||
import COLOR_IMAGE from "/assets/images/settings/top-screen/user/color.webp";
|
||||
import MESSAGE_IMAGE from "/assets/images/settings/top-screen/user/message.webp";
|
||||
import USER_NAME_IMAGE from "/assets/images/settings/top-screen/user/user-name.webp";
|
||||
|
||||
const props = defineProps<{
|
||||
x: number;
|
||||
y: number;
|
||||
@@ -14,23 +6,7 @@ const props = defineProps<{
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const [
|
||||
menuImage,
|
||||
menuActiveImage,
|
||||
menuDisabledImage,
|
||||
birthdayImage,
|
||||
colorImage,
|
||||
messageImage,
|
||||
userNameImage,
|
||||
] = useImages(
|
||||
MENU_IMAGE,
|
||||
MENU_ACTIVE_IMAGE,
|
||||
MENU_DISABLED_IMAGE,
|
||||
BIRTHDAY_IMAGE,
|
||||
COLOR_IMAGE,
|
||||
MESSAGE_IMAGE,
|
||||
USER_NAME_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
const isOpen = computed(() => settingsStore.isMenuOpen("user"));
|
||||
const isAnyOtherMenuOpen = computed(() =>
|
||||
@@ -44,27 +20,31 @@ useRender((ctx) => {
|
||||
|
||||
if (isOpen.value || animation.playing) {
|
||||
ctx.drawImage(
|
||||
birthdayImage!,
|
||||
assets.settings.topScreen.user.birthday,
|
||||
-48 + animation.stage2Offset,
|
||||
-48 + animation.stage1Offset,
|
||||
);
|
||||
ctx.drawImage(userNameImage!, 0, -48 + animation.stage1Offset);
|
||||
ctx.drawImage(
|
||||
messageImage!,
|
||||
assets.settings.topScreen.user.userName,
|
||||
0,
|
||||
-48 + animation.stage1Offset,
|
||||
);
|
||||
ctx.drawImage(
|
||||
assets.settings.topScreen.user.message,
|
||||
48 - animation.stage2Offset,
|
||||
-48 + animation.stage1Offset,
|
||||
);
|
||||
ctx.drawImage(
|
||||
colorImage!,
|
||||
assets.settings.topScreen.user.color,
|
||||
0,
|
||||
-96 + animation.stage2Offset + animation.stage1Offset,
|
||||
);
|
||||
|
||||
ctx.drawImage(menuActiveImage!, 0, 0);
|
||||
ctx.drawImage(assets.settings.topScreen.user.userActive, 0, 0);
|
||||
} else if (isAnyOtherMenuOpen.value) {
|
||||
ctx.drawImage(menuDisabledImage!, 0, 0);
|
||||
ctx.drawImage(assets.settings.topScreen.user.userDisabled, 0, 0);
|
||||
} else {
|
||||
ctx.drawImage(menuImage!, 0, 0);
|
||||
ctx.drawImage(assets.settings.topScreen.user.user, 0, 0);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import BACKGROUND_IMAGE from "/assets/images/home/top-screen/background.webp";
|
||||
|
||||
const [backgroundImage] = useImages(BACKGROUND_IMAGE);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.drawImage(backgroundImage!, 0, 0);
|
||||
ctx.drawImage(assets.home.topScreen.background, 0, 0);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import CALENDAR_IMAGE from "/assets/images/home/top-screen/calendar/calendar.webp";
|
||||
import LAST_ROW_IMAGE from "/assets/images/home/top-screen/calendar/last-row.webp";
|
||||
import DAY_SELECTOR_IMAGE from "/assets/images/home/top-screen/calendar/day-selector.webp";
|
||||
|
||||
const [calendarImage, lastRowImage, daySelectorImage] = useImages(
|
||||
CALENDAR_IMAGE,
|
||||
LAST_ROW_IMAGE,
|
||||
DAY_SELECTOR_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.fillStyle = "black";
|
||||
@@ -29,11 +21,19 @@ useRender((ctx) => {
|
||||
const firstDay = new Date(year, month, 1).getDay();
|
||||
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
||||
|
||||
ctx.drawImage(calendarImage!, CALENDAR_LEFT - 3, CALENDAR_TOP - 33);
|
||||
ctx.drawImage(
|
||||
assets.home.topScreen.calendar.calendar,
|
||||
CALENDAR_LEFT - 3,
|
||||
CALENDAR_TOP - 33,
|
||||
);
|
||||
|
||||
const extraRow = CALENDAR_COLS * CALENDAR_ROWS - daysInMonth - firstDay < 0;
|
||||
if (extraRow) {
|
||||
ctx.drawImage(lastRowImage!, CALENDAR_LEFT - 3, CALENDAR_TOP + 79);
|
||||
ctx.drawImage(
|
||||
assets.home.topScreen.calendar.lastRow,
|
||||
CALENDAR_LEFT - 3,
|
||||
CALENDAR_TOP + 79,
|
||||
);
|
||||
}
|
||||
|
||||
for (let col = 0; col < CALENDAR_ROWS + (extraRow ? 1 : 0); col += 1) {
|
||||
@@ -49,7 +49,11 @@ useRender((ctx) => {
|
||||
const cellTop = CALENDAR_TOP + col * 16;
|
||||
|
||||
if (now.getDate() === day) {
|
||||
ctx.drawImage(daySelectorImage!, cellLeft, cellTop);
|
||||
ctx.drawImage(
|
||||
assets.home.topScreen.calendar.daySelector,
|
||||
cellLeft,
|
||||
cellTop,
|
||||
);
|
||||
}
|
||||
|
||||
ctx.fillText(
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import CLOCK_IMAGE from "/assets/images/home/top-screen/clock.webp";
|
||||
|
||||
const CENTER_X = 63;
|
||||
const CENTER_Y = 95;
|
||||
|
||||
const [clockImage] = useImages(CLOCK_IMAGE);
|
||||
const { assets } = useAssets();
|
||||
|
||||
function drawLine(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
@@ -54,7 +52,7 @@ function drawLine(
|
||||
useRender((ctx) => {
|
||||
ctx.translate(0, -16);
|
||||
|
||||
ctx.drawImage(clockImage!, 13, 45);
|
||||
ctx.drawImage(assets.home.topScreen.clock, 13, 45);
|
||||
|
||||
const now = new Date();
|
||||
|
||||
|
||||
@@ -1,37 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import NOTIFICATION_IMAGE from "/assets/images/settings/top-screen/notification.webp";
|
||||
import SETTINGS_IMAGE from "/assets/images/settings/top-screen/settings.webp";
|
||||
import OPTIONS_IMAGE from "/assets/images/settings/top-screen/options/options.webp";
|
||||
import CLOCK_IMAGE from "/assets/images/settings/top-screen/clock/clock.webp";
|
||||
import USER_IMAGE from "/assets/images/settings/top-screen/user/user.webp";
|
||||
import TOUCH_SCREEN_IMAGE from "/assets/images/settings/top-screen/touch_screen/touch-screen.webp";
|
||||
import START_UP_IMAGE from "/assets/images/settings/top-screen/options/start-up.webp";
|
||||
import LANGUAGE_IMAGE from "/assets/images/settings/top-screen/options/language.webp";
|
||||
import GBA_MODE_IMAGE from "/assets/images/settings/top-screen/options/gba-mode.webp";
|
||||
|
||||
const store = useSettingsStore();
|
||||
|
||||
const [
|
||||
notificationImage,
|
||||
settingsImage,
|
||||
optionsImage,
|
||||
clockImage,
|
||||
userImage,
|
||||
touchScreenImage,
|
||||
startUpImage,
|
||||
languageImage,
|
||||
gbaModeImage,
|
||||
] = useImages(
|
||||
NOTIFICATION_IMAGE,
|
||||
SETTINGS_IMAGE,
|
||||
OPTIONS_IMAGE,
|
||||
CLOCK_IMAGE,
|
||||
USER_IMAGE,
|
||||
TOUCH_SCREEN_IMAGE,
|
||||
START_UP_IMAGE,
|
||||
LANGUAGE_IMAGE,
|
||||
GBA_MODE_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
const renderNotification = (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
@@ -39,7 +9,7 @@ const renderNotification = (
|
||||
title: string,
|
||||
description: string,
|
||||
) => {
|
||||
ctx.drawImage(notificationImage!, 0, 0);
|
||||
ctx.drawImage(assets.settings.topScreen.notification, 0, 0);
|
||||
ctx.drawImage(image, 2, 2);
|
||||
|
||||
ctx.font = "10px NDS10";
|
||||
@@ -55,7 +25,7 @@ const renderNotification = (
|
||||
};
|
||||
|
||||
const mainNotification = computed(() => ({
|
||||
image: settingsImage!,
|
||||
image: assets.settings.topScreen.settings,
|
||||
title: $t("settings.title"),
|
||||
description: $t("settings.description"),
|
||||
}));
|
||||
@@ -67,16 +37,16 @@ const menuNotification = computed(() => {
|
||||
let id = "";
|
||||
|
||||
if (/^options[A-Z]/.test(store.currentMenu)) {
|
||||
image = optionsImage!;
|
||||
image = assets.settings.topScreen.options.options;
|
||||
id = "options";
|
||||
} else if (/^clock[A-Z]/.test(store.currentMenu)) {
|
||||
image = clockImage!;
|
||||
image = assets.settings.topScreen.clock.clock;
|
||||
id = "clock";
|
||||
} else if (/^user[A-Z]/.test(store.currentMenu)) {
|
||||
image = userImage!;
|
||||
image = assets.settings.topScreen.user.user;
|
||||
id = "user";
|
||||
} else if (/^touchScreen[A-Z]/.test(store.currentMenu)) {
|
||||
image = touchScreenImage!;
|
||||
image = assets.settings.topScreen.touchScreen.touchScreen;
|
||||
id = "touchScreen";
|
||||
}
|
||||
|
||||
@@ -90,9 +60,9 @@ const menuNotification = computed(() => {
|
||||
});
|
||||
|
||||
const IMAGES_MAP: Record<string, HTMLImageElement> = {
|
||||
optionsStartUp: startUpImage!,
|
||||
optionsLanguage: languageImage!,
|
||||
optionsGbaMode: gbaModeImage!,
|
||||
optionsStartUp: assets.settings.topScreen.options.startUp,
|
||||
optionsLanguage: assets.settings.topScreen.options.language,
|
||||
optionsGbaMode: assets.settings.topScreen.options.gbaMode,
|
||||
};
|
||||
|
||||
const submenuNotification = computed(() => {
|
||||
|
||||
@@ -1,21 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import STATUS_BAR_IMAGE from "/assets/images/home/top-screen/status-bar/status-bar.webp";
|
||||
import GBA_DISPLAY_IMAGE from "/assets/images/home/top-screen/status-bar/gba-display.webp";
|
||||
import STARTUP_MODE_IMAGE from "/assets/images/home/top-screen/status-bar/startup-mode.webp";
|
||||
import BATTERY_IMAGE from "/assets/images/home/top-screen/status-bar/battery.webp";
|
||||
|
||||
const [statusBarImage, gbaDisplayImage, startupModeImage, batteryImage] =
|
||||
useImages(
|
||||
STATUS_BAR_IMAGE,
|
||||
GBA_DISPLAY_IMAGE,
|
||||
STARTUP_MODE_IMAGE,
|
||||
BATTERY_IMAGE,
|
||||
);
|
||||
const { assets } = useAssets();
|
||||
|
||||
useRender((ctx) => {
|
||||
const TEXT_Y = 11;
|
||||
|
||||
ctx.drawImage(statusBarImage!, 0, 0);
|
||||
ctx.drawImage(assets.home.topScreen.statusBar.statusBar, 0, 0);
|
||||
|
||||
ctx.fillStyle = "#ffffff";
|
||||
ctx.font = "7px NDS7";
|
||||
@@ -45,9 +34,9 @@ useRender((ctx) => {
|
||||
fillNumberCell(now.getMonth() + 1, 12, -1);
|
||||
|
||||
// icons
|
||||
ctx.drawImage(gbaDisplayImage!, 210, 2);
|
||||
ctx.drawImage(startupModeImage!, 226, 2);
|
||||
ctx.drawImage(batteryImage!, 242, 4);
|
||||
ctx.drawImage(assets.home.topScreen.statusBar.gbaDisplay, 210, 2);
|
||||
ctx.drawImage(assets.home.topScreen.statusBar.startupMode, 226, 2);
|
||||
ctx.drawImage(assets.home.topScreen.statusBar.battery, 242, 4);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
|
||||
34
app/composables/useAssets.ts.in
Normal file
@@ -0,0 +1,34 @@
|
||||
const imageCache = new Map<string, HTMLImageElement>();
|
||||
|
||||
const loaded = ref(0);
|
||||
const total = ref({{TOTAL}});
|
||||
const isReady = computed(() => loaded.value === total.value);
|
||||
|
||||
const createImage = (path: string) => {
|
||||
if (imageCache.has(path)) {
|
||||
return imageCache.get(path)!;
|
||||
}
|
||||
|
||||
const img = document.createElement('img');
|
||||
img.src = path;
|
||||
imageCache.set(path, img);
|
||||
|
||||
if (img.complete) {
|
||||
loaded.value += 1;
|
||||
} else {
|
||||
img.onload = () => { loaded.value += 1 };
|
||||
}
|
||||
|
||||
return img;
|
||||
};
|
||||
|
||||
const assets = {{ASSETS}};
|
||||
|
||||
export const useAssets = () => {
|
||||
return {
|
||||
assets,
|
||||
loaded,
|
||||
total,
|
||||
isReady,
|
||||
};
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
const imageCache = new Map<string, HTMLImageElement>();
|
||||
|
||||
export const useImages = (...paths: string[]) => {
|
||||
const images = paths.map((path) => {
|
||||
if (imageCache.has(path)) {
|
||||
return imageCache.get(path)!;
|
||||
}
|
||||
|
||||
const img = document.createElement("img");
|
||||
img.src = path;
|
||||
imageCache.set(path, img);
|
||||
|
||||
return img;
|
||||
});
|
||||
|
||||
return images;
|
||||
};
|
||||
8
app/pages/test.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
const { isReady } = useAssets();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<LoadingScreen v-if="!isReady" />
|
||||
<p v-else>ok</p>
|
||||
</template>
|
||||
@@ -38,7 +38,9 @@ export const useProjectsStore = defineStore("projects", {
|
||||
if (!projects.value) throw "Cannot load projects";
|
||||
this.projects = projects.value.map((project) => ({
|
||||
...project,
|
||||
id: project.id.split("/")[2]!,
|
||||
id: project.id
|
||||
.split("/")[2]!
|
||||
.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()),
|
||||
}));
|
||||
|
||||
console.log(this.projects);
|
||||
|
||||
@@ -13,7 +13,10 @@ export default defineNuxtModule({
|
||||
async setup(_, nuxt) {
|
||||
const logger = useLogger("content-assets");
|
||||
const contentDir = join(nuxt.options.rootDir, "content");
|
||||
const publicDir = join(nuxt.options.rootDir, "public/images/projects");
|
||||
const publicDir = join(
|
||||
nuxt.options.rootDir,
|
||||
"public/images/projects/pokemons",
|
||||
);
|
||||
|
||||
const getFileChecksum = async (filePath: string): Promise<string> => {
|
||||
const content = await readFile(filePath);
|
||||
|
||||
128
modules/image-assets.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { defineNuxtModule, useLogger } from "@nuxt/kit";
|
||||
import { readdir, readFile, writeFile } from "fs/promises";
|
||||
import { join, relative, parse } from "path";
|
||||
import { existsSync, watch } from "fs";
|
||||
|
||||
type AssetsTree = {
|
||||
[key: string]: string | AssetsTree;
|
||||
};
|
||||
|
||||
const IMAGE_EXTENSIONS = new Set([".png", ".jpg", ".jpeg", ".webp", ".gif"]);
|
||||
|
||||
export default defineNuxtModule({
|
||||
meta: {
|
||||
name: "image-assets",
|
||||
configKey: "imageAssets",
|
||||
},
|
||||
defaults: {},
|
||||
async setup(_, nuxt) {
|
||||
const logger = useLogger("image-assets");
|
||||
const publicImagesDir = join(nuxt.options.rootDir, "public/images");
|
||||
const templateFile = join(
|
||||
nuxt.options.rootDir,
|
||||
"app/composables/useAssets.ts.in",
|
||||
);
|
||||
const outputFile = join(
|
||||
nuxt.options.rootDir,
|
||||
"app/composables/useAssets.ts",
|
||||
);
|
||||
|
||||
const isImageFile = (filename: string): boolean => {
|
||||
const ext = parse(filename).ext.toLowerCase();
|
||||
return IMAGE_EXTENSIONS.has(ext);
|
||||
};
|
||||
|
||||
const scanDirectory = async (dir: string): Promise<string[]> => {
|
||||
const images: string[] = [];
|
||||
const entries = await readdir(dir, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = join(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
images.push(...(await scanDirectory(fullPath)));
|
||||
} else if (isImageFile(entry.name)) {
|
||||
images.push(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
return images;
|
||||
};
|
||||
|
||||
const toCamelCase = (str: string): string => {
|
||||
return str.replace(/[-_](.)/g, (_, c) => c.toUpperCase());
|
||||
};
|
||||
|
||||
const buildAssetsTree = (images: string[], baseDir: string): AssetsTree => {
|
||||
const tree: AssetsTree = {};
|
||||
|
||||
for (const imagePath of images) {
|
||||
const relativePath = relative(baseDir, imagePath);
|
||||
const parts = relativePath.split("/");
|
||||
const filename = parse(parts[parts.length - 1]!).name;
|
||||
|
||||
let current = tree;
|
||||
for (let i = 0; i < parts.length - 1; i += 1) {
|
||||
const key = toCamelCase(parts[i]!);
|
||||
current[key] ??= {};
|
||||
current = current[key] as AssetsTree;
|
||||
}
|
||||
|
||||
current[toCamelCase(filename)] = `/images/${relativePath}`;
|
||||
}
|
||||
|
||||
return tree;
|
||||
};
|
||||
|
||||
const generateAssetsObject = (tree: AssetsTree, indent = 0): string => {
|
||||
const spaces = " ".repeat(indent);
|
||||
const entries = Object.entries(tree);
|
||||
if (!entries.length) return "{}";
|
||||
|
||||
const lines = entries.map(([key, value]) =>
|
||||
typeof value === "string"
|
||||
? `${spaces} ${key}: createImage("${value}"),`
|
||||
: `${spaces} ${key}: ${generateAssetsObject(value, indent + 1)},`,
|
||||
);
|
||||
|
||||
return `{\n${lines.join("\n")}\n${spaces}}`;
|
||||
};
|
||||
|
||||
const generateAssetsFile = async () => {
|
||||
try {
|
||||
if (!existsSync(publicImagesDir)) {
|
||||
logger.warn("No public/images directory found");
|
||||
return;
|
||||
}
|
||||
|
||||
const images = await scanDirectory(publicImagesDir);
|
||||
const assetsTree = buildAssetsTree(images, publicImagesDir);
|
||||
const assetsObject = generateAssetsObject(assetsTree);
|
||||
|
||||
const template = await readFile(templateFile, "utf-8");
|
||||
const fileContent = template
|
||||
.replace("{{TOTAL}}", images.length.toString())
|
||||
.replace("{{ASSETS}}", assetsObject);
|
||||
|
||||
await writeFile(outputFile, fileContent, "utf-8");
|
||||
logger.success(`Generated useAssets.ts with ${images.length} images`);
|
||||
} catch (error) {
|
||||
logger.error("Error generating assets file:", error);
|
||||
}
|
||||
};
|
||||
|
||||
nuxt.hook("build:before", async () => {
|
||||
await generateAssetsFile();
|
||||
});
|
||||
|
||||
if (nuxt.options.dev) {
|
||||
nuxt.hook("ready", () => {
|
||||
watch(publicImagesDir, { recursive: true }, async (_, filePath) => {
|
||||
if (filePath && isImageFile(filePath)) {
|
||||
logger.info(`Detected change: ${filePath}`);
|
||||
await generateAssetsFile();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -7,6 +7,7 @@ export default defineNuxtConfig({
|
||||
"@nuxt/content",
|
||||
"@pinia/nuxt",
|
||||
"./modules/content-assets",
|
||||
"./modules/image-assets",
|
||||
"@nuxtjs/i18n",
|
||||
"@tresjs/nuxt",
|
||||
],
|
||||
|
||||
|
Before Width: | Height: | Size: 102 B After Width: | Height: | Size: 102 B |
|
Before Width: | Height: | Size: 438 B After Width: | Height: | Size: 438 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 110 B After Width: | Height: | Size: 110 B |
|
Before Width: | Height: | Size: 236 B After Width: | Height: | Size: 236 B |
|
Before Width: | Height: | Size: 334 B After Width: | Height: | Size: 334 B |
|
Before Width: | Height: | Size: 60 B After Width: | Height: | Size: 60 B |
|
Before Width: | Height: | Size: 176 B After Width: | Height: | Size: 176 B |
|
Before Width: | Height: | Size: 44 B After Width: | Height: | Size: 44 B |
|
Before Width: | Height: | Size: 180 B After Width: | Height: | Size: 180 B |
|
Before Width: | Height: | Size: 132 B After Width: | Height: | Size: 132 B |
|
Before Width: | Height: | Size: 66 B After Width: | Height: | Size: 66 B |
|
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 350 B |
|
Before Width: | Height: | Size: 80 B After Width: | Height: | Size: 80 B |
|
Before Width: | Height: | Size: 470 B After Width: | Height: | Size: 470 B |
|
Before Width: | Height: | Size: 296 B After Width: | Height: | Size: 296 B |
|
Before Width: | Height: | Size: 108 B After Width: | Height: | Size: 108 B |
|
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 68 B |
|
Before Width: | Height: | Size: 98 B After Width: | Height: | Size: 98 B |
|
Before Width: | Height: | Size: 302 B After Width: | Height: | Size: 302 B |
|
Before Width: | Height: | Size: 90 B After Width: | Height: | Size: 90 B |
|
Before Width: | Height: | Size: 122 B After Width: | Height: | Size: 122 B |
|
Before Width: | Height: | Size: 398 B After Width: | Height: | Size: 398 B |
|
Before Width: | Height: | Size: 104 B After Width: | Height: | Size: 104 B |
|
Before Width: | Height: | Size: 84 B After Width: | Height: | Size: 84 B |
|
Before Width: | Height: | Size: 88 B After Width: | Height: | Size: 88 B |
|
Before Width: | Height: | Size: 160 B After Width: | Height: | Size: 160 B |
BIN
public/images/projects/biobleud.webp
Normal file
|
After Width: | Height: | Size: 58 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 392 B |
|
Before Width: | Height: | Size: 376 B After Width: | Height: | Size: 376 B |
|
Before Width: | Height: | Size: 198 B After Width: | Height: | Size: 198 B |
|
Before Width: | Height: | Size: 174 B After Width: | Height: | Size: 174 B |
|
Before Width: | Height: | Size: 178 B After Width: | Height: | Size: 178 B |
|
Before Width: | Height: | Size: 178 B After Width: | Height: | Size: 178 B |
BIN
public/images/projects/lbf-bot.webp
Normal file
|
After Width: | Height: | Size: 456 B |
BIN
public/images/projects/lilou-cat.webp
Normal file
|
After Width: | Height: | Size: 598 B |
BIN
public/images/projects/pihkaal-me.webp
Normal file
|
After Width: | Height: | Size: 442 B |
BIN
public/images/projects/raylib-speedruns.webp
Normal file
|
After Width: | Height: | Size: 478 B |
BIN
public/images/projects/s3pweb.webp
Normal file
|
After Width: | Height: | Size: 624 B |
BIN
public/images/projects/simple-qr.webp
Normal file
|
After Width: | Height: | Size: 910 B |
BIN
public/images/projects/tlock.webp
Normal file
|
After Width: | Height: | Size: 660 B |
|
Before Width: | Height: | Size: 1010 B After Width: | Height: | Size: 1010 B |
|
Before Width: | Height: | Size: 148 B After Width: | Height: | Size: 148 B |
|
Before Width: | Height: | Size: 106 B After Width: | Height: | Size: 106 B |
|
Before Width: | Height: | Size: 438 B After Width: | Height: | Size: 438 B |
|
Before Width: | Height: | Size: 322 B After Width: | Height: | Size: 322 B |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 336 B After Width: | Height: | Size: 336 B |
|
Before Width: | Height: | Size: 318 B After Width: | Height: | Size: 318 B |
|
Before Width: | Height: | Size: 362 B After Width: | Height: | Size: 362 B |
|
Before Width: | Height: | Size: 146 B After Width: | Height: | Size: 146 B |
|
Before Width: | Height: | Size: 334 B After Width: | Height: | Size: 334 B |
|
Before Width: | Height: | Size: 374 B After Width: | Height: | Size: 374 B |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 322 B After Width: | Height: | Size: 322 B |
|
Before Width: | Height: | Size: 266 B After Width: | Height: | Size: 266 B |
|
Before Width: | Height: | Size: 220 B After Width: | Height: | Size: 220 B |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 254 B After Width: | Height: | Size: 254 B |
|
Before Width: | Height: | Size: 342 B After Width: | Height: | Size: 342 B |