Skip to content

Commit 604341a

Browse files
authored
feat(tamagotchi): add "Pin on top" toggle to controls island (#1183)
\
1 parent 57b04d9 commit 604341a

File tree

8 files changed

+46
-2
lines changed

8 files changed

+46
-2
lines changed

apps/stage-tamagotchi/src/main/services/electron/window.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { defineInvokeHandler } from '@moeru/eventa'
55
import { bounds, startLoopGetBounds } from '@proj-airi/electron-eventa'
66
import { createRendererLoop } from '@proj-airi/electron-vueuse/main'
77

8-
import { electron, electronWindowClose } from '../../../shared/eventa'
8+
import { electron, electronWindowClose, electronWindowSetAlwaysOnTop } from '../../../shared/eventa'
99
import { onAppBeforeQuit, onAppWindowAllClosed } from '../../libs/bootkit/lifecycle'
1010
import { resizeWindowByDelta } from '../../windows/shared/window'
1111

@@ -46,6 +46,17 @@ export function createWindowService(params: { context: ReturnType<typeof createC
4646
}
4747
})
4848

49+
defineInvokeHandler(params.context, electronWindowSetAlwaysOnTop, (flag, options) => {
50+
if (params.window.webContents.id === options?.raw.ipcMainEvent.sender.id) {
51+
if (flag) {
52+
params.window.setAlwaysOnTop(true, 'screen-saver', 1)
53+
}
54+
else {
55+
params.window.setAlwaysOnTop(false)
56+
}
57+
}
58+
})
59+
4960
defineInvokeHandler(params.context, electron.window.setVibrancy, (vibrancy, options) => {
5061
if (vibrancy && params.window.webContents.id === options?.raw.ipcMainEvent.sender.id) {
5162
params.window.setVibrancy(vibrancy[0])

apps/stage-tamagotchi/src/renderer/components/stage-islands/controls-island/index.vue

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
electronOpenSettings,
2121
electronStartDraggingWindow,
2222
electronWindowClose,
23+
electronWindowSetAlwaysOnTop,
2324
} from '../../../../shared/eventa'
2425
2526
const { isDark, toggleDark } = useTheme()
@@ -29,11 +30,12 @@ const settingsAudioDeviceStore = useSettingsAudioDevice()
2930
const settingsStore = useSettings()
3031
const context = useElectronEventaContext()
3132
const { enabled } = storeToRefs(settingsAudioDeviceStore)
32-
const { controlsIslandIconSize } = storeToRefs(settingsStore)
33+
const { alwaysOnTop, controlsIslandIconSize } = storeToRefs(settingsStore)
3334
const openSettings = useElectronEventaInvoke(electronOpenSettings)
3435
const openChat = useElectronEventaInvoke(electronOpenChat)
3536
const isLinux = useElectronEventaInvoke(electron.app.isLinux)
3637
const closeWindow = useElectronEventaInvoke(electronWindowClose)
38+
const setAlwaysOnTop = useElectronEventaInvoke(electronWindowSetAlwaysOnTop)
3739
3840
const expanded = ref(false)
3941
const islandRef = ref<HTMLElement>()
@@ -53,6 +55,15 @@ useIntervalFn(() => {
5355
}
5456
}, 1500)
5557
58+
// Apply alwaysOnTop on mount and when it changes
59+
watch(alwaysOnTop, (val) => {
60+
setAlwaysOnTop(val)
61+
}, { immediate: true })
62+
63+
function toggleAlwaysOnTop() {
64+
alwaysOnTop.value = !alwaysOnTop.value
65+
}
66+
5667
// Grouped classes for icon / border / padding and combined style class
5768
const adjustStyleClasses = computed(() => {
5869
let isLarge: boolean
@@ -163,6 +174,16 @@ function refreshWindow() {
163174
</template>
164175
</ControlButtonTooltip>
165176

177+
<ControlButtonTooltip>
178+
<ControlButton :button-style="adjustStyleClasses.button" @click="toggleAlwaysOnTop()">
179+
<div v-if="alwaysOnTop" i-solar:pin-bold :class="adjustStyleClasses.icon" text="neutral-800 dark:neutral-300" />
180+
<div v-else i-solar:pin-linear :class="adjustStyleClasses.icon" text="neutral-800 dark:neutral-300 opacity-50" />
181+
</ControlButton>
182+
<template #tooltip>
183+
{{ alwaysOnTop ? t('tamagotchi.stage.controls-island.unpin-from-top') : t('tamagotchi.stage.controls-island.pin-on-top') }}
184+
</template>
185+
</ControlButtonTooltip>
186+
166187
<ControlsIslandFadeOnHover :icon-class="adjustStyleClasses.icon" :button-style="adjustStyleClasses.button" />
167188

168189
<ControlButtonTooltip>

apps/stage-tamagotchi/src/shared/eventa.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ export const widgetsFetch = defineInvokeEventa<WidgetSnapshot | void, { id: stri
197197
export const widgetsPrepareWindow = defineInvokeEventa<string | undefined, { id?: string }>('eventa:invoke:electron:windows:widgets:prepare')
198198

199199
export const electronWindowClose = defineInvokeEventa<void>('eventa:invoke:electron:window:close')
200+
export const electronWindowSetAlwaysOnTop = defineInvokeEventa<void, boolean>('eventa:invoke:electron:window:set-always-on-top')
200201
export const electronAppQuit = defineInvokeEventa<void>('eventa:invoke:electron:app:quit')
201202

202203
// Internal event from main -> widgets renderer when a widget should render

packages/i18n/src/locales/en/tamagotchi/stage.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ docs:
1919
'drag-to-move-window': Drag to move window
2020
'switch-to-light-mode': Switch to light mode
2121
'switch-to-dark-mode': Switch to dark mode
22+
'pin-on-top': Pin on top
23+
'unpin-from-top': Unpin from top
2224
'close': Close
2325
'expand': Expand
2426
'collapse': Collapse

packages/i18n/src/locales/ja/tamagotchi/stage.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ docs:
1919
'drag-to-move-window': ウィンドウをドラッグして移動
2020
'switch-to-light-mode': ライトモードに切り替え
2121
'switch-to-dark-mode': ダークモードに切り替え
22+
'pin-on-top': 最前面にピン留め
23+
'unpin-from-top': ピン留めを解除
2224
'close': Close
2325
'expand': Expand
2426
'collapse': Collapse

packages/i18n/src/locales/zh-Hans/tamagotchi/stage.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ docs:
1919
'drag-to-move-window': 拖动以移动窗口
2020
'switch-to-light-mode': 切换到亮色模式
2121
'switch-to-dark-mode': 切换到暗色模式
22+
'pin-on-top': 置顶显示
23+
'unpin-from-top': 取消置顶
2224
'close': 关闭
2325
'expand': 展开
2426
'collapse': 折叠

packages/stage-ui/src/stores/settings/controls-island.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
import { useLocalStorageManualReset } from '@proj-airi/stage-shared/composables'
22
import { defineStore } from 'pinia'
3+
import { ref } from 'vue'
34

45
export const useSettingsControlsIsland = defineStore('settings-controls-island', () => {
56
const allowVisibleOnAllWorkspaces = useLocalStorageManualReset<boolean>('settings/allow-visible-on-all-workspaces', true)
7+
const alwaysOnTop = useLocalStorageManualReset<boolean>('settings/always-on-top', true)
68
const controlsIslandIconSize = useLocalStorageManualReset<'auto' | 'large' | 'small'>('settings/controls-island/icon-size', 'auto')
79

810
function resetState() {
911
allowVisibleOnAllWorkspaces.reset()
12+
alwaysOnTop.value = true
1013
controlsIslandIconSize.reset()
1114
}
1215

1316
return {
1417
allowVisibleOnAllWorkspaces,
18+
alwaysOnTop,
1519
controlsIslandIconSize,
1620
resetState,
1721
}

packages/stage-ui/src/stores/settings/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export const useSettings = defineStore('settings', () => {
7373

7474
// UI settings
7575
allowVisibleOnAllWorkspaces: controlsIslandRefs.allowVisibleOnAllWorkspaces,
76+
alwaysOnTop: controlsIslandRefs.alwaysOnTop,
7677
controlsIslandIconSize: controlsIslandRefs.controlsIslandIconSize,
7778

7879
// Methods

0 commit comments

Comments
 (0)