Skip to content

Commit c75aec0

Browse files
committed
fix(#1266): power menu on multiple monitors
1 parent 1ab62fe commit c75aec0

7 files changed

Lines changed: 130 additions & 91 deletions

File tree

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
- external links not working.
2020
- wallpaper manager corner barder radius.
2121
- windows overlaping the toolbar and dock when autohide is disabled.
22+
- Power Menu not showing corrently on multiple monitors (#1266).
2223

2324
## [2.4.5]
2425

libs/core/src/system_state/monitors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use crate::{identifier_impl, rect::Rect};
22

33
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
4+
#[serde(rename_all = "camelCase")]
45
pub struct PhysicalMonitor {
56
pub id: MonitorId,
67
pub name: String,
78
pub rect: Rect,
89
pub dpi: f64,
10+
pub is_primary: bool,
911
}
1012

1113
#[derive(Debug, Serialize, Deserialize, TS)]

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/background/modules/monitors/domain.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ impl TryFrom<Monitor> for PhysicalMonitor {
1414
name: m.name()?,
1515
rect: m.rect()?,
1616
dpi,
17+
is_primary: m.is_primary(),
1718
})
1819
}
1920
}
Lines changed: 67 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,96 @@
11
// https://github.com/markdurrant/noisy-uris/tree/master
22
$base-noise-010: "data:image/png;base64,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";
33

4-
.power-menu {
4+
.power-menu-overlay {
55
width: 100vw;
66
height: 100vh;
7-
padding: 10vh 10vw 14vh;
87
background-image: url($base-noise-010);
98
background-color: #000d;
10-
color: #fcfcfc;
119

12-
display: flex;
13-
flex-direction: column;
14-
align-items: center;
15-
gap: 1rem;
10+
.power-menu {
11+
padding: 10% 10% 14%;
12+
color: #fcfcfc;
1613

17-
.power-menu-user {
1814
display: flex;
1915
flex-direction: column;
2016
align-items: center;
2117
gap: 1rem;
2218

23-
.power-menu-user-profile {
24-
width: 100px;
25-
height: 100px;
26-
border-radius: 50%;
27-
object-fit: cover;
28-
}
29-
30-
.power-menu-user-email {
31-
font-weight: 600;
32-
}
33-
}
34-
35-
.power-menu-bye-bye {
36-
font-size: 2rem;
37-
font-weight: 600;
38-
text-align: center;
39-
margin-bottom: 1rem;
40-
}
41-
42-
.power-menu-list {
43-
flex: 1;
44-
width: 100%;
45-
display: grid;
46-
grid-template-columns: repeat(3, 1fr);
47-
grid-template-rows: 1fr 1fr;
48-
gap: 20px;
49-
50-
.power-menu-item {
51-
position: relative;
52-
53-
width: 100%;
54-
height: 100%;
55-
border-radius: 16px;
56-
background-color: rgba(var(--system-accent-darker-color-rgb), 0.5);
57-
color: #fcfcfc;
58-
19+
.power-menu-user {
5920
display: flex;
6021
flex-direction: column;
6122
align-items: center;
62-
justify-content: center;
6323
gap: 1rem;
6424

65-
&:hover {
66-
background-color: rgba(var(--system-accent-dark-color-rgb), 0.5);
25+
.power-menu-user-profile {
26+
width: 100px;
27+
height: 100px;
28+
border-radius: 50%;
29+
object-fit: cover;
6730
}
6831

69-
&:active {
70-
background-color: rgba(var(--system-accent-dark-color-rgb), 0.5);
71-
transform: scale(0.95);
72-
}
73-
74-
&:focus-visible {
75-
outline: solid 2px #fcfcfc !important;
32+
.power-menu-user-email {
33+
font-weight: 600;
7634
}
35+
}
7736

78-
.slu-icon {
79-
height: 30% !important;
80-
}
37+
.power-menu-bye-bye {
38+
font-size: 2rem;
39+
font-weight: 600;
40+
text-align: center;
41+
margin-bottom: 1rem;
42+
}
8143

82-
.power-menu-item-label {
83-
font-size: 1.2rem;
84-
font-weight: 600;
44+
.power-menu-list {
45+
flex: 1;
46+
width: 100%;
47+
display: grid;
48+
grid-template-columns: repeat(3, 1fr);
49+
grid-template-rows: 1fr 1fr;
50+
gap: 20px;
51+
52+
.power-menu-item {
53+
position: relative;
54+
55+
width: 100%;
56+
height: 100%;
57+
border-radius: 16px;
58+
background-color: rgba(var(--system-accent-darker-color-rgb), 0.5);
59+
color: #fcfcfc;
60+
61+
display: flex;
62+
flex-direction: column;
63+
align-items: center;
64+
justify-content: center;
65+
gap: 1rem;
66+
67+
&:hover {
68+
background-color: rgba(var(--system-accent-dark-color-rgb), 0.5);
69+
}
70+
71+
&:active {
72+
background-color: rgba(var(--system-accent-dark-color-rgb), 0.5);
73+
transform: scale(0.95);
74+
}
75+
76+
&:focus-visible {
77+
outline: solid 2px #fcfcfc !important;
78+
}
79+
80+
.slu-icon {
81+
height: 30% !important;
82+
}
83+
84+
.power-menu-item-label {
85+
font-size: 1.2rem;
86+
font-weight: 600;
87+
}
8588
}
8689
}
87-
}
8890

89-
.power-menu-uptime {
90-
font-style: italic;
91-
font-size: 0.8rem;
91+
.power-menu-uptime {
92+
font-style: italic;
93+
font-size: 0.8rem;
94+
}
9295
}
9396
}

src/ui/svelte/power-menu/app.svelte

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<script>
1+
<script lang="ts">
22
import { onMount } from "svelte";
33
import { options } from "./options";
44
import { setup } from "./actions";
@@ -7,6 +7,7 @@
77
import Icon from "libs/ui/svelte/components/Icon/Icon.svelte";
88
import { Widget } from "@seelen-ui/lib";
99
import { t } from "./i18n";
10+
import { MissingIcon } from "libs/ui/svelte/components/Icon";
1011
1112
onMount(() => {
1213
setup(state);
@@ -15,41 +16,61 @@
1516
function onCancel() {
1617
Widget.getCurrent().webview.hide();
1718
}
19+
20+
const width = $derived(
21+
(state.menuRect.right - state.menuRect.left) / globalThis.devicePixelRatio
22+
);
23+
const height = $derived(
24+
(state.menuRect.bottom - state.menuRect.top) / globalThis.devicePixelRatio
25+
);
1826
</script>
1927

2028
<div
21-
class="power-menu"
29+
class="power-menu-overlay"
2230
role="menu"
2331
tabindex="-1"
24-
on:click={onCancel}
25-
on:keydown={(e) => {
32+
onclick={onCancel}
33+
onkeydown={(e) => {
2634
if (e.key === "Escape") {
2735
onCancel();
2836
}
2937
}}
3038
>
31-
<div class="power-menu-user">
32-
<img
33-
class="power-menu-user-profile"
34-
src={convertFileSrc(state.user.profilePicturePath)}
35-
alt=""
36-
/>
37-
<div class="power-menu-user-email">
38-
{state.user.email}
39+
<div
40+
class="power-menu"
41+
style:position="fixed"
42+
style:left="{state.menuRect.left / globalThis.devicePixelRatio}px"
43+
style:top="{state.menuRect.top / globalThis.devicePixelRatio}px"
44+
style:width="{width}px"
45+
style:height="{height}px"
46+
>
47+
<div class="power-menu-user">
48+
{#if state.user.profilePicturePath}
49+
<img
50+
class="power-menu-user-profile"
51+
src={convertFileSrc(state.user.profilePicturePath)}
52+
alt=""
53+
/>
54+
{:else}
55+
<MissingIcon class="power-menu-user-profile" />
56+
{/if}
57+
<div class="power-menu-user-email">
58+
{state.user.email}
59+
</div>
3960
</div>
61+
<div class="power-menu-bye-bye">{$t("goodbye", { 0: state.user.name })}</div>
62+
<ul class="power-menu-list">
63+
{#each options as option}
64+
<li>
65+
<button onclick={option.onClick} class="power-menu-item">
66+
<Icon iconName={option.icon as any} />
67+
<span class="power-menu-item-label">{$t(option.key)}</span>
68+
</button>
69+
</li>
70+
{/each}
71+
</ul>
72+
<!-- <div class="power-menu-uptime">{$t("uptime")}: 2 hours 30 minutes</div> -->
4073
</div>
41-
<div class="power-menu-bye-bye">{$t("goodbye", [state.user.name])}</div>
42-
<ul class="power-menu-list">
43-
{#each options as option}
44-
<li>
45-
<button on:click={option.onClick} class="power-menu-item">
46-
<Icon iconName={option.icon} />
47-
<span class="power-menu-item-label">{$t(option.key)}</span>
48-
</button>
49-
</li>
50-
{/each}
51-
</ul>
52-
<!-- <div class="power-menu-uptime">{$t("uptime")}: 2 hours 30 minutes</div> -->
5374
</div>
5475

5576
<style>

src/ui/svelte/power-menu/state.svelte.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ let desktopRect = $derived.by(() => {
2424
return rect;
2525
});
2626

27+
let menuRect = $derived.by(() => {
28+
let primary = monitors.find((m) => m.isPrimary);
29+
if (primary) {
30+
return primary.rect;
31+
}
32+
return desktopRect;
33+
});
34+
2735
let user = $state(await invoke(SeelenCommand.GetUser));
2836
subscribe(SeelenEvent.UserChanged, (e) => {
2937
user = e.payload;
@@ -37,6 +45,9 @@ export const state = {
3745
get desktopRect() {
3846
return desktopRect;
3947
},
48+
get menuRect() {
49+
return menuRect;
50+
},
4051
get user() {
4152
return user;
4253
},

0 commit comments

Comments
 (0)