✨ feat(dashboard): add dashboard UI and functionality with Bluetooth and Network tiles

This commit is contained in:
sankalp committed 2025-07-27 12:06:05 +05:45
1 parent a85e606022
commit e61fadd43c
6 files changed
+209 -410

No files matched your search

+1 -201
View File
@@ -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);
}
}
+1 -2
View File
@@ -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,
],
+2 -8
View File
@@ -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",
+6 -1
View File
@@ -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"
+193
View File
@@ -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
View File
@@ -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;