Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a95fbd5
init mdui
ArjixWasTaken Jul 3, 2025
919f372
temp: do not tree-shake mdui
ArjixWasTaken Jul 3, 2025
b322c9c
Merge remote-tracking branch 'upstream/master' into mdui
ArjixWasTaken Jul 12, 2025
64ba6f0
update pnpm-lock.yaml
ArjixWasTaken Jul 12, 2025
808df2e
feat: allow ES5 and ES6 HTMLElements to co-exist
ArjixWasTaken Jul 12, 2025
b21db78
simplify code
ArjixWasTaken Jul 12, 2025
ddc8210
enable mdui CSS
ArjixWasTaken Jul 12, 2025
396e0ff
small refactor
ArjixWasTaken Jul 13, 2025
1074547
Merge branch 'master' into mdui
ArjixWasTaken Jul 13, 2025
e472ac4
fix CSS weirdness
ArjixWasTaken Jul 13, 2025
47d8a17
fix theme
ArjixWasTaken Jul 13, 2025
d0c533f
make navigation buttons use m3 components
ArjixWasTaken Jul 13, 2025
bcd9c86
Merge branch 'th-ch:master' into mdui
ArjixWasTaken Jul 17, 2025
bc2bfeb
Merge branch 'master' into mdui
ArjixWasTaken Jul 25, 2025
7f13640
Merge branch 'master' into mdui
ArjixWasTaken Jul 29, 2025
9d3e57d
suppress Lit warnings
ArjixWasTaken Jul 29, 2025
261a55b
remove polyfill
ArjixWasTaken Jul 29, 2025
edc82e7
Discard changes to src/plugins/navigation/components/back-button.tsx
ArjixWasTaken Jul 29, 2025
21fb20d
Discard changes to src/plugins/navigation/components/forward-button.tsx
ArjixWasTaken Jul 29, 2025
b06cd2d
Discard changes to src/youtube-music.d.ts
ArjixWasTaken Jul 29, 2025
cd6a79f
Merge branch 'master' into mdui
ArjixWasTaken Jul 31, 2025
f06c383
Merge branch 'master' into mdui
ArjixWasTaken Aug 3, 2025
07afd7e
Discard changes to .prettierrc
ArjixWasTaken Aug 3, 2025
24107b9
Merge branch 'master' into mdui
ArjixWasTaken Aug 5, 2025
3a86327
feat(plugin): settings-ui
ArjixWasTaken Jul 25, 2025
252cab4
Merge branch 'master' into feat/settings-ui
ArjixWasTaken Oct 10, 2025
4e97621
Merge branch 'master' into feat/settings-ui
ArjixWasTaken Oct 10, 2025
8db9345
Merge branch 'pear-devs:master' into feat/settings-ui
ArjixWasTaken Oct 11, 2025
de9e8d2
apply eslint --fix
ArjixWasTaken Oct 11, 2025
99cce0c
Merge branch 'pear-devs:master' into feat/settings-ui
ArjixWasTaken Oct 12, 2025
be7f39c
Merge branch 'pear-devs:master' into feat/settings-ui
ArjixWasTaken Oct 12, 2025
86d5270
Merge branch 'master' into feat/settings-ui
ArjixWasTaken Oct 12, 2025
4cd887c
start rewrite on settings ui
ArjixWasTaken Oct 12, 2025
e8cd5a6
Merge branch 'pear-devs:master' into feat/settings-ui
ArjixWasTaken Oct 13, 2025
3a8cf53
Merge branch 'pear-devs:master' into feat/settings-ui
ArjixWasTaken Oct 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions patches/mdui.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
diff --git a/jsx.en.d.ts b/jsx.en.d.ts
index 514d455dcdb436aaf7b2ee88deaefe01943c8b4b..48dff045dead4315936afd931336198996c88217 100644
--- a/jsx.en.d.ts
+++ b/jsx.en.d.ts
@@ -1,12 +1,8 @@
-import React from 'react';
import { JQ } from '@mdui/jq';

-type HTMLElementProps = React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>;
+type HTMLElementProps = import("solid-js").JSX.HTMLAttributes<HTMLElement>;

-declare global {
- namespace React {
- namespace JSX {
- interface IntrinsicElements {
+export interface IntrinsicElements {
/**
* Avatar Component
*
@@ -3296,7 +3292,4 @@ declare global {
*/
'order'?: number;
} & HTMLElementProps;
- }
- }
- }
}
diff --git a/package.json b/package.json
index 3fa3eeb471ce4c31d7ac1c9bcb2d6823947e91ca..c4b062020bf20b8db34ccfea500fa682a4af19a6 100644
--- a/package.json
+++ b/package.json
@@ -60,5 +60,8 @@
"tslib": "^2.8.1",
"@mdui/shared": "^1.0.8",
"@mdui/jq": "^3.0.3"
+ },
+ "peerDependencies": {
+ "solid-js": "^1.9.7"
}
}
2 changes: 1 addition & 1 deletion src/config/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export interface DefaultConfig {
themes: string[];
customWindowTitle?: string;
};
'plugins': Record<string, unknown>;
'plugins': Record<string, Record<string, unknown> & { enabled: boolean }>;
}

