summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-02-28 12:48:42 +1100
committer2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-02-28 12:48:42 +1100
commit5cf36b005814ee254271648691513d5361096649 (patch)
treee8dea19f804586b07f6804b9bf2366d7303fb624
parentlauncher: made search bar + mode switcher (diff)
downloadcaelestia-shell-5cf36b005814ee254271648691513d5361096649.tar.gz
caelestia-shell-5cf36b005814ee254271648691513d5361096649.tar.bz2
caelestia-shell-5cf36b005814ee254271648691513d5361096649.zip
launcher: apps mode
-rw-r--r--scss/launcher.scss64
-rw-r--r--src/modules/launcher.tsx82
-rw-r--r--src/utils/widgets.ts7
3 files changed, 136 insertions, 17 deletions
diff --git a/scss/launcher.scss b/scss/launcher.scss
index c2175e7..7535699 100644
--- a/scss/launcher.scss
+++ b/scss/launcher.scss
@@ -1,3 +1,4 @@
+@use "sass:color";
@use "scheme";
@use "lib";
@use "font";
@@ -14,8 +15,19 @@
}
}
- .mode-switcher .mode.selected {
- border-top: lib.s(2) solid $colour;
+ .mode-switcher .mode {
+ &.selected {
+ border-top: lib.s(2) solid $colour;
+ }
+
+ &:hover,
+ &:focus {
+ color: $colour;
+ }
+
+ &:active {
+ color: color.mix($colour, scheme.$base, 80%);
+ }
}
}
}
@@ -32,14 +44,14 @@
min-width: lib.s(700);
min-height: lib.s(420);
- @include lib.spacing(20, true);
-
@include launcher(apps, scheme.$sapphire);
@include launcher(files, scheme.$peach);
@include launcher(math, scheme.$green);
@include launcher(windows, scheme.$teal);
.search-bar {
+ margin-bottom: lib.s(15);
+
@include lib.spacing(10);
.mode {
@@ -55,23 +67,61 @@
border-top: lib.s(2) solid transparent;
padding-top: lib.s(10);
+
+ .icon {
+ font-size: lib.s(24);
+ }
+
+ & > box {
+ @include lib.spacing(10);
+ }
}
.result {
@include lib.element-decel;
- padding: lib.s(5) lib.s(10);
+ .icon {
+ font-size: lib.s(32);
+ }
+ }
- &:hover,
- &:focus {
+ .apps .result {
+ border-bottom: lib.s(2) solid transparent;
+ padding-left: lib.s(10);
+
+ & > box {
+ @include lib.spacing(10);
+ }
+
+ &:hover {
background-color: scheme.$surface0;
}
+ &:focus {
+ border-bottom: lib.s(2) solid scheme.$red;
+ color: scheme.$red;
+ }
+
&:active {
background-color: scheme.$surface1;
}
}
+ // .result {
+ // @include lib.element-decel;
+
+ // padding: lib.s(5) lib.s(10);
+
+ // &:hover,
+ // &:focus {
+ // background-color: scheme.$surface0;
+ // }
+
+ // &:active {
+ // background-color: scheme.$surface1;
+ // }
+ // }
+
.pinned-app {
@include lib.rounded(5);
diff --git a/src/modules/launcher.tsx b/src/modules/launcher.tsx
index 356b6d4..b6af58e 100644
--- a/src/modules/launcher.tsx
+++ b/src/modules/launcher.tsx
@@ -1,6 +1,11 @@
+import { Apps as AppsService } from "@/services/apps";
+import { getAppCategoryIcon } from "@/utils/icons";
+import { launch } from "@/utils/system";
+import { FlowBox } from "@/utils/widgets";
import PopupWindow from "@/widgets/popupwindow";
import { bind, register, Variable } from "astal";
-import { Astal, Gtk, Widget } from "astal/gtk3";
+import { App, Astal, Gtk, Widget } from "astal/gtk3";
+import type AstalApps from "gi://AstalApps";
type Mode = "apps" | "files" | "math" | "windows";
@@ -9,25 +14,77 @@ interface ModeContent {
handleActivate(search: string): void;
}
+const close = () => App.get_window("launcher")?.hide();
+
+const getModeIcon = (mode: Mode) => {
+ if (mode === "apps") return "apps";
+ if (mode === "files") return "folder";
+ if (mode === "math") return "calculate";
+ if (mode === "windows") return "select_window";
+ return "search";
+};
+
+const getPrettyMode = (mode: Mode) => {
+ if (mode === "apps") return "Apps";
+ if (mode === "files") return "Files";
+ if (mode === "math") return "Math";
+ if (mode === "windows") return "Windows";
+ return mode;
+};
+
+const AppResult = ({ app }: { app: AstalApps.Application }) => (
+ <Gtk.FlowBoxChild visible canFocus={false}>
+ <button
+ className="result"
+ cursor="pointer"
+ onClicked={() => {
+ launch(app);
+ close();
+ }}
+ >
+ <box>
+ {app.iconName && Astal.Icon.lookup_icon(app.iconName) ? (
+ <icon className="icon" icon={app.iconName} />
+ ) : (
+ <label className="icon" label={getAppCategoryIcon(app)} />
+ )}
+ <label truncate label={app.name} />
+ </box>
+ </button>
+ </Gtk.FlowBoxChild>
+);
+
@register()
class Apps extends Widget.Box implements ModeContent {
+ #content: FlowBox;
+
constructor() {
- super({ name: "apps" });
+ super({ name: "apps", className: "apps" });
+
+ this.#content = (<FlowBox homogeneous valign={Gtk.Align.START} maxChildrenPerLine={2} />) as FlowBox;
+
+ this.add(
+ <scrollable expand hscroll={Gtk.PolicyType.NEVER}>
+ {this.#content}
+ </scrollable>
+ );
}
updateContent(search: string): void {
- throw new Error("Method not implemented.");
+ this.#content.foreach(c => c.destroy());
+ AppsService.fuzzy_query(search).forEach(app => this.#content.add(<AppResult app={app} />));
}
- handleActivate(search: string): void {
- throw new Error("Method not implemented.");
+ handleActivate(): void {
+ this.#content.get_child_at_index(0)?.get_child()?.grab_focus();
+ this.#content.get_child_at_index(0)?.get_child()?.activate();
}
}
@register()
class Files extends Widget.Box implements ModeContent {
constructor() {
- super({ name: "files" });
+ super({ name: "files", className: "files" });
}
updateContent(search: string): void {
@@ -42,7 +99,7 @@ class Files extends Widget.Box implements ModeContent {
@register()
class Math extends Widget.Box implements ModeContent {
constructor() {
- super({ name: "math" });
+ super({ name: "math", className: "math" });
}
updateContent(search: string): void {
@@ -57,7 +114,7 @@ class Math extends Widget.Box implements ModeContent {
@register()
class Windows extends Widget.Box implements ModeContent {
constructor() {
- super({ name: "windows" });
+ super({ name: "windows", className: "windows" });
}
updateContent(search: string): void {
@@ -83,8 +140,12 @@ const ModeSwitcher = ({ mode, modes }: { mode: Variable<Mode>; modes: Mode[] })
className={bind(mode).as(c => `mode ${c === m ? "selected" : ""}`)}
cursor="pointer"
onClicked={() => mode.set(m)}
- label={m}
- />
+ >
+ <box halign={Gtk.Align.CENTER}>
+ <label className="icon" label={getModeIcon(m)} />
+ <label label={getPrettyMode(m)} />
+ </box>
+ </button>
))}
</box>
);
@@ -144,6 +205,7 @@ export default class Launcher extends PopupWindow {
this.mode = mode;
+ content[mode.get()].updateContent(entry.get_text());
this.hook(mode, (_, v: Mode) => {
entry.set_text("");
content[v].updateContent(entry.get_text());
diff --git a/src/utils/widgets.ts b/src/utils/widgets.ts
index 9802263..7b1eb5c 100644
--- a/src/utils/widgets.ts
+++ b/src/utils/widgets.ts
@@ -73,3 +73,10 @@ export class Calendar extends astalify(Gtk.Calendar) {
super(props as any);
}
}
+
+@register()
+export class FlowBox extends astalify(Gtk.FlowBox) {
+ constructor(props: ConstructProps<FlowBox, Gtk.FlowBox.ConstructorProps>) {
+ super(props as any);
+ }
+}