refactor(agsV2): abstract sorted-list code
All checks were successful
Discord / discord commits (push) Has been skipped
All checks were successful
Discord / discord commits (push) Has been skipped
This commit is contained in:
parent
ab6b00c259
commit
ccdde81356
8 changed files with 250 additions and 295 deletions
|
@ -17,6 +17,7 @@ window, viewport {
|
||||||
@import 'widgets/date/style.scss';
|
@import 'widgets/date/style.scss';
|
||||||
@import 'widgets/icon-browser/style.scss';
|
@import 'widgets/icon-browser/style.scss';
|
||||||
@import 'widgets/lockscreen/style.scss';
|
@import 'widgets/lockscreen/style.scss';
|
||||||
|
@import 'widgets/misc/style.scss';
|
||||||
@import 'widgets/notifs/style.scss';
|
@import 'widgets/notifs/style.scss';
|
||||||
@import 'widgets/powermenu/style.scss';
|
@import 'widgets/powermenu/style.scss';
|
||||||
@import 'widgets/screenshot/style.scss';
|
@import 'widgets/screenshot/style.scss';
|
||||||
|
|
|
@ -1,66 +1,36 @@
|
||||||
import { App, Astal, Gtk, Widget } from 'astal/gtk3';
|
import { App } from 'astal/gtk3';
|
||||||
import { idle } from 'astal';
|
|
||||||
|
|
||||||
import AstalApps from 'gi://AstalApps';
|
import AstalApps from 'gi://AstalApps';
|
||||||
|
|
||||||
import { Fzf, FzfResultItem } from 'fzf';
|
import SortedList from '../misc/sorted-list';
|
||||||
|
|
||||||
import PopupWindow from '../misc/popup-window';
|
|
||||||
import { centerCursor } from '../../lib';
|
|
||||||
|
|
||||||
import AppItemWidget, { AppItem } from './app-item';
|
|
||||||
import { launchApp } from './launch';
|
import { launchApp } from './launch';
|
||||||
|
import AppItemWidget, { AppItem } from './app-item';
|
||||||
|
|
||||||
|
|
||||||
export default () => {
|
export default () => SortedList({
|
||||||
let Applications: AstalApps.Application[] = [];
|
name: 'applauncher',
|
||||||
let fzfResults = [] as FzfResultItem<AstalApps.Application>[];
|
|
||||||
|
|
||||||
const list = new Gtk.ListBox({
|
create_list: () => AstalApps.Apps.new().get_list(),
|
||||||
selectionMode: Gtk.SelectionMode.SINGLE,
|
|
||||||
});
|
|
||||||
|
|
||||||
list.connect('row-activated', (_, row) => {
|
create_row: (app) => AppItemWidget({ app }),
|
||||||
|
|
||||||
|
fzf_options: {
|
||||||
|
selector: (app) => app.name + app.executable,
|
||||||
|
|
||||||
|
tiebreakers: [
|
||||||
|
(a, b) => b.item.frequency - a.item.frequency,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
on_row_activated: (row) => {
|
||||||
const app = (row.get_children()[0] as AppItem).app;
|
const app = (row.get_children()[0] as AppItem).app;
|
||||||
|
|
||||||
launchApp(app);
|
launchApp(app);
|
||||||
App.get_window('win-applauncher')?.set_visible(false);
|
App.get_window('win-applauncher')?.set_visible(false);
|
||||||
});
|
},
|
||||||
|
|
||||||
const placeholder = (
|
sort_func: (a, b, entry, fzfResults) => {
|
||||||
<revealer>
|
|
||||||
<label
|
|
||||||
label=" Couldn't find a match"
|
|
||||||
className="placeholder"
|
|
||||||
/>
|
|
||||||
</revealer>
|
|
||||||
) as Widget.Revealer;
|
|
||||||
|
|
||||||
const on_text_change = (text: string) => {
|
|
||||||
const fzf = new Fzf(Applications, {
|
|
||||||
selector: (app) => app.name + app.executable,
|
|
||||||
|
|
||||||
tiebreakers: [
|
|
||||||
(a, b) => b.item.frequency - a.item.frequency,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
fzfResults = fzf.find(text);
|
|
||||||
list.invalidate_sort();
|
|
||||||
|
|
||||||
const visibleApplications = list.get_children().filter((row) => row.visible).length;
|
|
||||||
|
|
||||||
placeholder.reveal_child = visibleApplications <= 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const entry = (
|
|
||||||
<entry
|
|
||||||
onChanged={(self) => on_text_change(self.text)}
|
|
||||||
hexpand
|
|
||||||
/>
|
|
||||||
) as Widget.Entry;
|
|
||||||
|
|
||||||
list.set_sort_func((a, b) => {
|
|
||||||
const row1 = (a.get_children()[0] as AppItem).app;
|
const row1 = (a.get_children()[0] as AppItem).app;
|
||||||
const row2 = (b.get_children()[0] as AppItem).app;
|
const row2 = (b.get_children()[0] as AppItem).app;
|
||||||
|
|
||||||
|
@ -79,72 +49,5 @@ export default () => {
|
||||||
|
|
||||||
return s2 - s1;
|
return s2 - s1;
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
});
|
||||||
const refreshApplications = () => idle(() => {
|
|
||||||
(list.get_children() as Gtk.ListBoxRow[])
|
|
||||||
.forEach((child) => {
|
|
||||||
child.destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
Applications = AstalApps.Apps.new().get_list();
|
|
||||||
|
|
||||||
Applications
|
|
||||||
.flatMap((app) => AppItemWidget({ app }))
|
|
||||||
.forEach((child) => {
|
|
||||||
list.add(child);
|
|
||||||
});
|
|
||||||
|
|
||||||
list.show_all();
|
|
||||||
on_text_change('');
|
|
||||||
});
|
|
||||||
|
|
||||||
refreshApplications();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PopupWindow
|
|
||||||
name="applauncher"
|
|
||||||
keymode={Astal.Keymode.ON_DEMAND}
|
|
||||||
on_open={() => {
|
|
||||||
entry.text = '';
|
|
||||||
centerCursor();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<box
|
|
||||||
vertical
|
|
||||||
className="applauncher"
|
|
||||||
>
|
|
||||||
<box className="widget app-search">
|
|
||||||
|
|
||||||
<icon icon="preferences-system-search-symbolic" />
|
|
||||||
|
|
||||||
{entry}
|
|
||||||
|
|
||||||
<button
|
|
||||||
css="margin-left: 5px;"
|
|
||||||
cursor="pointer"
|
|
||||||
onButtonReleaseEvent={refreshApplications}
|
|
||||||
>
|
|
||||||
<icon icon="view-refresh-symbolic" css="font-size: 26px;" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
</box>
|
|
||||||
|
|
||||||
<eventbox cursor="pointer">
|
|
||||||
<scrollable
|
|
||||||
className="widget app-list"
|
|
||||||
|
|
||||||
css="min-height: 600px; min-width: 600px;"
|
|
||||||
hscroll={Gtk.PolicyType.NEVER}
|
|
||||||
vscroll={Gtk.PolicyType.AUTOMATIC}
|
|
||||||
>
|
|
||||||
<box vertical>
|
|
||||||
{list}
|
|
||||||
{placeholder}
|
|
||||||
</box>
|
|
||||||
</scrollable>
|
|
||||||
</eventbox>
|
|
||||||
</box>
|
|
||||||
</PopupWindow>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,32 +1,6 @@
|
||||||
.applauncher {
|
.applauncher {
|
||||||
.app-search {
|
.app {
|
||||||
icon {
|
margin: 20px;
|
||||||
font-size: 20px;
|
font-size: 16px;
|
||||||
min-width: 40px;
|
|
||||||
min-height: 40px
|
|
||||||
}
|
|
||||||
|
|
||||||
entry {}
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-list {
|
|
||||||
row {
|
|
||||||
border-radius: 10px;
|
|
||||||
|
|
||||||
&:hover, &:selected {
|
|
||||||
icon {
|
|
||||||
-gtk-icon-shadow: 2px 2px $accent_color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.app {
|
|
||||||
margin: 20px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder {
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +1,29 @@
|
||||||
import { Astal, Gtk, Widget } from 'astal/gtk3';
|
import { Gtk, Widget } from 'astal/gtk3';
|
||||||
import { idle } from 'astal';
|
|
||||||
|
|
||||||
import { Fzf, FzfResultItem } from 'fzf';
|
import SortedList from '../misc/sorted-list';
|
||||||
|
|
||||||
import PopupWindow from '../misc/popup-window';
|
|
||||||
import { centerCursor } from '../../lib';
|
|
||||||
|
|
||||||
|
|
||||||
export default () => {
|
export default () => SortedList({
|
||||||
let Icons: string[] = [];
|
name: 'icon-browser',
|
||||||
let fzfResults = [] as FzfResultItem<string>[];
|
|
||||||
|
|
||||||
const list = new Gtk.ListBox({
|
create_list: () => Gtk.IconTheme.get_default().list_icons(null)
|
||||||
selectionMode: Gtk.SelectionMode.SINGLE,
|
.filter((icon) => icon.endsWith('symbolic'))
|
||||||
});
|
.sort(),
|
||||||
|
|
||||||
list.connect('row-activated', (_, row) => {
|
create_row: (icon) => (
|
||||||
|
<box>
|
||||||
|
<icon css="font-size: 60px; margin-right: 25px;" icon={icon} />
|
||||||
|
<label label={icon} />
|
||||||
|
</box>
|
||||||
|
),
|
||||||
|
|
||||||
|
on_row_activated: (row) => {
|
||||||
const icon = ((row.get_children()[0] as Widget.Box).get_children()[0] as Widget.Icon).icon;
|
const icon = ((row.get_children()[0] as Widget.Box).get_children()[0] as Widget.Icon).icon;
|
||||||
|
|
||||||
console.log(icon);
|
console.log(icon);
|
||||||
});
|
},
|
||||||
|
|
||||||
const placeholder = (
|
sort_func: (a, b, entry, fzfResults) => {
|
||||||
<revealer>
|
|
||||||
<label
|
|
||||||
label=" Couldn't find a match"
|
|
||||||
className="placeholder"
|
|
||||||
/>
|
|
||||||
</revealer>
|
|
||||||
) as Widget.Revealer;
|
|
||||||
|
|
||||||
const on_text_change = (text: string) => {
|
|
||||||
const fzf = new Fzf(Icons);
|
|
||||||
|
|
||||||
fzfResults = fzf.find(text);
|
|
||||||
list.invalidate_sort();
|
|
||||||
|
|
||||||
const visibleIcons = list.get_children().filter((row) => row.visible).length;
|
|
||||||
|
|
||||||
placeholder.reveal_child = visibleIcons <= 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const entry = (
|
|
||||||
<entry
|
|
||||||
onChanged={(self) => on_text_change(self.text)}
|
|
||||||
hexpand
|
|
||||||
/>
|
|
||||||
) as Widget.Entry;
|
|
||||||
|
|
||||||
list.set_sort_func((a, b) => {
|
|
||||||
const row1 = ((a.get_children()[0] as Widget.Box).get_children()[0] as Widget.Icon).icon;
|
const row1 = ((a.get_children()[0] as Widget.Box).get_children()[0] as Widget.Icon).icon;
|
||||||
const row2 = ((b.get_children()[0] as Widget.Box).get_children()[0] as Widget.Icon).icon;
|
const row2 = ((b.get_children()[0] as Widget.Box).get_children()[0] as Widget.Icon).icon;
|
||||||
|
|
||||||
|
@ -67,76 +42,5 @@ export default () => {
|
||||||
|
|
||||||
return s2 - s1;
|
return s2 - s1;
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
});
|
||||||
const refreshIcons = () => idle(() => {
|
|
||||||
(list.get_children() as Gtk.ListBoxRow[])
|
|
||||||
.forEach((child) => {
|
|
||||||
child.destroy();
|
|
||||||
});
|
|
||||||
|
|
||||||
Icons = Gtk.IconTheme.get_default().list_icons(null)
|
|
||||||
.filter((icon) => icon.endsWith('symbolic'))
|
|
||||||
.sort();
|
|
||||||
|
|
||||||
Icons
|
|
||||||
.flatMap((icon) => (
|
|
||||||
<box>
|
|
||||||
<icon css="font-size: 60px; margin-right: 25px;" icon={icon} />
|
|
||||||
<label label={icon} />
|
|
||||||
</box>
|
|
||||||
))
|
|
||||||
.forEach((child) => {
|
|
||||||
list.add(child);
|
|
||||||
});
|
|
||||||
|
|
||||||
list.show_all();
|
|
||||||
on_text_change('');
|
|
||||||
});
|
|
||||||
|
|
||||||
refreshIcons();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PopupWindow
|
|
||||||
name="icon-browser"
|
|
||||||
keymode={Astal.Keymode.ON_DEMAND}
|
|
||||||
on_open={() => {
|
|
||||||
entry.text = '';
|
|
||||||
centerCursor();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<box
|
|
||||||
vertical
|
|
||||||
className="icon-browser"
|
|
||||||
>
|
|
||||||
<box className="widget icon-search">
|
|
||||||
|
|
||||||
<icon icon="preferences-system-search-symbolic" />
|
|
||||||
|
|
||||||
{entry}
|
|
||||||
|
|
||||||
<button
|
|
||||||
css="margin-left: 5px;"
|
|
||||||
onButtonReleaseEvent={refreshIcons}
|
|
||||||
>
|
|
||||||
<icon icon="view-refresh-symbolic" css="font-size: 26px;" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
</box>
|
|
||||||
|
|
||||||
<scrollable
|
|
||||||
className="widget icon-list"
|
|
||||||
|
|
||||||
css="min-height: 600px; min-width: 600px;"
|
|
||||||
hscroll={Gtk.PolicyType.NEVER}
|
|
||||||
vscroll={Gtk.PolicyType.AUTOMATIC}
|
|
||||||
>
|
|
||||||
<box vertical>
|
|
||||||
{list}
|
|
||||||
{placeholder}
|
|
||||||
</box>
|
|
||||||
</scrollable>
|
|
||||||
</box>
|
|
||||||
</PopupWindow>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,32 +1,4 @@
|
||||||
.icon-browser {
|
.icon-browser .icon-list row box {
|
||||||
.icon-search {
|
margin: 20px;
|
||||||
icon {
|
font-size: 16px;
|
||||||
font-size: 20px;
|
|
||||||
min-width: 40px;
|
|
||||||
min-height: 40px
|
|
||||||
}
|
|
||||||
|
|
||||||
entry {}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-list {
|
|
||||||
row {
|
|
||||||
border-radius: 10px;
|
|
||||||
|
|
||||||
&:hover, &:selected {
|
|
||||||
icon {
|
|
||||||
-gtk-icon-shadow: 2px 2px $accent_color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
box {
|
|
||||||
margin: 20px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder {
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@ import { get_hyprland_monitor, hyprMessage } from '../../lib';
|
||||||
type CloseType = 'none' | 'stay' | 'released' | 'clicked';
|
type CloseType = 'none' | 'stay' | 'released' | 'clicked';
|
||||||
type HyprTransition = 'slide' | 'slide top' | 'slide bottom' | 'slide left' |
|
type HyprTransition = 'slide' | 'slide top' | 'slide bottom' | 'slide left' |
|
||||||
'slide right' | 'popin' | 'fade';
|
'slide right' | 'popin' | 'fade';
|
||||||
type PopupCallback = (self: PopupWindow) => void;
|
type PopupCallback = (self?: Widget.Window) => void;
|
||||||
|
|
||||||
type PopupWindowProps = Widget.WindowProps & {
|
export type PopupWindowProps = Widget.WindowProps & {
|
||||||
transition?: HyprTransition | Binding<HyprTransition>
|
transition?: HyprTransition | Binding<HyprTransition>
|
||||||
close_on_unfocus?: CloseType | Binding<CloseType>
|
close_on_unfocus?: CloseType | Binding<CloseType>
|
||||||
on_open?: PopupCallback
|
on_open?: PopupCallback
|
||||||
|
|
174
nixosModules/ags/v2/widgets/misc/sorted-list.tsx
Normal file
174
nixosModules/ags/v2/widgets/misc/sorted-list.tsx
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
// This is definitely not good practice but I couldn't figure out how to extend PopupWindow
|
||||||
|
// so here we are with a cursed function that returns a prop of the class.
|
||||||
|
|
||||||
|
import { Astal, Gtk, Widget } from 'astal/gtk3';
|
||||||
|
import { idle } from 'astal';
|
||||||
|
|
||||||
|
import { Fzf, FzfOptions, FzfResultItem } from 'fzf';
|
||||||
|
|
||||||
|
import PopupWindow, { PopupWindow as PopupWindowClass } from '../misc/popup-window';
|
||||||
|
import { centerCursor } from '../../lib';
|
||||||
|
|
||||||
|
export interface SortedListProps<T> {
|
||||||
|
create_list: () => T[]
|
||||||
|
create_row: (item: T) => Gtk.Widget
|
||||||
|
fzf_options?: FzfOptions<T>
|
||||||
|
on_row_activated: (row: Gtk.ListBoxRow) => void
|
||||||
|
sort_func: (
|
||||||
|
a: Gtk.ListBoxRow,
|
||||||
|
b: Gtk.ListBoxRow,
|
||||||
|
entry: Widget.Entry,
|
||||||
|
fzf: FzfResultItem<T>[],
|
||||||
|
) => number
|
||||||
|
name: string
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export class SortedList<T> {
|
||||||
|
private item_list: T[] = [];
|
||||||
|
private fzf_results: FzfResultItem<T>[] = [];
|
||||||
|
|
||||||
|
readonly window: PopupWindowClass;
|
||||||
|
|
||||||
|
readonly create_list: () => T[];
|
||||||
|
readonly create_row: (item: T) => Gtk.Widget;
|
||||||
|
readonly fzf_options: FzfOptions<T> | undefined;
|
||||||
|
|
||||||
|
readonly on_row_activated: (row: Gtk.ListBoxRow) => void;
|
||||||
|
|
||||||
|
readonly sort_func: (
|
||||||
|
a: Gtk.ListBoxRow,
|
||||||
|
b: Gtk.ListBoxRow,
|
||||||
|
entry: Widget.Entry,
|
||||||
|
fzf: FzfResultItem<T>[],
|
||||||
|
) => number;
|
||||||
|
|
||||||
|
|
||||||
|
constructor({
|
||||||
|
create_list,
|
||||||
|
create_row,
|
||||||
|
fzf_options,
|
||||||
|
on_row_activated,
|
||||||
|
sort_func,
|
||||||
|
name,
|
||||||
|
}: SortedListProps<T>) {
|
||||||
|
const list = new Gtk.ListBox({
|
||||||
|
selectionMode: Gtk.SelectionMode.SINGLE,
|
||||||
|
});
|
||||||
|
|
||||||
|
list.connect('row-activated', (_, row) => {
|
||||||
|
this.on_row_activated(row);
|
||||||
|
});
|
||||||
|
|
||||||
|
const placeholder = (
|
||||||
|
<revealer>
|
||||||
|
<label
|
||||||
|
label=" Couldn't find a match"
|
||||||
|
className="placeholder"
|
||||||
|
/>
|
||||||
|
</revealer>
|
||||||
|
) as Widget.Revealer;
|
||||||
|
|
||||||
|
const on_text_change = (text: string) => {
|
||||||
|
// @ts-expect-error this should be okay
|
||||||
|
this.fzf_results = (new Fzf(this.item_list, this.fzf_options)).find(text);
|
||||||
|
list.invalidate_sort();
|
||||||
|
|
||||||
|
const visibleApplications = list.get_children().filter((row) => row.visible).length;
|
||||||
|
|
||||||
|
placeholder.reveal_child = visibleApplications <= 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const entry = (
|
||||||
|
<entry
|
||||||
|
onChanged={(self) => on_text_change(self.text)}
|
||||||
|
hexpand
|
||||||
|
/>
|
||||||
|
) as Widget.Entry;
|
||||||
|
|
||||||
|
list.set_sort_func((a, b) => {
|
||||||
|
return this.sort_func(a, b, entry, this.fzf_results);
|
||||||
|
});
|
||||||
|
|
||||||
|
const refreshItems = () => idle(() => {
|
||||||
|
(list.get_children() as Gtk.ListBoxRow[])
|
||||||
|
.forEach((child) => {
|
||||||
|
child.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.item_list = this.create_list();
|
||||||
|
|
||||||
|
this.item_list
|
||||||
|
.flatMap((prop) => this.create_row(prop))
|
||||||
|
.forEach((child) => {
|
||||||
|
list.add(child);
|
||||||
|
});
|
||||||
|
|
||||||
|
list.show_all();
|
||||||
|
on_text_change('');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.window = (
|
||||||
|
<PopupWindow
|
||||||
|
name={name}
|
||||||
|
keymode={Astal.Keymode.ON_DEMAND}
|
||||||
|
on_open={() => {
|
||||||
|
entry.text = '';
|
||||||
|
centerCursor();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<box
|
||||||
|
vertical
|
||||||
|
className={`${name} sorted-list`}
|
||||||
|
>
|
||||||
|
<box className="widget search">
|
||||||
|
|
||||||
|
<icon icon="preferences-system-search-symbolic" />
|
||||||
|
|
||||||
|
{entry}
|
||||||
|
|
||||||
|
<button
|
||||||
|
css="margin-left: 5px;"
|
||||||
|
cursor="pointer"
|
||||||
|
onButtonReleaseEvent={refreshItems}
|
||||||
|
>
|
||||||
|
<icon icon="view-refresh-symbolic" css="font-size: 26px;" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</box>
|
||||||
|
|
||||||
|
<eventbox cursor="pointer">
|
||||||
|
<scrollable
|
||||||
|
className="widget list"
|
||||||
|
|
||||||
|
css="min-height: 600px; min-width: 600px;"
|
||||||
|
hscroll={Gtk.PolicyType.NEVER}
|
||||||
|
vscroll={Gtk.PolicyType.AUTOMATIC}
|
||||||
|
>
|
||||||
|
<box vertical>
|
||||||
|
{list}
|
||||||
|
{placeholder}
|
||||||
|
</box>
|
||||||
|
</scrollable>
|
||||||
|
</eventbox>
|
||||||
|
</box>
|
||||||
|
</PopupWindow>
|
||||||
|
) as PopupWindowClass;
|
||||||
|
|
||||||
|
this.create_list = create_list;
|
||||||
|
this.create_row = create_row;
|
||||||
|
this.fzf_options = fzf_options;
|
||||||
|
this.on_row_activated = on_row_activated;
|
||||||
|
this.sort_func = sort_func;
|
||||||
|
|
||||||
|
refreshItems();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param props props for a SortedList Widget
|
||||||
|
* @returns the widget
|
||||||
|
*/
|
||||||
|
export default function<Attr>(props: SortedListProps<Attr>) {
|
||||||
|
return (new SortedList(props)).window;
|
||||||
|
}
|
27
nixosModules/ags/v2/widgets/misc/style.scss
Normal file
27
nixosModules/ags/v2/widgets/misc/style.scss
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
.sorted-list {
|
||||||
|
.search {
|
||||||
|
icon {
|
||||||
|
font-size: 20px;
|
||||||
|
min-width: 40px;
|
||||||
|
min-height: 40px
|
||||||
|
}
|
||||||
|
|
||||||
|
entry {}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
row {
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
&:hover, &:selected {
|
||||||
|
icon {
|
||||||
|
-gtk-icon-shadow: 2px 2px $accent_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue