🌐 feat(i18n): add translations for media controls

This commit is contained in:
retrozinndev
2025-10-01 22:26:37 -03:00
parent 3c919c9bc9
commit c4eb2a84ef
14 changed files with 128 additions and 122 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
node_modules/ node_modules/
@girs/ @types/
build/ build/
pnpm-lock.yaml pnpm-lock.yaml
+1 -8
View File
@@ -40,10 +40,6 @@ else
mkdir -p $output mkdir -p $output
fi fi
# link node_modules to src, so ags(esbuild) knows there are modules to bundle
echo "[info] linking modules"
ln -s node_modules src/node_modules
echo "[info] compiling gresource" echo "[info] compiling gresource"
gres_target=`[[ "$keep_gresource" ]] && echo -n "$output/resources.gresource" || \ gres_target=`[[ "$keep_gresource" ]] && echo -n "$output/resources.gresource" || \
echo -n "${gresources_target:-$output/resources.gresource}"` echo -n "${gresources_target:-$output/resources.gresource}"`
@@ -53,12 +49,9 @@ glib-compile-resources resources.gresource.xml \
--target "$gres_target" --target "$gres_target"
echo "[info] bundling project" echo "[info] bundling project"
ags bundle src/app.ts $output/colorshell \ ags --gtk 4 bundle src/app.ts $output/colorshell \
-r ./src \ -r ./src \
-d "DEVEL=`[[ $is_devel ]] && echo -n true || echo -n false`" \ -d "DEVEL=`[[ $is_devel ]] && echo -n true || echo -n false`" \
-d "COLORSHELL_VERSION='`cat package.json | jq -r .version`'" \ -d "COLORSHELL_VERSION='`cat package.json | jq -r .version`'" \
-d "GRESOURCES_FILE='${gresources_target:-$output/resources.gresource}'" \ -d "GRESOURCES_FILE='${gresources_target:-$output/resources.gresource}'" \
|| rm -rf src/node_modules || rm -rf src/node_modules
echo "[info] cleaning"
rm -rf src/node_modules
+1 -1
View File
@@ -5,4 +5,4 @@ fi
echo "Building types, this can take long..." echo "Building types, this can take long..."
pnpx @ts-for-gir/cli generate --ignoreVersionConflicts -o ./@girs pnpx @ts-for-gir/cli generate --ignoreVersionConflicts
+1 -5
View File
@@ -1,7 +1,3 @@
// fix ags needing --gtk 4
// import app from "ags/gtk4/app";
// fix can't convert non-null pointer to JS value (thanks Aylur!)
import "ags/overrides"; import "ags/overrides";
import "./config"; import "./config";
import { import {
@@ -29,13 +25,13 @@ import { setConsoleLogDomain } from "console";
import { initPlayer } from "./modules/media"; import { initPlayer } from "./modules/media";
import { createSubscription, encoder, secureBaseBinding } from "./modules/utils"; import { createSubscription, encoder, secureBaseBinding } from "./modules/utils";
import { exec } from "ags/process"; import { exec } from "ags/process";
import { NightLight } from "./modules/nightlight";
import { Backlights } from "./modules/backlight"; import { Backlights } from "./modules/backlight";
import GObject, { register } from "ags/gobject"; import GObject, { register } from "ags/gobject";
import GLib from "gi://GLib?version=2.0"; import GLib from "gi://GLib?version=2.0";
import Gio from "gi://Gio?version=2.0"; import Gio from "gi://Gio?version=2.0";
import Adw from "gi://Adw?version=1"; import Adw from "gi://Adw?version=1";
import { NightLight } from "./modules/nightlight";
const runnerPlugins: Array<Runner.Plugin> = [ const runnerPlugins: Array<Runner.Plugin> = [
+4 -3
View File
@@ -48,11 +48,11 @@ const generalConfigDefaults = {
const userDataDefaults = { const userDataDefaults = {
/** last default adapter */ /** last default adapter */
bluetooth_default_adapter: undefined, bluetooth_default_adapter: undefined as unknown as string,
control_center: { control_center: {
/** last default backlight */ /** last default backlight */
default_backlight: undefined default_backlight: undefined as unknown as string
}, },
night_light: { night_light: {
@@ -75,5 +75,6 @@ export const userData = new Config<
export const generalConfig = new Config<keyof typeof generalConfigDefaults, export const generalConfig = new Config<keyof typeof generalConfigDefaults,
typeof generalConfigDefaults[keyof typeof generalConfigDefaults]>( typeof generalConfigDefaults[keyof typeof generalConfigDefaults]>(
`${GLib.get_user_config_dir()}/colorshell/config.json`, generalConfigDefaults `${GLib.get_user_config_dir()}/colorshell/config.json`,
generalConfigDefaults
); );
+15 -1
View File
@@ -20,7 +20,21 @@ export default {
connect: "Connect", connect: "Connect",
disconnect: "Disconnect", disconnect: "Disconnect",
copy_to_clipboard: "Copy to clipboard",
media: {
play: "Play",
pause: "Pause",
next: "Next",
previous: "Previous",
loop: "Loop",
no_loop: "No loop",
song_loop: "Loop song",
shuffle_order: "Shuffle",
follow_order: "Follow order",
no_artist: "No artist",
no_title: "No title"
},
control_center: { control_center: {
tiles: { tiles: {
enabled: "Enabled", enabled: "Enabled",
@@ -88,4 +102,4 @@ export default {
ask_popup: { ask_popup: {
title: "Question" title: "Question"
} }
} as i18nStruct; } satisfies i18nStruct;
+15 -1
View File
@@ -20,7 +20,21 @@ export default {
apps: "Aplicativos", apps: "Aplicativos",
clear: "Limpar", clear: "Limpar",
copy_to_clipboard: "Copiar para a Área de Transferência",
media: {
next: "Próxima faixa",
pause: "Pausar",
play: "Tocar",
previous: "Faixa anterior",
loop: "Repetir",
no_loop: "Não repetir",
song_loop: "Repetir faixa",
follow_order: "Seguir ordem",
shuffle_order: "Ordem aleatória",
no_title: "Sem título",
no_artist: "Sem artista"
},
control_center: { control_center: {
tiles: { tiles: {
enabled: "Ligado", enabled: "Ligado",
@@ -88,4 +102,4 @@ export default {
ask_popup: { ask_popup: {
title: "Pergunta" title: "Pergunta"
} }
} as i18nStruct; } satisfies i18nStruct;
+16 -2
View File
@@ -17,9 +17,23 @@ export type i18nStruct = {
disconnect: string, disconnect: string,
connect: string, connect: string,
apps: string; apps: string,
clear: string; clear: string,
copy_to_clipboard: string,
media: {
loop: string,
song_loop: string,
no_loop: string,
shuffle_order: string,
follow_order: string,
pause: string,
play: string,
next: string,
previous: string,
no_artist: string,
no_title: string
},
control_center: { control_center: {
tiles: { tiles: {
enabled: string, enabled: string,
+43 -1
View File
@@ -9,6 +9,14 @@ import AstalBluetooth from "gi://AstalBluetooth";
/** AstalBluetooth helper (implements the default adapter feature) */ /** AstalBluetooth helper (implements the default adapter feature) */
@register({ GTypeName: "Bluetooth" }) @register({ GTypeName: "Bluetooth" })
export class Bluetooth extends GObject.Object { export class Bluetooth extends GObject.Object {
declare $signals: {
"notify": () => void;
"notify::adapter": (adapter: AstalBluetooth.Adapter|null) => void;
"notify::is-available": (available: boolean) => void;
"notify::save-default-adapter": (save: boolean) => void;
"notify::last-device": (device: AstalBluetooth.Device|null) => void;
};
private static instance: Bluetooth; private static instance: Bluetooth;
private astalBl = AstalBluetooth.get_default(); private astalBl = AstalBluetooth.get_default();
@@ -16,11 +24,17 @@ export class Bluetooth extends GObject.Object {
#adapter: AstalBluetooth.Adapter|null = this.astalBl.adapter ?? null; #adapter: AstalBluetooth.Adapter|null = this.astalBl.adapter ?? null;
#scope!: Scope; #scope!: Scope;
#isAvailable: boolean = false; #isAvailable: boolean = false;
#lastDevice: AstalBluetooth.Device|null = null;
@property(Boolean)
saveDefaultAdapter: boolean = true;
@getter(Boolean) @getter(Boolean)
get isAvailable() { return this.#isAvailable; } get isAvailable() { return this.#isAvailable; }
@property(Boolean) saveDefaultAdapter = true; /** last connected device, can be null */
@getter(AstalBluetooth.Device)
get lastDevice() { return this.#lastDevice!; }
@getter(gtype<AstalBluetooth.Adapter|null>(AstalBluetooth.Adapter)) @getter(gtype<AstalBluetooth.Adapter|null>(AstalBluetooth.Adapter))
get adapter() { return this.#adapter; } get adapter() { return this.#adapter; }
@@ -94,6 +108,16 @@ export class Bluetooth extends GObject.Object {
] ]
); );
this.#lastDevice = this.getLastConnectedDevice();
this.notify("last-device");
this.#connections.set(AstalBluetooth.get_default(), [
AstalBluetooth.get_default().connect("notify::devices", (_) => {
this.#lastDevice = this.getLastConnectedDevice();
this.notify("last-device");
})
]);
this.#scope.onCleanup(() => this.#connections.forEach((ids, gobj) => this.#scope.onCleanup(() => this.#connections.forEach((ids, gobj) =>
Array.isArray(ids) ? Array.isArray(ids) ?
ids.forEach(id => gobj.disconnect(id)) ids.forEach(id => gobj.disconnect(id))
@@ -112,4 +136,22 @@ export class Bluetooth extends GObject.Object {
vfunc_dispose(): void { vfunc_dispose(): void {
this.#scope.dispose(); this.#scope.dispose();
} }
private getLastConnectedDevice(): AstalBluetooth.Device|null {
const connectedDevices = AstalBluetooth.get_default().devices
.filter(d => d.connected);
const lastDevice = connectedDevices[connectedDevices.length - 1];
console.log(`last device: ${lastDevice?.address}`);
return lastDevice ?? null;
}
connect<Signal extends keyof (typeof this)["$signals"]>(
signal: Signal, callback: (typeof this["$signals"])[Signal]
): number {
return super.connect(signal as string, callback as () => void);
}
} }
-71
View File
@@ -1,71 +0,0 @@
import GLib from "gi://GLib?version=2.0";
import GObject, { getter, property, register } from "ags/gobject";
/** WIP Global implementation of a system that supports
* a variety of Wayland Compositors */
export namespace Compositor {
let instance: _Compositor;
@register({ GTypeName: "CompositorMonitor" })
class _CompositorMonitor extends GObject.Object {
public readonly width: number;
public readonly height: number;
@property(Boolean)
public readonly mirror: boolean;
constructor(width: number, height: number, mirror: boolean = false) {
super();
this.width = width;
this.height = height;
this.mirror = mirror;
}
}
@register({ GTypeName: "CompositorWorkspace" })
class _CompositorWorkspace extends GObject.Object {
public readonly id: number;
@getter(_CompositorMonitor)
public readonly monitor: _CompositorMonitor;
constructor(monitor: _CompositorMonitor, id: number) {
super();
this.monitor = monitor;
this.id = id;
}
}
@register({ GTypeName: "Compositor" })
class _Compositor extends GObject.Object {
#workspaces: Array<_CompositorWorkspace> = [];
@property()
public get workspaces() { return this.#workspaces; }
};
export function getDefault(): _Compositor {
if(!instance)
instance = new _Compositor();
return instance;
}
export const Compositor = _Compositor,
CompositorWorkspace = _CompositorWorkspace,
CompositorMonitor = _CompositorMonitor;
/** Uses the XDG_CURRENT_DESKTOP variable to detect running compositor's name.
* ---
* @returns running wayland compositor's name (lowercase) or `undefined` if variable's not set */
export function getName(): string|undefined {
return GLib.getenv("XDG_CURRENT_DESKTOP") ?? undefined;
}
}
+3 -3
View File
@@ -2,7 +2,7 @@ import { timeout } from "ags/time";
import { monitorFile, readFileAsync, writeFileAsync } from "ags/file"; import { monitorFile, readFileAsync, writeFileAsync } from "ags/file";
import { Notifications } from "./notifications"; import { Notifications } from "./notifications";
import { Accessor } from "ags"; import { Accessor } from "ags";
import GObject, { getter, ParamSpec, register } from "ags/gobject"; import GObject, { getter, gtype, register } from "ags/gobject";
import Gio from "gi://Gio?version=2.0"; import Gio from "gi://Gio?version=2.0";
import AstalIO from "gi://AstalIO"; import AstalIO from "gi://AstalIO";
@@ -13,7 +13,7 @@ export { Config };
type ValueTypes = "string" | "boolean" | "object" | "number" | "any"; type ValueTypes = "string" | "boolean" | "object" | "number" | "any";
@register({ GTypeName: "Config" }) @register({ GTypeName: "Config" })
class Config<K extends NonNullable<string|number|symbol>, V extends string|object|any> extends GObject.Object { class Config<K extends string, V = any> extends GObject.Object {
declare $signals: GObject.Object.SignalSignatures & { declare $signals: GObject.Object.SignalSignatures & {
"notify::entries": (entries: Record<K, V>) => void; "notify::entries": (entries: Record<K, V>) => void;
}; };
@@ -22,7 +22,7 @@ class Config<K extends NonNullable<string|number|symbol>, V extends string|objec
* in the `entries` field */ * in the `entries` field */
public readonly defaults: Record<K, V>; public readonly defaults: Record<K, V>;
@getter(Object as unknown as ParamSpec<Record<K, V>>) @getter(gtype<Record<K, V>>(Object))
public get entries() { return this.#entries; } public get entries() { return this.#entries; }
#file: Gio.File; #file: Gio.File;
+11 -9
View File
@@ -9,6 +9,7 @@ import { accessMediaUrl, player, setPlayer } from "../../../modules/media";
import GObject from "ags/gobject"; import GObject from "ags/gobject";
import AstalMpris from "gi://AstalMpris"; import AstalMpris from "gi://AstalMpris";
import Pango from "gi://Pango?version=1.0"; import Pango from "gi://Pango?version=1.0";
import { tr } from "../../../i18n/intl";
export const Media = () => { export const Media = () => {
@@ -66,12 +67,12 @@ export const Media = () => {
createBinding(player.get(), "busName").as(getPlayerIconFromBusName)} createBinding(player.get(), "busName").as(getPlayerIconFromBusName)}
/> />
<Gtk.Label class={"title"} label={createBinding(player.get(), "title").as(title => <Gtk.Label class={"title"} label={createBinding(player.get(), "title").as(title =>
title ?? "No Title")} maxWidthChars={20} ellipsize={Pango.EllipsizeMode.END} title ?? tr("media.no_title"))} maxWidthChars={20} ellipsize={Pango.EllipsizeMode.END}
/> />
<Separator orientation={Gtk.Orientation.HORIZONTAL} size={1} margin={5} <Separator orientation={Gtk.Orientation.HORIZONTAL} size={1} margin={5}
alpha={.3} spacing={6} /> alpha={.3} spacing={6} />
<Gtk.Label class={"artist"} label={createBinding(player.get(), "artist").as(artist => <Gtk.Label class={"artist"} label={createBinding(player.get(), "artist").as(artist =>
artist ?? "No Artist")} maxWidthChars={18} ellipsize={Pango.EllipsizeMode.END} artist ?? tr("media.no_artist"))} maxWidthChars={18} ellipsize={Pango.EllipsizeMode.END}
/> />
</Gtk.Box>} </Gtk.Box>}
</With> </With>
@@ -84,7 +85,7 @@ export const Media = () => {
<Gtk.Box class={"extra button-row"}> <Gtk.Box class={"extra button-row"}>
<Gtk.Button class={"link"} iconName={"edit-paste-symbolic"} <Gtk.Button class={"link"} iconName={"edit-paste-symbolic"}
visible={variableToBoolean(accessMediaUrl(player.get()))} visible={variableToBoolean(accessMediaUrl(player.get()))}
tooltipText={"Copy link to Clipboard"} onClicked={() => { tooltipText={tr("copy_to_clipboard")} onClicked={() => {
const url = accessMediaUrl(player.get()).get(); const url = accessMediaUrl(player.get()).get();
url && Clipboard.getDefault().copyAsync(url); url && Clipboard.getDefault().copyAsync(url);
}} }}
@@ -92,20 +93,21 @@ export const Media = () => {
</Gtk.Box> </Gtk.Box>
<Gtk.Box class={"media-controls button-row"}> <Gtk.Box class={"media-controls button-row"}>
<Gtk.Button class={"previous"} iconName={"media-skip-backward-symbolic"} <Gtk.Button class={"previous"} iconName={"media-skip-backward-symbolic"}
tooltipText={"Previous"} onClicked={() => tooltipText={tr("media.previous")} onClicked={() =>
player.get().canGoPrevious && player.get().previous()} player.get().canGoPrevious && player.get().previous()}
/> />
<Gtk.Button class={"play-pause"} iconName={createBinding(player.get(), "playbackStatus").as(status => <Gtk.Button class={"play-pause"} iconName={createBinding(player.get(), "playbackStatus").as(status =>
status === AstalMpris.PlaybackStatus.PAUSED ? status === AstalMpris.PlaybackStatus.PAUSED ?
"media-playback-start-symbolic" "media-playback-start-symbolic"
: "media-playback-pause-symbolic")} : "media-playback-pause-symbolic")}
tooltipText={ tooltipText={createBinding(player.get(), "playbackStatus").as(status =>
createBinding(player.get(), "playbackStatus").as(status => status === AstalMpris.PlaybackStatus.PAUSED ?
status === AstalMpris.PlaybackStatus.PAUSED ? "Play" : "Pause") tr("media.play")
} onClicked={() => player.get().play_pause()} : tr("media.pause")
)} onClicked={() => player.get().play_pause()}
/> />
<Gtk.Button class={"next"} iconName={"media-skip-forward-symbolic"} <Gtk.Button class={"next"} iconName={"media-skip-forward-symbolic"}
tooltipText={"Next"} onClicked={() => player.get().canGoNext && tooltipText={tr("media.next")} onClicked={() => player.get().canGoNext &&
player.get().next()} player.get().next()}
/> />
</Gtk.Box> </Gtk.Box>
+15 -14
View File
@@ -5,6 +5,7 @@ import { Clipboard } from "../../../modules/clipboard";
import { accessMediaUrl } from "../../../modules/media"; import { accessMediaUrl } from "../../../modules/media";
import { player, setPlayer } from "../../../modules/media"; import { player, setPlayer } from "../../../modules/media";
import { pathToURI, variableToBoolean } from "../../../modules/utils"; import { pathToURI, variableToBoolean } from "../../../modules/utils";
import { tr } from "../../../i18n/intl";
import AstalMpris from "gi://AstalMpris"; import AstalMpris from "gi://AstalMpris";
import Pango from "gi://Pango?version=1.0"; import Pango from "gi://Pango?version=1.0";
@@ -31,7 +32,7 @@ export const BigMedia = () => {
</For> </For>
</Adw.Carousel> as Adw.Carousel; </Adw.Carousel> as Adw.Carousel;
return <Gtk.Box class={"big-media"} orientation={Gtk.Orientation.VERTICAL} widthRequest={255} return <Gtk.Box class={"big-media"} orientation={Gtk.Orientation.VERTICAL} widthRequest={270}
visible={variableToBoolean(availablePlayers)}> visible={variableToBoolean(availablePlayers)}>
{carousel} {carousel}
@@ -75,15 +76,15 @@ class PlayerWidget extends Gtk.Box {
valign={Gtk.Align.CENTER} vexpand hexpand> valign={Gtk.Align.CENTER} vexpand hexpand>
<Gtk.Label class={"title"} tooltipText={ <Gtk.Label class={"title"} tooltipText={
createBinding(player, "title").as(title => title ?? "No Title") createBinding(player, "title").as(title => title ?? tr("media.no_title"))
} label={ } label={
createBinding(player, "title").as(title => title ?? "No Title") createBinding(player, "title").as(title => title ?? tr("media.no_title"))
} ellipsize={Pango.EllipsizeMode.END} maxWidthChars={25} } ellipsize={Pango.EllipsizeMode.END} maxWidthChars={25}
/> />
<Gtk.Label class={"artist"} tooltipText={ <Gtk.Label class={"artist"} tooltipText={
createBinding(player, "artist").as(artist => artist ?? "No Artist") createBinding(player, "artist").as(artist => artist ?? tr("media.no_artist"))
} label={ } label={
createBinding(player, "artist").as(artist => artist ?? "No Artist") createBinding(player, "artist").as(artist => artist ?? tr("media.no_artist"))
} ellipsize={Pango.EllipsizeMode.END} maxWidthChars={28} } ellipsize={Pango.EllipsizeMode.END} maxWidthChars={28}
/> />
</Gtk.Box> as Gtk.Box </Gtk.Box> as Gtk.Box
@@ -128,7 +129,7 @@ class PlayerWidget extends Gtk.Box {
<Gtk.Box spacing={4} $type="center"> <Gtk.Box spacing={4} $type="center">
<Gtk.Box class={"extra button-row"}> <Gtk.Box class={"extra button-row"}>
<Gtk.Button class={"link"} <Gtk.Button class={"link"}
tooltipText={"Copy link to clipboard"} tooltipText={tr("copy_to_clipboard")}
visible={variableToBoolean(accessMediaUrl(player))} visible={variableToBoolean(accessMediaUrl(player))}
onClicked={(self) => { onClicked={(self) => {
const url = accessMediaUrl(player).get(); const url = accessMediaUrl(player).get();
@@ -180,22 +181,22 @@ class PlayerWidget extends Gtk.Box {
"media-playlist-shuffle-symbolic" "media-playlist-shuffle-symbolic"
: "media-playlist-consecutive-symbolic")} tooltipText={ : "media-playlist-consecutive-symbolic")} tooltipText={
createBinding(player, "shuffleStatus").as(status => status === AstalMpris.Shuffle.ON ? createBinding(player, "shuffleStatus").as(status => status === AstalMpris.Shuffle.ON ?
"Shuffle" tr("media.shuffle")
: "No shuffle")} onClicked={() => player.shuffle()} : tr("media.follow_order"))} onClicked={() => player.shuffle()}
/> />
<Gtk.Button class={"previous"} iconName={"media-skip-backward-symbolic"} <Gtk.Button class={"previous"} iconName={"media-skip-backward-symbolic"}
tooltipText={"Previous"} onClicked={() => player.canGoPrevious && player.previous()} tooltipText={tr("media.previous")} onClicked={() => player.canGoPrevious && player.previous()}
/> />
<Gtk.Button class={"play-pause"} tooltipText={ <Gtk.Button class={"play-pause"} tooltipText={
createBinding(player, "playbackStatus").as(status => createBinding(player, "playbackStatus").as(status =>
status === AstalMpris.PlaybackStatus.PLAYING ? "Pause" : "Play")} status === AstalMpris.PlaybackStatus.PLAYING ? tr("media.pause") : tr("media.play"))}
iconName={createBinding(player, "playbackStatus").as(status => iconName={createBinding(player, "playbackStatus").as(status =>
status === AstalMpris.PlaybackStatus.PLAYING ? status === AstalMpris.PlaybackStatus.PLAYING ?
"media-playback-pause-symbolic" "media-playback-pause-symbolic"
: "media-playback-start-symbolic")} onClicked={() => player.play_pause()} : "media-playback-start-symbolic")} onClicked={() => player.play_pause()}
/> />
<Gtk.Button class={"next"} iconName={"media-skip-forward-symbolic"} <Gtk.Button class={"next"} iconName={"media-skip-forward-symbolic"}
tooltipText={"Next"} onClicked={() => player.canGoNext && player.next()} tooltipText={tr("media.next")} onClicked={() => player.canGoNext && player.next()}
/> />
<Gtk.Button class={"repeat"} iconName={createBinding(player, "loopStatus").as(status => { <Gtk.Button class={"repeat"} iconName={createBinding(player, "loopStatus").as(status => {
if(status === AstalMpris.Loop.TRACK) if(status === AstalMpris.Loop.TRACK)
@@ -209,12 +210,12 @@ class PlayerWidget extends Gtk.Box {
status !== AstalMpris.Loop.UNSUPPORTED)} status !== AstalMpris.Loop.UNSUPPORTED)}
tooltipText={createBinding(player, "loopStatus").as(status => { tooltipText={createBinding(player, "loopStatus").as(status => {
if(status === AstalMpris.Loop.TRACK) if(status === AstalMpris.Loop.TRACK)
return "Loop song"; return tr("media.song_loop");
if(status === AstalMpris.Loop.PLAYLIST) if(status === AstalMpris.Loop.PLAYLIST)
return "Loop playlist"; return tr("media.loop");
return "No loop"; return tr("media.no_loop");
})} onClicked={() => player.loop()} })} onClicked={() => player.loop()}
/> />
</Gtk.Box> </Gtk.Box>
+1 -1
View File
@@ -9,7 +9,7 @@
"moduleResolution": "bundler", "moduleResolution": "bundler",
"skipLibCheck": true, "skipLibCheck": true,
"types": [ "types": [
"./@girs" "./@types"
], ],
"strict": true, "strict": true,
"jsx": "react-jsx", "jsx": "react-jsx",