This includes temporary AI-generated frontend scaffolding, none of this will be used in production. It was just used during development for the backend.
150 lines
4.6 KiB
Plaintext
150 lines
4.6 KiB
Plaintext
/// TEMPORARY AI GENERATED FRONTEND \\\
|
|
/// NOT TO BE USED IN PRODUCTION \\\
|
|
|
|
import { ScrollView } from "std-widgets.slint";
|
|
import { Theme } from "../theme.slint";
|
|
import { Icons } from "../icons.slint";
|
|
import { ServerItem } from "../types.slint";
|
|
import { Icon } from "icon.slint";
|
|
import { Badge } from "badge.slint";
|
|
|
|
// One round button on the rail. Morphs from circle to rounded square on hover
|
|
// or selection, with a white "pill" on the left edge.
|
|
component RailButton inherits Rectangle {
|
|
in property <bool> selected;
|
|
in property <bool> unread;
|
|
in property <int> mentions;
|
|
in property <color> idle-color: Theme.chat-bg;
|
|
in property <color> active-color: Theme.accent;
|
|
callback clicked();
|
|
|
|
height: 56px;
|
|
|
|
// Left-edge pill: tall = selected, medium = hovered, dot = unread.
|
|
Rectangle {
|
|
x: 0px;
|
|
width: 4px;
|
|
height: root.selected ? 40px : (touch.has-hover ? 20px : (root.unread ? 8px : 0px));
|
|
y: (parent.height - self.height) / 2;
|
|
border-top-right-radius: 4px;
|
|
border-bottom-right-radius: 4px;
|
|
background: Theme.text-header;
|
|
animate height { duration: 120ms; }
|
|
}
|
|
|
|
body := Rectangle {
|
|
width: 48px;
|
|
height: 48px;
|
|
x: (parent.width - self.width) / 2;
|
|
y: (parent.height - self.height) / 2;
|
|
clip: true;
|
|
border-radius: root.selected || touch.has-hover ? 16px : 24px;
|
|
background: root.selected || touch.has-hover ? root.active-color : root.idle-color;
|
|
animate border-radius { duration: 120ms; }
|
|
@children
|
|
}
|
|
|
|
Badge {
|
|
count: root.mentions;
|
|
x: body.x + body.width - self.width + 4px;
|
|
y: body.y + body.height - self.height + 4px;
|
|
}
|
|
|
|
touch := TouchArea {
|
|
mouse-cursor: pointer;
|
|
clicked => {
|
|
root.clicked();
|
|
}
|
|
}
|
|
}
|
|
|
|
export component ServerRail inherits Rectangle {
|
|
in property <[ServerItem]> servers;
|
|
in property <string> selected-id; // "" = Home (direct messages)
|
|
in property <bool> home-unread;
|
|
in property <int> home-mentions;
|
|
callback select(string);
|
|
callback add-server();
|
|
|
|
width: Theme.rail-width;
|
|
background: Theme.rail-bg;
|
|
|
|
ScrollView {
|
|
vertical-scrollbar-policy: always-off;
|
|
horizontal-scrollbar-policy: always-off;
|
|
|
|
VerticalLayout {
|
|
padding-top: 8px;
|
|
padding-bottom: 8px;
|
|
alignment: start;
|
|
|
|
RailButton {
|
|
selected: root.selected-id == "";
|
|
unread: root.home-unread;
|
|
mentions: root.home-mentions;
|
|
clicked => {
|
|
root.select("");
|
|
}
|
|
Icon {
|
|
source: Icons.chat;
|
|
tint: white;
|
|
icon-size: 26px;
|
|
// `parent` here is the rail layout (children are projected into RailButton),
|
|
// so centre against the button's fixed 48px body instead.
|
|
x: (48px - self.width) / 2;
|
|
y: (48px - self.height) / 2;
|
|
}
|
|
}
|
|
|
|
// separator
|
|
Rectangle {
|
|
height: 10px;
|
|
Rectangle {
|
|
width: 32px;
|
|
height: 2px;
|
|
x: (parent.width - self.width) / 2;
|
|
y: 4px;
|
|
border-radius: 1px;
|
|
background: Theme.divider;
|
|
}
|
|
}
|
|
|
|
for s in root.servers: RailButton {
|
|
selected: root.selected-id == s.id;
|
|
unread: s.unread;
|
|
mentions: s.mentions;
|
|
idle-color: s.color;
|
|
active-color: s.color;
|
|
clicked => {
|
|
root.select(s.id);
|
|
}
|
|
Text {
|
|
width: 48px;
|
|
height: 48px;
|
|
text: s.initial;
|
|
color: white;
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
}
|
|
}
|
|
|
|
RailButton {
|
|
idle-color: Theme.chat-bg;
|
|
active-color: Theme.success;
|
|
clicked => {
|
|
root.add-server();
|
|
}
|
|
Icon {
|
|
source: Icons.plus;
|
|
tint: Theme.success;
|
|
icon-size: 24px;
|
|
x: (48px - self.width) / 2;
|
|
y: (48px - self.height) / 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|