This includes temporary AI-generated frontend scaffolding, none of this will be used in production. It was just used during development for the backend.
176 lines
5.2 KiB
Plaintext
176 lines
5.2 KiB
Plaintext
/// TEMPORARY AI GENERATED FRONTEND \\\
|
|
/// NOT TO BE USED IN PRODUCTION \\\
|
|
|
|
import { ListView } from "std-widgets.slint";
|
|
import { Theme } from "../theme.slint";
|
|
import { Icons } from "../icons.slint";
|
|
import { ChannelItem, ChannelKind } from "../types.slint";
|
|
import { Icon } from "icon.slint";
|
|
import { Avatar } from "avatar.slint";
|
|
import { Badge } from "badge.slint";
|
|
|
|
component ChannelRow inherits Rectangle {
|
|
in property <ChannelItem> c;
|
|
in property <bool> selected;
|
|
callback clicked();
|
|
|
|
height: c.kind == ChannelKind.category ? 34px : (c.is-dm ? 44px : 34px);
|
|
opacity: c.joined || c.kind == ChannelKind.category ? 1.0 : 0.5;
|
|
|
|
// --- category heading ("TEXT CHANNELS") ---
|
|
if c.kind == ChannelKind.category: Text {
|
|
x: 16px;
|
|
y: 0px;
|
|
width: parent.width - 32px;
|
|
height: parent.height - 4px;
|
|
text: c.name;
|
|
color: Theme.text-muted;
|
|
font-size: 12px;
|
|
font-weight: 700;
|
|
vertical-alignment: bottom;
|
|
overflow: elide;
|
|
}
|
|
|
|
// --- text / voice channel ---
|
|
if c.kind != ChannelKind.category && !c.is-dm: Rectangle {
|
|
x: 8px;
|
|
y: 1px;
|
|
width: parent.width - 16px;
|
|
height: parent.height - 2px;
|
|
border-radius: 4px;
|
|
background: root.selected ? Theme.selected-bg : (touch.has-hover ? Theme.hover-bg : transparent);
|
|
|
|
Icon {
|
|
source: c.kind == ChannelKind.voice ? Icons.speaker : Icons.hash;
|
|
tint: root.selected || c.unread ? Theme.text-header : Theme.text-muted;
|
|
icon-size: 18px;
|
|
x: 8px;
|
|
y: (parent.height - self.height) / 2;
|
|
}
|
|
|
|
Text {
|
|
x: 34px;
|
|
width: parent.width - 34px - (c.mentions > 0 ? 40px : 8px);
|
|
height: parent.height;
|
|
text: c.name;
|
|
color: root.selected || c.unread || touch.has-hover ? Theme.text-header : Theme.text-muted;
|
|
font-weight: c.unread ? 700 : 500;
|
|
vertical-alignment: center;
|
|
overflow: elide;
|
|
}
|
|
|
|
Badge {
|
|
count: c.mentions;
|
|
x: parent.width - self.width - 8px;
|
|
y: (parent.height - self.height) / 2;
|
|
}
|
|
}
|
|
|
|
// --- direct message ---
|
|
if c.is-dm && c.kind != ChannelKind.category: Rectangle {
|
|
x: 8px;
|
|
y: 1px;
|
|
width: parent.width - 16px;
|
|
height: parent.height - 2px;
|
|
border-radius: 4px;
|
|
background: root.selected ? Theme.selected-bg : (touch.has-hover ? Theme.hover-bg : transparent);
|
|
|
|
Avatar {
|
|
initial: c.initial;
|
|
tint: c.color;
|
|
diameter: 32px;
|
|
x: 8px;
|
|
y: (parent.height - self.height) / 2;
|
|
}
|
|
|
|
Text {
|
|
x: 50px;
|
|
width: parent.width - 50px - (c.mentions > 0 ? 40px : 8px);
|
|
height: parent.height;
|
|
text: c.name;
|
|
color: root.selected || c.unread || touch.has-hover ? Theme.text-header : Theme.text-muted;
|
|
font-weight: c.unread ? 700 : 500;
|
|
vertical-alignment: center;
|
|
overflow: elide;
|
|
}
|
|
|
|
Badge {
|
|
count: c.mentions;
|
|
x: parent.width - self.width - 8px;
|
|
y: (parent.height - self.height) / 2;
|
|
}
|
|
}
|
|
|
|
touch := TouchArea {
|
|
enabled: c.kind != ChannelKind.category;
|
|
mouse-cursor: pointer;
|
|
clicked => {
|
|
root.clicked();
|
|
}
|
|
}
|
|
}
|
|
|
|
export component ChannelList inherits Rectangle {
|
|
in property <string> title;
|
|
in property <bool> is-home;
|
|
in property <[ChannelItem]> channels;
|
|
in property <string> selected-id;
|
|
callback select(string);
|
|
callback open-server-menu();
|
|
|
|
width: Theme.sidebar-width;
|
|
background: Theme.sidebar-bg;
|
|
|
|
VerticalLayout {
|
|
// Header: server name (or "Direct Messages")
|
|
Rectangle {
|
|
height: Theme.header-height;
|
|
background: header-touch.has-hover && !root.is-home ? Theme.hover-bg : transparent;
|
|
|
|
Text {
|
|
x: 16px;
|
|
width: parent.width - 52px;
|
|
height: parent.height;
|
|
text: root.title;
|
|
color: Theme.text-header;
|
|
font-size: 15px;
|
|
font-weight: 700;
|
|
vertical-alignment: center;
|
|
overflow: elide;
|
|
}
|
|
|
|
if !root.is-home: Icon {
|
|
source: Icons.chevron-down;
|
|
tint: Theme.text-header;
|
|
icon-size: 16px;
|
|
x: parent.width - 16px - self.width;
|
|
y: (parent.height - self.height) / 2;
|
|
}
|
|
|
|
// bottom hairline
|
|
Rectangle {
|
|
y: parent.height - 1px;
|
|
height: 1px;
|
|
background: Theme.rail-bg;
|
|
}
|
|
|
|
header-touch := TouchArea {
|
|
enabled: !root.is-home;
|
|
clicked => {
|
|
root.open-server-menu();
|
|
}
|
|
}
|
|
}
|
|
|
|
ListView {
|
|
for c in root.channels: ChannelRow {
|
|
c: c;
|
|
selected: c.id == root.selected-id;
|
|
clicked => {
|
|
root.select(c.id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|