feat(stage-tamagotchi): inlay window & spotlight position calculation

This commit is contained in:
Neko Ayaka
2025-10-07 23:05:59 +08:00
parent f46774c576
commit a6265bbf87
6 changed files with 83 additions and 12 deletions
@@ -0,0 +1,69 @@
import { dirname, join, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { BrowserWindow, shell } from 'electron'
import { isMacOS } from 'std-env'
import icon from '../../../../resources/icon.png?asset'
import { baseUrl, load, withHashRoute } from '../../libs/electron/location'
import { currentDisplayBounds, mapForBreakpoints, resolutionBreakpoints, widthFrom } from '../shared/display'
import { spotlightLikeWindowConfig } from '../shared/window'
const __dirname = dirname(fileURLToPath(import.meta.url))
export async function setupInlayWindow() {
const window = new BrowserWindow({
title: 'Inlay',
width: 450,
height: 150,
show: false,
icon,
webPreferences: {
preload: join(dirname(fileURLToPath(import.meta.url)), '../preload/index.mjs'),
sandbox: false,
},
...spotlightLikeWindowConfig(),
})
if (isMacOS) {
window.setWindowButtonVisibility(false)
}
const displayBounds = currentDisplayBounds(window)
const width = mapForBreakpoints(
displayBounds.width,
{
'720p': widthFrom(displayBounds, { percentage: 1, max: { percentage: 0.5 } }),
'1080p': widthFrom(displayBounds, { percentage: 1, max: { percentage: 0.33 } }),
'2k': widthFrom(displayBounds, { percentage: 0.25, max: { actual: 710 } }),
'4k': widthFrom(displayBounds, { percentage: 0.2, max: { actual: 768 } }),
},
{ breakpoints: resolutionBreakpoints },
)
const height = width / 4
window.setBounds({
width,
height: width / 4,
x: displayBounds.x + (displayBounds.width - width) / 2, // Center horizontally
y: mapForBreakpoints(
displayBounds.height,
{
sm: displayBounds.height / 4 * 3 - height, // Bottom quarter, minus window height
md: displayBounds.height / 5 * 4 - height, // Center vertically
lg: displayBounds.height / 6 * 5 - height, // Top quarter, minus half window height
},
),
})
window.on('ready-to-show', () => window.show())
window.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url)
return { action: 'deny' }
})
await load(window, withHashRoute(baseUrl(resolve(__dirname, '..', '..', 'renderer')), '/inlay'))
return window
}
@@ -11,7 +11,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
export async function setupSettingsWindow() {
const window = new BrowserWindow({
title: 'AIRI',
title: 'Settings',
width: 600.0,
height: 800.0,
show: false,
@@ -13,12 +13,12 @@ const { platform } = useAppRuntime()
<div
bg="neutral-100 dark:neutral-900" w="100dvw"
top="0"
data-tauri-drag-region fixed z-100 w-full select-none py-2 pr-4
fixed z-100 w-full select-none py-2 pr-4 drag-region
:class="[
platform === 'macos' ? 'pl-20' : 'pl-4',
]"
>
<div data-tauri-drag-region flex>
<div flex drag-region>
<div
bg="hover:neutral-200 hover:dark:neutral-800"
transition="all duration-200 ease-in-out"
@@ -27,7 +27,7 @@ const { platform } = useAppRuntime()
<div :class="icon" select-none text="neutral-400 dark:neutral-500" whitespace-nowrap />
<div><span select-none whitespace-nowrap text-sm>{{ title }}</span></div>
</div>
<div data-tauri-drag-region w-full />
<div w-full drag-region />
<div
bg="hover:neutral-200 hover:dark:neutral-800"
transition="all duration-200 ease-in-out"
@@ -107,17 +107,17 @@ const modeIndicatorClass = computed(() => {
>
<div
v-if="windowControlStore.controlMode === WindowControlMode.MOVE"
class="drag-region absolute left-0 top-0 z-99 h-full w-full flex cursor-grab items-center justify-center overflow-hidden"
class="absolute left-0 top-0 z-99 h-full w-full flex cursor-grab items-center justify-center overflow-hidden drag-region"
>
<div
class="absolute h-32 w-full flex items-center justify-center overflow-hidden rounded-xl"
bg="white/80 dark:neutral-950/80" backdrop-blur="md"
>
<div class="wall absolute top-0 h-8" />
<div class="drag-region absolute left-0 top-0 h-full w-full flex animate-flash animate-duration-5s animate-count-infinite select-none items-center justify-center text-1.5rem text-primary-400 font-normal">
<div class="absolute left-0 top-0 h-full w-full flex animate-flash animate-duration-5s animate-count-infinite select-none items-center justify-center text-1.5rem text-primary-400 font-normal drag-region">
DRAG HERE TO MOVE
</div>
<div class="wall drag-region absolute bottom-0 h-8" />
<div class="wall absolute bottom-0 h-8 drag-region" />
</div>
</div>
</Transition>
@@ -139,10 +139,6 @@ const modeIndicatorClass = computed(() => {
</template>
<style scoped>
.drag-region {
app-region: drag;
}
.view {
transition: opacity 0.5s ease-in-out;
@@ -0,0 +1,6 @@
<template>
<div class="drag-region">
<h1>Spotlight</h1>
<p>This is the Spotlight page.</p>
</div>
</template>
@@ -19,7 +19,7 @@ function handleConfigured() {
<template>
<div h-full w-full flex flex-col overflow-x-hidden overflow-y-hidden overscroll-none>
<div bg="white dark:#181818" w="100dvw" min-h="12" data-tauri-drag-region w-full flex-shrink-0 select-none />
<div bg="white dark:#181818" w="100dvw" min-h="12" w-full flex-shrink-0 select-none data-tauri-drag-region />
<div w-full flex-1 overflow-y-scroll px-3>
<div h-full py-3>
<OnboardingScreen @skipped="handleSkipped" @configured="handleConfigured" />