launcher: apps mode
This commit is contained in:
parent
73e7c08b8c
commit
5cf36b0058
3 changed files with 136 additions and 17 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
|
@use "sass:color";
|
||||||
@use "scheme";
|
@use "scheme";
|
||||||
@use "lib";
|
@use "lib";
|
||||||
@use "font";
|
@use "font";
|
||||||
|
|
@ -14,9 +15,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mode-switcher .mode.selected {
|
.mode-switcher .mode {
|
||||||
|
&.selected {
|
||||||
border-top: lib.s(2) solid $colour;
|
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-width: lib.s(700);
|
||||||
min-height: lib.s(420);
|
min-height: lib.s(420);
|
||||||
|
|
||||||
@include lib.spacing(20, true);
|
|
||||||
|
|
||||||
@include launcher(apps, scheme.$sapphire);
|
@include launcher(apps, scheme.$sapphire);
|
||||||
@include launcher(files, scheme.$peach);
|
@include launcher(files, scheme.$peach);
|
||||||
@include launcher(math, scheme.$green);
|
@include launcher(math, scheme.$green);
|
||||||
@include launcher(windows, scheme.$teal);
|
@include launcher(windows, scheme.$teal);
|
||||||
|
|
||||||
.search-bar {
|
.search-bar {
|
||||||
|
margin-bottom: lib.s(15);
|
||||||
|
|
||||||
@include lib.spacing(10);
|
@include lib.spacing(10);
|
||||||
|
|
||||||
.mode {
|
.mode {
|
||||||
|
|
@ -55,23 +67,61 @@
|
||||||
|
|
||||||
border-top: lib.s(2) solid transparent;
|
border-top: lib.s(2) solid transparent;
|
||||||
padding-top: lib.s(10);
|
padding-top: lib.s(10);
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: lib.s(24);
|
||||||
|
}
|
||||||
|
|
||||||
|
& > box {
|
||||||
|
@include lib.spacing(10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.result {
|
.result {
|
||||||
@include lib.element-decel;
|
@include lib.element-decel;
|
||||||
|
|
||||||
padding: lib.s(5) lib.s(10);
|
.icon {
|
||||||
|
font-size: lib.s(32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:hover,
|
.apps .result {
|
||||||
&:focus {
|
border-bottom: lib.s(2) solid transparent;
|
||||||
|
padding-left: lib.s(10);
|
||||||
|
|
||||||
|
& > box {
|
||||||
|
@include lib.spacing(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
background-color: scheme.$surface0;
|
background-color: scheme.$surface0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-bottom: lib.s(2) solid scheme.$red;
|
||||||
|
color: scheme.$red;
|
||||||
|
}
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
background-color: scheme.$surface1;
|
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 {
|
.pinned-app {
|
||||||
@include lib.rounded(5);
|
@include lib.rounded(5);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 PopupWindow from "@/widgets/popupwindow";
|
||||||
import { bind, register, Variable } from "astal";
|
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";
|
type Mode = "apps" | "files" | "math" | "windows";
|
||||||
|
|
||||||
|
|
@ -9,25 +14,77 @@ interface ModeContent {
|
||||||
handleActivate(search: string): void;
|
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()
|
@register()
|
||||||
class Apps extends Widget.Box implements ModeContent {
|
class Apps extends Widget.Box implements ModeContent {
|
||||||
|
#content: FlowBox;
|
||||||
|
|
||||||
constructor() {
|
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 {
|
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 {
|
handleActivate(): void {
|
||||||
throw new Error("Method not implemented.");
|
this.#content.get_child_at_index(0)?.get_child()?.grab_focus();
|
||||||
|
this.#content.get_child_at_index(0)?.get_child()?.activate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@register()
|
@register()
|
||||||
class Files extends Widget.Box implements ModeContent {
|
class Files extends Widget.Box implements ModeContent {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({ name: "files" });
|
super({ name: "files", className: "files" });
|
||||||
}
|
}
|
||||||
|
|
||||||
updateContent(search: string): void {
|
updateContent(search: string): void {
|
||||||
|
|
@ -42,7 +99,7 @@ class Files extends Widget.Box implements ModeContent {
|
||||||
@register()
|
@register()
|
||||||
class Math extends Widget.Box implements ModeContent {
|
class Math extends Widget.Box implements ModeContent {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({ name: "math" });
|
super({ name: "math", className: "math" });
|
||||||
}
|
}
|
||||||
|
|
||||||
updateContent(search: string): void {
|
updateContent(search: string): void {
|
||||||
|
|
@ -57,7 +114,7 @@ class Math extends Widget.Box implements ModeContent {
|
||||||
@register()
|
@register()
|
||||||
class Windows extends Widget.Box implements ModeContent {
|
class Windows extends Widget.Box implements ModeContent {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({ name: "windows" });
|
super({ name: "windows", className: "windows" });
|
||||||
}
|
}
|
||||||
|
|
||||||
updateContent(search: string): void {
|
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" : ""}`)}
|
className={bind(mode).as(c => `mode ${c === m ? "selected" : ""}`)}
|
||||||
cursor="pointer"
|
cursor="pointer"
|
||||||
onClicked={() => mode.set(m)}
|
onClicked={() => mode.set(m)}
|
||||||
label={m}
|
>
|
||||||
/>
|
<box halign={Gtk.Align.CENTER}>
|
||||||
|
<label className="icon" label={getModeIcon(m)} />
|
||||||
|
<label label={getPrettyMode(m)} />
|
||||||
|
</box>
|
||||||
|
</button>
|
||||||
))}
|
))}
|
||||||
</box>
|
</box>
|
||||||
);
|
);
|
||||||
|
|
@ -144,6 +205,7 @@ export default class Launcher extends PopupWindow {
|
||||||
|
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
|
|
||||||
|
content[mode.get()].updateContent(entry.get_text());
|
||||||
this.hook(mode, (_, v: Mode) => {
|
this.hook(mode, (_, v: Mode) => {
|
||||||
entry.set_text("");
|
entry.set_text("");
|
||||||
content[v].updateContent(entry.get_text());
|
content[v].updateContent(entry.get_text());
|
||||||
|
|
|
||||||
|
|
@ -73,3 +73,10 @@ export class Calendar extends astalify(Gtk.Calendar) {
|
||||||
super(props as any);
|
super(props as any);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@register()
|
||||||
|
export class FlowBox extends astalify(Gtk.FlowBox) {
|
||||||
|
constructor(props: ConstructProps<FlowBox, Gtk.FlowBox.ConstructorProps>) {
|
||||||
|
super(props as any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue