Skip to content

Commit

Permalink
feat: mini tracker window snapping
Browse files Browse the repository at this point in the history
  • Loading branch information
Z233 committed Oct 4, 2023
1 parent 1dfac5c commit 9d3323d
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 28 deletions.
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,14 @@
"typescript": "5.1.6",
"unocss": "^0.55.4",
"vite": "^4.4.7",
"vite-plugin-singlefile": "^0.13.3",
"vite-plugin-windicss": "^1.8.10",
"windicss": "^3.5.6"
"vite-plugin-singlefile": "^0.13.3"
},
"dependencies": {
"@headlessui/react": "^1.7.16",
"@popperjs/core": "^2.11.6",
"@tanstack/react-table": "^8.7.9",
"@tgrosinger/md-advanced-tables": "^3.8.0",
"@unocss/reset": "^0.56.4",
"clsx": "^1.2.1",
"immer": "^9.0.19",
"jotai": "^2.3.1",
Expand Down
16 changes: 6 additions & 10 deletions src/platform/desktop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function desktopInit(plugin: SuperPlan) {

function miniTrackerInit(plugin: SuperPlan, tracker: PlanTracker) {
const { settings, store, manifest } = plugin
const open = settings.showMiniTracker
let open = settings.enableMiniTracker

const ribbonIconId = open ? 'alarm-clock-off' : 'alarm-clock'
const ribbon = plugin.addRibbonIcon(ribbonIconId, 'Toggle mini tracker', () => void 0)
Expand Down Expand Up @@ -75,14 +75,12 @@ function miniTrackerInit(plugin: SuperPlan, tracker: PlanTracker) {
ribbon.firstChild?.remove()
ribbon.appendChild(openedIconSVG)

plugin.settings.update({
showMiniTracker: true,
})

miniTracker.onClose(() => {
if (__DEV__) return
closeMiniTracker()
})

open = true
}

function closeMiniTracker() {
Expand All @@ -92,16 +90,14 @@ function miniTrackerInit(plugin: SuperPlan, tracker: PlanTracker) {
if (miniTracker?.isOpen) {
miniTracker?.close()
}

plugin.settings.update({
showMiniTracker: false,
})

open = false
}

if (open) showMiniTracker()

ribbon.onclick = () => {
if (settings.showMiniTracker) {
if (open) {
closeMiniTracker()
} else {
showMiniTracker()
Expand Down
2 changes: 0 additions & 2 deletions src/store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { atom, createStore } from 'jotai'
import { atomWithStorage } from 'jotai/utils'
import type SuperPlan from './main'
import type { ISettings } from './setting/settings'

Expand Down
87 changes: 80 additions & 7 deletions src/window/mini-tracker/MiniTrackerWindow.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import type { TrackerState } from 'src/tracker/plan-tracker'
import type { ScheduledActivity, Maybe } from 'src/types'
import MiniClock from './MiniClock.svelte'
import { onMount } from 'svelte'
let now: Maybe<ScheduledActivity> = null
let next: Maybe<ScheduledActivity> = null
let progress = 0
Expand All @@ -16,26 +17,98 @@
now = ongoing.activity
progress = ongoing.progress
}
if (upcoming) {
next = upcoming.activity
}
})
let snapped: 'l' | 'r' | null = null
let isViewingSnapped = false
const onSnappedViewStart = () => {
requestAnimationFrame(() => {
isViewingSnapped = true
})
ipcRenderer.send('snapped-view-start')
}
const onSnappedViewEnd = () => {
isViewingSnapped = false
ipcRenderer.send('snapped-view-end')
}
$: {
if (snapped) {
document.addEventListener('mouseenter', onSnappedViewStart)
document.addEventListener('mouseleave', onSnappedViewEnd)
} else {
document.removeEventListener('mouseenter', onSnappedViewStart)
document.removeEventListener('mouseleave', onSnappedViewEnd)
}
}
onMount(() => () => {
document.removeEventListener('mouseenter', onSnappedViewStart)
document.removeEventListener('mouseleave', onSnappedViewEnd)
})
ipcRenderer.on('snapped', (e, direction) => {
if (direction) {
snapped = direction
}
})
const handleSnapStop = () => {
snapped = null
ipcRenderer.send('snapped-stop')
}
</script>

<div class="w-full h-full grid place-content-center" style="-webkit-app-region: drag">
<div
class="w-full h-full grid place-content-center relative select-none"
style:-webkit-app-region={snapped ? 'no-drag' : 'drag'}
>
<div class="grid items-center space-x-3 grid-cols-4 px-4">
<div class="col-span-1">
<MiniClock {progress} size={36} />
</div>
<div class="col-span-3">
<div class="col-span-3 space-y-1">
<div class="text-gray-900 truncate">{now?.activity ?? 'No activity'}</div>
<div class="text-xs text-gray-400 truncate">
{next ? `Next: ${next.activity}` : 'All done'}
</div>
</div>
</div>
</div>

{#if snapped !== null && isViewingSnapped}
<div
on:click={handleSnapStop}
on:keypress={ e => e.key === 'Enter' ? handleSnapStop() : void 0 }
class="absolute h-full w-2 bg-gray-100 transition hover:bg-[hsla(254,80%,50%,1)] hover:shadow-md"
class:right-0={snapped === 'l'}
class:left-0={snapped === 'r'}
/>
{/if}


<style windi:preflights:global windi:safelist:global>
</style>
{#if snapped !== null && !isViewingSnapped}
<div
class="absolute h-full w-4 write-vertical-right text-xs place-content-center text-gray-800
tracking-widest text-shadow flex justify-center items-center"
class:left-0={snapped === 'r'}
class:right-0={snapped === 'l'}
class:rotate-180={snapped === 'l'}
class:animate-flash={progress >= 100}
class:!animate-[flash_1.5s_linear_infinite]={progress >= 100}
>
{#if progress > 0}
{Math.floor(progress)}<span class="mt-[.1rem]">%</span>
{:else}
<span class="text-[.6rem]">NONE</span>
{/if}
</div>
{/if}
</div>
2 changes: 2 additions & 0 deletions src/window/mini-tracker/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import MiniTrackerWindow from './MiniTrackerWindow.svelte'
import 'virtual:uno.css'
import '@unocss/reset/eric-meyer.css'

const window = new MiniTrackerWindow({
target: document.body,
Expand Down
86 changes: 80 additions & 6 deletions src/window/mini-tracker/mini-tracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ import type { Observer, PlanTracker } from 'src/tracker/plan-tracker'
import type { Maybe } from 'src/types'
import { getElectronAPI } from 'src/window/utils'

const SNAPPING_DISTANCE = 24
const SNAPPING_VISIBLE_EDGE = 16

const Size = {
WIDTH: 180,
HEIGHT: 60,
}

const defaultMiniTrackerData: MiniTrackerData = {
position: {},
}
Expand All @@ -15,6 +23,8 @@ export class MiniTracker {

private onCloseCallbacks: (() => void)[] = []

private isSnapping = false

private constructor(private store: DataStore, private tracker: PlanTracker) {}

static new(store: DataStore, tracker: PlanTracker) {
Expand All @@ -39,7 +49,7 @@ export class MiniTracker {
}

this.onCloseCallbacks.forEach((cb) => cb())

this.tracker.removeObserver(this.trackerObserver)
this.win?.removeAllListeners()
}
Expand All @@ -57,8 +67,8 @@ export class MiniTracker {
this.win = new BrowserWindow({
frame: false,
alwaysOnTop: true,
width: 180,
height: 60,
width: Size.WIDTH,
height: Size.HEIGHT,
hasShadow: true,
webPreferences: {
nodeIntegration: true,
Expand All @@ -73,15 +83,21 @@ export class MiniTracker {

if (__DEV__) {
this.win.loadURL(import.meta.env.VITE_DEV_SERVER_URL + 'window/mini-tracker/index.html')
// Enable DevTools
this.win.webContents.openDevTools()
this.win.webContents.executeJavaScript(
'console.log("%c====== MiniTracker DevTools ======", "color: red; font-size: 20px;")'
)
} else {
this.win.loadURL(`data:text/html;charset=UTF-8,__MINI_TRACKER_HTML__`)
}

this.tracker.addObserver(this.trackerObserver)

this.win.on('move', debounce(this.handleWindowMove, 500).bind(this))
this.win.on('moved', this.handleWindowMove.bind(this))
this.win.on('close', this.close.bind(this))

// Close Mini Tracker when Obsidian main window close
window.addEventListener('pagehide', (e) => {
MiniTracker.clean()
})
Expand All @@ -93,10 +109,68 @@ export class MiniTracker {
},
}

private handleWindowMove() {
private async handleWindowMove() {
if (!this.win) return
const { x, y } = this.win.getBounds()

const { x, y, width } = this.win.getBounds()

this.savePosition({ x, y })

// #region ==================== Snapping ====================

const { screen } = getElectronAPI()
const display = screen.getDisplayMatching(this.win.getBounds())
const { width: screenWidth } = display.bounds

let snapped: 'l' | 'r' | null = null

const snapToRight = () => this.win!.setPosition(screenWidth - SNAPPING_VISIBLE_EDGE, y, true)
const snapToLeft = () => this.win!.setPosition(SNAPPING_VISIBLE_EDGE - Size.WIDTH, y, true)
const makeAppRegionChangesWork = () => {
this.win!.setBounds({ width: width + 1 })
this.win!.setBounds({ width })
}

// Right
if (x >= screenWidth - Size.WIDTH + SNAPPING_DISTANCE) {
snapToRight()
snapped = 'r'
}
// Left
else if (x <= -SNAPPING_DISTANCE) {
snapToLeft()
snapped = 'l'
}

if (snapped) {
this.win.webContents.send('snapped', snapped)
makeAppRegionChangesWork()

this.win.webContents.on('ipc-message', (event, channel) => {
if (!this.win || snapped === null) return

if (channel === 'snapped-stop') {
snapped === 'l'
? this.win.setPosition(SNAPPING_VISIBLE_EDGE, y)
: this.win.setPosition(screenWidth - Size.WIDTH - SNAPPING_VISIBLE_EDGE, y)
snapped = null
}

if (channel === 'snapped-view-start') {
snapped === 'l'
? this.win.setPosition(0, y)
: this.win.setPosition(screenWidth - Size.WIDTH + SNAPPING_VISIBLE_EDGE, y)
}

if (channel === 'snapped-view-end') {
snapped === 'l'
? snapToLeft()
: snapToRight()
}
})
}

// #endregion
}

private async saveData(data: Partial<MiniTrackerData>) {
Expand Down
5 changes: 5 additions & 0 deletions vite.config.web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { isDev, r } from './scripts/utils'
import { windi } from 'svelte-windicss-preprocess'
import { join } from 'path'
import { viteSingleFile } from 'vite-plugin-singlefile'
import UnoCSS from 'unocss/vite'
import presetWind from 'unocss/preset-wind'

// https://vitejs.dev/config/
export default defineConfig({
Expand All @@ -28,5 +30,8 @@ export default defineConfig({
preprocess: [vitePreprocess(), windi({})],
}),
viteSingleFile(),
UnoCSS({
presets: [presetWind()],
})
],
})
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,11 @@
resolved "https://registry.yarnpkg.com/@unocss/reset/-/reset-0.55.4.tgz#9f038799ed62a0392e1c6c6d4360d2b4e4e4d6ac"
integrity sha512-USn/uZiXDplwQwhodyE3wBm7SU9BUDbRJ3sl5SuULAC4uMkh2JE/EV+X88Vm4N9dEIAbuWLfG20fCuiEKA5+hA==

"@unocss/reset@^0.56.4":
version "0.56.4"
resolved "https://registry.yarnpkg.com/@unocss/reset/-/reset-0.56.4.tgz#159237df367ede4f8f11c88d7e342c947dc3c1c8"
integrity sha512-7o3Jpog49ORWW+Rpz7bzYY+CStfLMyBXAeDOzhM2PQjftuQl4ZQOvIdXi6zrXDEN2SJQsi279s2t50ERZN8YcA==

"@unocss/scope@0.55.4":
version "0.55.4"
resolved "https://registry.yarnpkg.com/@unocss/scope/-/scope-0.55.4.tgz#bacc657b5ce7f7b815e36b537f41a2a066241ff8"
Expand Down

0 comments on commit 9d3323d

Please sign in to comment.