export const defaultConfig: DefaultConfig = {
Expand Down
13 changes: 8 additions & 5 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { deepmergeCustom } from 'deepmerge-ts';
import { store, type IStore } from './store';
import { restart } from '@/providers/app-controls';

import type { defaultConfig } from './defaults';
import { defaultConfig, type DefaultConfig } from './defaults';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [eslint] <@typescript-eslint/no-unused-vars> reported by reviewdog 🐶
'defaultConfig' is defined but never used.


const deepmerge = deepmergeCustom({
mergeArrays: false,
Expand Down Expand Up @@ -32,6 +32,8 @@ export const setMenuOption = (key: string, value: unknown) => {
}
};

export const getStore = () => store.store;

// MAGIC OF TYPESCRIPT

type Prev = [
Expand Down Expand Up @@ -64,7 +66,8 @@ type Join<K, P> = K extends string | number
? `${K}${'' extends P ? '' : '.'}${P}`
: never
: never;
type Paths<T, D extends number = 10> = [D] extends [never]

export type Paths<T, D extends number = 10> = [D] extends [never]
? never
: T extends object
? {
Expand All @@ -75,13 +78,13 @@ type Paths<T, D extends number = 10> = [D] extends [never]
: '';

type SplitKey<K> = K extends `${infer A}.${infer B}` ? [A, B] : [K, string];
type PathValue<T, K extends string> =
export type PathValue<T, K extends string> =
SplitKey<K> extends [infer A extends keyof T, infer B extends string]
? PathValue<T[A], B>
: T;

export const get = <Key extends Paths<typeof defaultConfig>>(key: Key) =>
store.get(key) as PathValue<typeof defaultConfig, typeof key>;
export const get = <Key extends Paths<DefaultConfig>>(key: Key) =>
store.get(key) as PathValue<DefaultConfig, typeof key>;

export const edit = () => store.openInEditor();

Expand Down
19 changes: 19 additions & 0 deletions src/i18n/resources/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,25 @@
"instrumental": "⚠️ - This is an instrumental song"
}
},
"settings-ui": {
"name": "Settings UI",
"description": "todo!()",
"button": "Settings",
"title": {
"general": "General",
"appearance": "Appearance",
"plugins": "Plugins",
"advanced": "Advanced",
"about": "About"
},
"label": {
"general": "General",
"appearance": "Appearance",
"plugins": "Plugins",
"advanced": "Advanced",
"about": "About"
}
},
"taskbar-mediacontrol": {
"description": "Control playback from your Windows taskbar",
"name": "Taskbar Media Control"
Expand Down
73 changes: 73 additions & 0 deletions src/plugins/settings-ui/backend.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import is from 'electron-is';
import { app } from 'electron';

import * as config from '@/config';
import * as Plugins from '@/config/plugins';

import { createBackend } from '@/utils';

const getVersion = () => app.getVersion();

const platform = () => {
const { arch } = process;

if (is.windows()) return `Windows (${arch})`;
if (is.macOS()) return `macOS (${arch})`;
if (is.linux()) {
const desktop =
process.env.XDG_CURRENT_DESKTOP || process.env.XDG_SESSION_DESKTOP;
const type = process.env.XDG_SESSION_TYPE;

return `Linux (desktop=${desktop}; type=${type}; arch=${arch})`;
}
return process.platform + ` (${arch})`;
};

const versions = () => process.versions;

const plugins = {
enable: (id: string) => {
Plugins.enable(id);
},
disable: (id: string) => {
Plugins.disable(id);
},
};

export type ConfigKey = Parameters<typeof config.get>[0];

const configHandlers = {
get: <T extends ConfigKey>(key: T) => config.get(key),
set: (key: ConfigKey, value: unknown) => config.set(key, value),
};

const loadSettings = () => config.getStore();

export const backend = createBackend({
start(ctx) {
ctx.ipc.handle('ytmd-sui:app-version', getVersion);
ctx.ipc.handle('ytmd-sui:platform', platform);
ctx.ipc.handle('ytmd-sui:versions', versions);
ctx.ipc.handle('ytmd-sui:load-settings', loadSettings);

ctx.ipc.handle('ytmd-sui:config-get', configHandlers.get);
ctx.ipc.handle('ytmd-sui:config-set', configHandlers.set);

ctx.ipc.handle('ytmd-sui:plugins-enable', plugins.enable);
ctx.ipc.handle('ytmd-sui:plugins-disable', plugins.disable);
},

stop(ctx) {
ctx.ipc.removeHandler('ytmd-sui:app-version');
ctx.ipc.removeHandler('ytmd-sui:platform');
ctx.ipc.removeHandler('ytmd-sui:versions');
ctx.ipc.removeHandler('ytmd-sui:load-settings');

ctx.ipc.removeHandler('ytmd-sui:config-get');
ctx.ipc.removeHandler('ytmd-sui:config-set');

ctx.ipc.removeHandler('ytmd-sui:plugins-enable');
ctx.ipc.removeHandler('ytmd-sui:plugins-disable');
ctx.ipc.removeHandler('ytmd-sui:plugins-isEnabled');
},
});
63 changes: 63 additions & 0 deletions src/plugins/settings-ui/components/Select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { For } from 'solid-js';

export interface SelectProps {
label: string;
description: string;

value: string;
options: { label: string; value: string }[];
onSelect: (value: string) => void;
}

export const Select = (props: SelectProps) => {
return (
<div
style={{
'display': 'flex',
'align-items': 'flex-start',
'justify-content': 'space-between',
'gap': '24px',
'margin-bottom': '20px',
}}
>
<label
style={{
'flex': '0 0 160px',
'text-align': 'right',
'color': 'var(--mdui-color-on-surface)',
'font-size': '0.95rem',
'font-weight': 500,
'line-height': '1.4',
'padding-top': '0.5rem',
}}
>
{props.label}
</label>
<div
style={{
'flex': 1,
'display': 'flex',
'flex-direction': 'column',
'gap': '4px',
}}
>
<span
style={{
'color': 'var(--mdui-color-on-surface-variant)',
'font-size': '0.8rem',
'line-height': '1.3',
}}
>
{props.description}
</span>
<mdui-select style={{ width: '100%' }} value={props.value}>
<For each={props.options}>
{({ label, value }) => (
<mdui-menu-item value={value}>{label}</mdui-menu-item>
)}
</For>
</mdui-select>
</div>
</div>
);
};
53 changes: 53 additions & 0 deletions src/plugins/settings-ui/components/Toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
export interface ToggleProps {
label: string;
description: string;
value: boolean;
toggle: () => void;
}

export const Toggle = (props: ToggleProps) => {
return (
<div
style={{
'display': 'flex',
'align-items': 'flex-start',
'justify-content': 'space-between',
'gap': '24px',
'margin-bottom': '20px',
}}
>
<label
style={{
'flex': '0 0 160px',
'text-align': 'right',
'color': 'var(--mdui-color-on-surface)',
'font-size': '0.95rem',
'font-weight': 500,
'line-height': '1.4',
'padding-top': '0.5rem',
}}
>
{props.label}
</label>
<div
style={{
'flex': 1,
'display': 'flex',
'flex-direction': 'column',
'gap': '4px',
}}
>
<span
style={{
'color': 'var(--mdui-color-on-surface-variant)',
'font-size': '0.8rem',
'line-height': '1.3',
}}
>
{props.description}
</span>
<mdui-switch checked={props.value} />
</div>
</div>
);
};
81 changes: 81 additions & 0 deletions src/plugins/settings-ui/components/sections/General.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { t } from '@/i18n';

import { Select } from '../Select';
import { Toggle } from '../Toggle';

export const General = () => {
const t$ = (key: string) => t(`main.menu.options.submenu.${key}`);

return (
<>
{/* <Show
when={
props.platform.startsWith('Windows') ||
props.platform.startsWith('macOS')
}
> */}
<Toggle
description="Start Pear Music on login"
label={t$('start-at-login')}
toggle={() => {}}
value={true}
/>
{/* </Show> */}

<Select
description="Select the language for the application"
label={t$('language.label')}
onSelect={() => {}}
options={[
// mock data
{ value: 'en', label: 'English' },
{ value: 'gr', label: 'Ελληνικά' },
]}
value="en"
/>

<Select
description="Select which page to show when the application starts"
label={t$('starting-page.label')}
onSelect={() => {}}
options={[]}
value={''}
/>

<Toggle
description="Automatically get notified about new versions"
label={t$('auto-update')}
toggle={() => {}}
value={true}
/>

<Toggle
description="Resume last song when app starts"
label={t$('resume-on-start')}
toggle={() => {}}
value={true}
/>

<Toggle
description="Keep the application window on top of other windows"
label={t$('always-on-top')}
toggle={() => {}}
value={false}
/>

{/* <Show
when={
props.platform.startsWith('Windows') ||
props.platform.startsWith('Linux')
}
> */}
<Toggle
description="Hide the menu bar"
label={t$('hide-menu.label')}
toggle={() => {}}
value={false}
/>
{/* </Show> */}
</>
);
};
Loading