✨ feat(dashboard): add dashboard UI and functionality with Bluetooth and Network tiles
This commit is contained in:
6 files changed
+209
-410
No files matched your search
@@ -11,6 +11,7 @@
|
||||
@import url("./styles/calendar.css");
|
||||
@import url("./styles/notification.css");
|
||||
@import url("./styles/player.css");
|
||||
@import url("./styles/dashboard.css");
|
||||
|
||||
* {
|
||||
all: unset;
|
||||
@@ -69,204 +70,3 @@ tooltip > * {
|
||||
box-shadow: 0 0 3px alpha(black, 0.7);
|
||||
}
|
||||
|
||||
#dashboard-window {
|
||||
transition: margin 0.25s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
}
|
||||
#dashboard {
|
||||
background-color: black;
|
||||
border-radius: 25px;
|
||||
padding: 10px;
|
||||
}
|
||||
#inner {
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
.tile {
|
||||
margin: 2px;
|
||||
min-height: 60px;
|
||||
min-width: 140px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.tile.mini {
|
||||
min-height: 46px;
|
||||
min-width: 46px;
|
||||
border-radius: 100%;
|
||||
}
|
||||
.tile.on {
|
||||
background-color: var(--primary);
|
||||
}
|
||||
.tile.off {
|
||||
background-color: var(--surface-bright);
|
||||
}
|
||||
.tile.on .desc-label,
|
||||
.tile.on .tile-label,
|
||||
.tile.on .tile-icon {
|
||||
color: black;
|
||||
transition: all;
|
||||
}
|
||||
.tile.off .desc-label,
|
||||
.tile.off .tile-label,
|
||||
.tile.off .tile-icon {
|
||||
color: var(--foreground);
|
||||
transition: all;
|
||||
}
|
||||
|
||||
.tile-icon {
|
||||
font-size: 16px;
|
||||
margin: 10px;
|
||||
}
|
||||
.tile-icon.mini {
|
||||
font-size: 20px;
|
||||
transition: font-size 0.25s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
}
|
||||
.tile-icon.maxi {
|
||||
font-size: 16px;
|
||||
transition: font-size 0.25s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
}
|
||||
|
||||
.tile-button {
|
||||
all: unset;
|
||||
}
|
||||
|
||||
.tile-menu {
|
||||
all: unset;
|
||||
min-width: 400px;
|
||||
min-height: 300px;
|
||||
margin: -999px;
|
||||
}
|
||||
.tile-menu.expand {
|
||||
margin: 0px;
|
||||
transition: margin 0.15s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
}
|
||||
.tile-menu.contract {
|
||||
margin: -200px;
|
||||
transition: margin 0.25s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
#bluetooth-header,
|
||||
#network-header {
|
||||
border: 2px solid var(--surface);
|
||||
padding: 4px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
#bluetooth-device,
|
||||
#wifi-ap-slot {
|
||||
border: 2px solid var(--surface);
|
||||
border-radius: 12px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
#bluetooth-scan,
|
||||
#bluetooth-back,
|
||||
#network-refresh,
|
||||
#network-back {
|
||||
background-color: var(--surface);
|
||||
border-radius: 8px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
#bluetooth-back-label,
|
||||
#network-back-label {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
#bluetooth-scan:hover,
|
||||
#bluetooth-back:hover,
|
||||
#network-refresh:hover,
|
||||
#network-back:hover {
|
||||
background-color: var(--surface-bright);
|
||||
}
|
||||
|
||||
#bluetooth-scan label,
|
||||
#bluetooth-toggle label,
|
||||
#wifi-connect-button label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#bluetooth-text,
|
||||
#bluetooth-section {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#bluetooth-section {
|
||||
background-color: var(--surface);
|
||||
border-radius: 12px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
#bluetooth-connection {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
#bluetooth-connect,
|
||||
#wifi-connect-button {
|
||||
font-weight: bold;
|
||||
background-color: var(--surface);
|
||||
border-radius: 8px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
#wifi-connect-button.connected {
|
||||
background-color: var(--green);
|
||||
}
|
||||
|
||||
#wifi-connect-button.connected label {
|
||||
color: var(--shadow);
|
||||
}
|
||||
|
||||
#bluetooth-connect.connected {
|
||||
background-color: var(--blue);
|
||||
}
|
||||
|
||||
#bluetooth-connect.connected label {
|
||||
color: var(--shadow);
|
||||
}
|
||||
|
||||
#bluetooth-connect:hover {
|
||||
background-color: var(--surface-bright);
|
||||
}
|
||||
|
||||
#bluetooth-paired,
|
||||
#bluetooth-available {
|
||||
background-color: var(--surface);
|
||||
border-radius: 20px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
#bt-sep {
|
||||
/*padding: 1px;*/
|
||||
border-radius: 16px;
|
||||
/*background-color: var(--surface);*/
|
||||
/*margin: 0 16px;*/
|
||||
}
|
||||
|
||||
#bluetooth-scan-label,
|
||||
#network-refresh-label {
|
||||
font-size: 20px;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
#bluetooth-scan.scanning {
|
||||
animation: blink 0.5s ease infinite;
|
||||
}
|
||||
|
||||
#bluetooth-scan-label.scanning {
|
||||
animation: blink 0.5s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0% {
|
||||
background-color: var(--blue);
|
||||
color: var(--shadow);
|
||||
}
|
||||
50% {
|
||||
background-color: var(--shadow);
|
||||
color: var(--blue);
|
||||
}
|
||||
100% {
|
||||
background-color: var(--blue);
|
||||
color: var(--shadow);
|
||||
}
|
||||
}
|
||||
@@ -39,10 +39,9 @@ class BluetoothDeviceSlot(CenterBox):
|
||||
children=[
|
||||
Image(icon_name=device.icon_name + "-symbolic", size=16),
|
||||
Label(
|
||||
label=device.name,
|
||||
label=device.name[:8] + "..." if len(device.name) > 8 else device.name,
|
||||
h_expand=True,
|
||||
h_align="start",
|
||||
ellipsization="end",
|
||||
),
|
||||
self.connection_label,
|
||||
],
|
||||
|
||||
@@ -13,7 +13,7 @@ from utils.wayland import WaylandWindow as Window
|
||||
class Dashboard(Box):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(
|
||||
name="dashboard",
|
||||
name="dashboard-box",
|
||||
visible=True,
|
||||
orientation="v",
|
||||
spacing=8,
|
||||
@@ -31,10 +31,7 @@ class Dashboard(Box):
|
||||
self.wifi.dashboard_instance = self
|
||||
self.bluetooth.dashboard_instance = self
|
||||
|
||||
# Create real notifications component
|
||||
self.dashboard_notifications = DashboardNotifications()
|
||||
|
||||
# Track currently active tile
|
||||
self.active_tile = None
|
||||
|
||||
self.tiles = Box(
|
||||
@@ -117,9 +114,6 @@ class Dashboard(Box):
|
||||
self.content_stack.set_visible_child(self.default_content)
|
||||
print("Showing default content")
|
||||
|
||||
# Don't change tile visual states - keep all tiles unchanged
|
||||
print("Tile handling complete")
|
||||
|
||||
def reset_to_default(self):
|
||||
"""Reset dashboard to default state (notifications visible, no active tile)"""
|
||||
print("Resetting dashboard to default state")
|
||||
@@ -140,7 +134,7 @@ class DashboardWindow(Window):
|
||||
self.dashboard = Dashboard()
|
||||
|
||||
super().__init__(
|
||||
name="dashboard-window",
|
||||
name="dashboard",
|
||||
layer="top",
|
||||
anchor="bottom",
|
||||
exclusivity="none",
|
||||
|
||||
@@ -163,7 +163,12 @@ class Network(Tile):
|
||||
|
||||
if wifi and wifi.active_access_point:
|
||||
connected = True
|
||||
con_label = wifi.active_access_point.ssid
|
||||
# Hacky truncation: limit to 8 characters and add ellipsis
|
||||
ssid = wifi.active_access_point.ssid
|
||||
if len(ssid) > 8:
|
||||
con_label = ssid[:8] + "..."
|
||||
else:
|
||||
con_label = ssid
|
||||
elif wifi and not wifi.wireless_enabled:
|
||||
con_label = "Off"
|
||||
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
#dashboard-box {
|
||||
transition: margin 0.25s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
background-color: var(--shadow);
|
||||
border-radius: 25px;
|
||||
padding: 6px;
|
||||
margin-bottom: 65px;
|
||||
}
|
||||
|
||||
#inner {
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
.tile {
|
||||
margin: 0 6px;
|
||||
min-height: 60px;
|
||||
min-width: 140px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.tile.mini {
|
||||
min-height: 46px;
|
||||
min-width: 46px;
|
||||
border-radius: 100%;
|
||||
}
|
||||
.tile.on {
|
||||
background-color: var(--primary);
|
||||
}
|
||||
.tile.off {
|
||||
background-color: var(--surface-bright);
|
||||
}
|
||||
.tile.on .desc-label,
|
||||
.tile.on .tile-label,
|
||||
.tile.on .tile-icon {
|
||||
color: var(--shadow);
|
||||
transition: all;
|
||||
}
|
||||
.tile.off .desc-label,
|
||||
.tile.off .tile-label,
|
||||
.tile.off .tile-icon {
|
||||
color: var(--foreground);
|
||||
transition: all;
|
||||
}
|
||||
|
||||
.tile-icon {
|
||||
font-size: 18px;
|
||||
margin: 10px;
|
||||
}
|
||||
.tile-icon.mini {
|
||||
font-size: 20px;
|
||||
transition: font-size 0.25s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
}
|
||||
.tile-icon.maxi {
|
||||
font-size: 16px;
|
||||
transition: font-size 0.25s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
}
|
||||
|
||||
.tile-menu {
|
||||
margin: -999px;
|
||||
}
|
||||
.tile-menu.expand {
|
||||
margin: 0px;
|
||||
transition: margin 0.15s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
}
|
||||
.tile-menu.contract {
|
||||
margin: -200px;
|
||||
transition: margin 0.25s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
}
|
||||
|
||||
#bluetooth-header,
|
||||
#network-header {
|
||||
border: 2px solid var(--surface);
|
||||
padding: 4px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
#bluetooth-device,
|
||||
#wifi-ap-slot {
|
||||
border: 2px solid var(--surface);
|
||||
border-radius: 12px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
#bluetooth-scan,
|
||||
#bluetooth-back,
|
||||
#network-refresh,
|
||||
#network-back {
|
||||
background-color: var(--surface);
|
||||
border-radius: 8px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
#bluetooth-back-label,
|
||||
#network-back-label {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
#bluetooth-scan:hover,
|
||||
#bluetooth-back:hover,
|
||||
#network-refresh:hover,
|
||||
#network-back:hover {
|
||||
background-color: var(--surface-bright);
|
||||
}
|
||||
|
||||
#bluetooth-scan label,
|
||||
#bluetooth-toggle label,
|
||||
#wifi-connect-button label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#bluetooth-text,
|
||||
#bluetooth-section {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#bluetooth-section {
|
||||
background-color: var(--surface);
|
||||
border-radius: 12px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
#bluetooth-connection {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
#bluetooth-connect,
|
||||
#wifi-connect-button {
|
||||
font-weight: bold;
|
||||
background-color: var(--surface);
|
||||
border-radius: 8px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
#wifi-connect-button.connected {
|
||||
background-color: var(--green);
|
||||
}
|
||||
|
||||
#wifi-connect-button.connected label {
|
||||
color: var(--shadow);
|
||||
}
|
||||
|
||||
#bluetooth-connect.connected {
|
||||
background-color: var(--blue);
|
||||
}
|
||||
|
||||
#bluetooth-connect.connected label {
|
||||
color: var(--shadow);
|
||||
}
|
||||
|
||||
#bluetooth-connect:hover {
|
||||
background-color: var(--surface-bright);
|
||||
}
|
||||
|
||||
#bluetooth-paired,
|
||||
#bluetooth-available {
|
||||
background-color: var(--surface);
|
||||
border-radius: 20px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
#bt-sep {
|
||||
/*padding: 1px;*/
|
||||
border-radius: 16px;
|
||||
/*background-color: var(--surface);*/
|
||||
/*margin: 0 16px;*/
|
||||
}
|
||||
|
||||
#bluetooth-scan-label,
|
||||
#network-refresh-label {
|
||||
font-size: 20px;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
#bluetooth-scan.scanning {
|
||||
animation: blink 0.5s ease infinite;
|
||||
}
|
||||
|
||||
#bluetooth-scan-label.scanning {
|
||||
animation: blink 0.5s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0% {
|
||||
background-color: var(--blue);
|
||||
color: var(--shadow);
|
||||
}
|
||||
50% {
|
||||
background-color: var(--shadow);
|
||||
color: var(--blue);
|
||||
}
|
||||
100% {
|
||||
background-color: var(--blue);
|
||||
color: var(--shadow);
|
||||
}
|
||||
}
|
||||
+6
-198
@@ -1,160 +1,7 @@
|
||||
.player {
|
||||
/* background-color: aqua; */
|
||||
min-height: 100px;
|
||||
min-width: 400px;
|
||||
box-shadow:
|
||||
inset 0 100px 100px black,
|
||||
inset 10px 0px 10px rgba(0, 0, 0, 0.5),
|
||||
inset -10px 0px 10px rgba(0, 0, 0, 0.5);
|
||||
border-bottom-right-radius: 20px;
|
||||
border-bottom-left-radius: 20px;
|
||||
padding: 20px;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
.player.vertical {
|
||||
box-shadow:
|
||||
inset 100px 0px 150px black,
|
||||
inset 0px 10px 10px rgba(0, 0, 0, 0.5),
|
||||
inset 0px -10px 10px rgba(0, 0, 0, 0.5);
|
||||
border-top-right-radius: 20px;
|
||||
border-bottom-right-radius: 20px;
|
||||
min-width: 400px;
|
||||
min-height: 150px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.player-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
#artist {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
#song {
|
||||
color: whitesmoke;
|
||||
font-size: 16px;
|
||||
margin-top: 5px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
#wiggle-bar {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
#source {
|
||||
/* background-color: antiquewhite; */
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
#controls {
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
|
||||
#play-next,
|
||||
#play-previous {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
#progress {
|
||||
/* min-height: 1px; */
|
||||
background-color: antiquewhite;
|
||||
}
|
||||
|
||||
#pause-button {
|
||||
background-color: var(--surface);
|
||||
border-radius: 20px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
#pause-button.pause-track {
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
#pause-label,
|
||||
#play-label {
|
||||
color: var(--primary);
|
||||
font-size: 20px;
|
||||
padding: 2px;
|
||||
border-radius: 999px;
|
||||
min-width: 25px;
|
||||
}
|
||||
|
||||
#shuffle-button,
|
||||
#next-button,
|
||||
#prev-button {
|
||||
border: none;
|
||||
padding: 0px;
|
||||
padding-left: 11px;
|
||||
padding-right: 11px;
|
||||
}
|
||||
|
||||
#shuffle-button:hover,
|
||||
#next-button:hover,
|
||||
#prev-button:hover {
|
||||
background-color: var(--surface-bright);
|
||||
}
|
||||
|
||||
#shuffle {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.player-button {
|
||||
border-radius: 5px;
|
||||
/* background-color: var(--secondary); */
|
||||
background-color: white;
|
||||
opacity: 0.5;
|
||||
min-width: 10px;
|
||||
min-height: 10px;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
border: none;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.player-button.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#player-switch-container.vertical-player {
|
||||
margin-top: -23px;
|
||||
padding-bottom: 13px;
|
||||
}
|
||||
|
||||
#player-switch-container {
|
||||
margin-top: -18px;
|
||||
padding-bottom: 13px;
|
||||
}
|
||||
|
||||
#controls.vertical {
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
#disable-shuffle {
|
||||
font-size: 27px;
|
||||
}
|
||||
|
||||
#progress-slider {
|
||||
margin-left: -3px;
|
||||
margin-right: -2px;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#progress-other-end {
|
||||
min-width: 50px;
|
||||
}
|
||||
|
||||
.player-mini {
|
||||
min-height: 60px;
|
||||
min-width: 220px;
|
||||
min-width: 200px;
|
||||
padding-right: 20px;
|
||||
/* box-shadow: inset 0 0 100px rgb(148, 148, 148),
|
||||
inset 60px 0px 10px rgba(255, 255, 255, 1); */
|
||||
|
||||
box-shadow:
|
||||
inset 0 0 100px rgba(148, 148, 148, 0.3),
|
||||
@@ -177,34 +24,9 @@
|
||||
|
||||
.album-image {
|
||||
min-width: 65px;
|
||||
min-height: 60px;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
/* border-top-left-radius: 15px;
|
||||
border-bottom-left-radius: 15px; */
|
||||
border-radius: 15px;
|
||||
/* margin: 2px; */
|
||||
}
|
||||
|
||||
.hide-player {
|
||||
margin: -350px;
|
||||
transition: margin 0.25s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
/* animation: hidePlayer 0.5s ease; */
|
||||
}
|
||||
|
||||
@keyframes hidePlayer {
|
||||
0% {
|
||||
margin: 0px;
|
||||
}
|
||||
100% {
|
||||
margin: -999px;
|
||||
}
|
||||
}
|
||||
|
||||
.reveal-player {
|
||||
margin: 0px;
|
||||
transition: margin 0.25s cubic-bezier(0.5, 0.25, 0, 1);
|
||||
/* animation: revealPlayer 0.5s ease; */
|
||||
}
|
||||
|
||||
#artist {
|
||||
@@ -223,7 +45,7 @@
|
||||
}
|
||||
|
||||
#source {
|
||||
/* background-color: antiquewhite; */
|
||||
background-color: antiquewhite;
|
||||
margin-top: -10px;
|
||||
}
|
||||
#source.mini {
|
||||
@@ -233,11 +55,7 @@
|
||||
#controls {
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
#play-next,
|
||||
#play-previous {
|
||||
text-shadow: none;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
#play-next.mini,
|
||||
#play-previous.mini {
|
||||
text-shadow: none;
|
||||
@@ -249,13 +67,7 @@
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
#progress {
|
||||
/* min-height: 1px; */
|
||||
background-color: antiquewhite;
|
||||
}
|
||||
|
||||
#pause-button {
|
||||
/* background-color: var(--surface); */
|
||||
background-color: whitesmoke;
|
||||
border-radius: 16px;
|
||||
padding: 10px;
|
||||
@@ -312,7 +124,7 @@
|
||||
.player-button {
|
||||
border-radius: 5px;
|
||||
/* background-color: var(--secondary); */
|
||||
background-color: white;
|
||||
/* background-color: white; */
|
||||
opacity: 0.5;
|
||||
min-width: 10px;
|
||||
min-height: 10px;
|
||||
@@ -324,7 +136,7 @@
|
||||
|
||||
.player-button.mini {
|
||||
border-radius: 5px;
|
||||
background-color: var(--surface);
|
||||
background-color: var(--shadow);
|
||||
/* background-color: white; */
|
||||
opacity: 0.5;
|
||||
min-width: 10px;
|
||||
@@ -353,7 +165,7 @@
|
||||
|
||||
#player-switch-container.mini {
|
||||
margin-top: 0px;
|
||||
margin-left: -20px;
|
||||
margin-left: -18px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
@@ -362,10 +174,6 @@
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.player-icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.player-icon.mini {
|
||||
font-size: 20px;
|
||||
color: black;
|
||||
|
||||
Reference in new issue
Block a user