mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-06-17 08:47:49 +00:00
feat(motd): add motd component (untested)
This commit is contained in:
@@ -0,0 +1,112 @@
|
|||||||
|
import {useEffect, useMemo, useState} from 'react'
|
||||||
|
import { getMotd, Motd } from '../store';
|
||||||
|
import { useSetting } from '../utils/hooks/useSetting';
|
||||||
|
import { DialogButton, Focusable, PanelSection } from '@decky/ui';
|
||||||
|
import { FaTimes } from 'react-icons/fa';
|
||||||
|
|
||||||
|
const SEVERITIES = {
|
||||||
|
High: {
|
||||||
|
color: "#bb1414",
|
||||||
|
text: "#fff",
|
||||||
|
},
|
||||||
|
Medium: {
|
||||||
|
color: "#bbbb14",
|
||||||
|
text: "#fff",
|
||||||
|
},
|
||||||
|
Low: {
|
||||||
|
color: "#1488bb",
|
||||||
|
text: "#fff",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const welcomeMotd: Motd = {
|
||||||
|
id: "welcomeMotd",
|
||||||
|
name: "Welcome to Decky!",
|
||||||
|
date: Date.now().toString(),
|
||||||
|
description: "We hope you enjoy using Decky! If you have any questions or feedback, please let us know.",
|
||||||
|
severity: "Low",
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MotdDisplay() {
|
||||||
|
const [motd, setMotd] = useState<Motd | null>(null);
|
||||||
|
// showWelcome will display a welcome motd, the welcome motd has an id of "welcome" and once that is saved to hiddenMotdId, it will not show again
|
||||||
|
const [hiddenMotdId, setHiddenMotdId] = useSetting("hiddenMotdId", "showWelcome")
|
||||||
|
|
||||||
|
async function fetchMotd() {
|
||||||
|
const motd = await getMotd();
|
||||||
|
setMotd(motd);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
void fetchMotd();
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (hiddenMotdId === 'showWelcome') {
|
||||||
|
setMotd(welcomeMotd);
|
||||||
|
}
|
||||||
|
}, [hiddenMotdId])
|
||||||
|
|
||||||
|
function hideMotd() {
|
||||||
|
if (motd) {
|
||||||
|
setHiddenMotdId(motd.id);
|
||||||
|
void fetchMotd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hidden = useMemo(() => {
|
||||||
|
return hiddenMotdId === motd?.id;
|
||||||
|
}, [hiddenMotdId, motd]);
|
||||||
|
|
||||||
|
if (!motd || !motd?.name || hidden) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const severity = SEVERITIES[motd?.severity || "Low"];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PanelSection>
|
||||||
|
<Focusable
|
||||||
|
style={{
|
||||||
|
// Transparency is 20% of the color
|
||||||
|
backgroundColor: `${severity.color}33`,
|
||||||
|
color: severity.text,
|
||||||
|
borderColor: severity.color,
|
||||||
|
borderWidth: "2px",
|
||||||
|
borderStyle: "solid",
|
||||||
|
padding: "0.7rem",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
position: "relative",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
||||||
|
<span style={{ fontWeight: "bold" }}>{motd?.name}</span>
|
||||||
|
<DialogButton
|
||||||
|
style={{
|
||||||
|
width: "1rem",
|
||||||
|
minWidth: "1rem",
|
||||||
|
height: "1rem",
|
||||||
|
padding: "0",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
position: "absolute",
|
||||||
|
top: ".75rem",
|
||||||
|
right: ".75rem",
|
||||||
|
}}
|
||||||
|
onClick={hideMotd}
|
||||||
|
>
|
||||||
|
<FaTimes
|
||||||
|
style={{
|
||||||
|
height: ".75rem",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</DialogButton>
|
||||||
|
</div>
|
||||||
|
<span style={{ fontSize: "0.75rem", whiteSpace: "pre-line" }}>{motd?.description}</span>
|
||||||
|
</Focusable>
|
||||||
|
</PanelSection>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import { useDeckyState } from './DeckyState';
|
|||||||
import NotificationBadge from './NotificationBadge';
|
import NotificationBadge from './NotificationBadge';
|
||||||
import { useQuickAccessVisible } from './QuickAccessVisibleState';
|
import { useQuickAccessVisible } from './QuickAccessVisibleState';
|
||||||
import TitleView from './TitleView';
|
import TitleView from './TitleView';
|
||||||
|
import { MotdDisplay } from './MotdDisplay';
|
||||||
|
|
||||||
const PluginView: FC = () => {
|
const PluginView: FC = () => {
|
||||||
const { plugins, hiddenPlugins, updates, activePlugin, pluginOrder, setActivePlugin, closeActivePlugin } =
|
const { plugins, hiddenPlugins, updates, activePlugin, pluginOrder, setActivePlugin, closeActivePlugin } =
|
||||||
@@ -36,6 +37,7 @@ const PluginView: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TitleView />
|
<TitleView />
|
||||||
|
<MotdDisplay />
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
paddingTop: '16px',
|
paddingTop: '16px',
|
||||||
|
|||||||
@@ -42,6 +42,14 @@ export interface PluginInstallRequest {
|
|||||||
installType: InstallType;
|
installType: InstallType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Motd {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
date: string;
|
||||||
|
severity: "High" | "Medium" | "Low";
|
||||||
|
}
|
||||||
|
|
||||||
// name: version
|
// name: version
|
||||||
export type PluginUpdateMapping = Map<string, StorePluginVersion>;
|
export type PluginUpdateMapping = Map<string, StorePluginVersion>;
|
||||||
|
|
||||||
@@ -49,6 +57,46 @@ export async function getStore(): Promise<Store> {
|
|||||||
return await getSetting<Store>('store', Store.Default);
|
return await getSetting<Store>('store', Store.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getMotd(): Promise<Motd> {
|
||||||
|
let version = await window.DeckyPluginLoader.updateVersion();
|
||||||
|
let store = await getSetting<Store | null>('store', null);
|
||||||
|
let customURL = await getSetting<string>('motd-url', 'https://plugins.deckbrew.xyz/v1/motd');
|
||||||
|
|
||||||
|
if (store === null) {
|
||||||
|
console.log('Could not get store, using Default.');
|
||||||
|
await setSetting('store', Store.Default);
|
||||||
|
store = Store.Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
let resolvedURL;
|
||||||
|
switch (store) {
|
||||||
|
case Store.Default:
|
||||||
|
resolvedURL = 'https://plugins.deckbrew.xyz/v1/motd';
|
||||||
|
break;
|
||||||
|
case Store.Testing:
|
||||||
|
resolvedURL = 'https://testing.deckbrew.xyz/v1/motd';
|
||||||
|
break;
|
||||||
|
case Store.Custom:
|
||||||
|
resolvedURL = customURL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error('Somehow you ended up without a standard URL, using the default URL.');
|
||||||
|
resolvedURL = 'https://plugins.deckbrew.xyz/v1/motd';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return fetch(resolvedURL, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'X-Decky-Version': version.current,
|
||||||
|
},
|
||||||
|
}).then((r) => {
|
||||||
|
if (r.status === 200) {
|
||||||
|
return r.json();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export async function getPluginList(
|
export async function getPluginList(
|
||||||
sort_by: SortOptions | null = null,
|
sort_by: SortOptions | null = null,
|
||||||
sort_direction: SortDirections | null = null,
|
sort_direction: SortDirections | null = null,
|
||||||
Reference in New Issue
Block a user