CustomTimestamps: Improve settings preview (#374)

* Improve settings preview

* Add updated css
This commit is contained in:
Suffocate 2025-09-06 15:40:12 +01:00 • committed by GitHub
parent 7c773e0942
commit 021000bec0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 104 additions and 41 deletions

View file

@ -7,12 +7,14 @@
import "./style.css";
import { definePluginSettings, useSettings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { Link } from "@components/Link";
import { Devs, EquicordDevs } from "@utils/constants";
import { Margins } from "@utils/margins";
import { useForceUpdater } from "@utils/react";
import definePlugin, { OptionType } from "@utils/types";
import { Forms, moment, TextInput, useEffect, useState } from "@webpack/common";
import { findByCodeLazy, findComponentByCodeLazy } from "@webpack";
import { Forms, moment, TextInput, useEffect, useRef, UserStore, useState } from "@webpack/common";
type TimeFormat = {
name: string;
@ -66,9 +68,9 @@ const timeFormats: Record<string, TimeFormat> = {
},
lastWeekFormat: {
name: "Last week",
description: "[calendar] format for last week",
description: "[calendar] format for within the last week",
default: "ddd DD.MM.YYYY HH:mm:ss",
offset: -1000 * 60 * 60 * 24 * 7,
offset: -1000 * 60 * 60 * 24 * 6, // setting an offset of a week exactly pushes it into "older date" territory as soon as a second passes
},
sameElseFormat: {
name: "Older date",
@ -102,31 +104,83 @@ const format = (date: Date, formatTemplate: string): string => {
const TimeRow = (props: TimeRowProps) => {
const [state, setState] = useState(props.pluginSettings?.[props.id] || props.format.default);
const [preview, setPreview] = useState("");
const handleChange = (value: string) => {
setState(value);
props.onChange(props.id, value);
};
const updatePreview = () => setPreview(format(new Date(Date.now() + props.format.offset), state || props.format.default));
useEffect(() => {
updatePreview();
const interval = setInterval(updatePreview, 1000);
return () => clearInterval(interval);
}, [state]);
return (
<>
<Forms.FormTitle tag="h5">{props.format.name}</Forms.FormTitle>
<Forms.FormText>{props.format.description}</Forms.FormText>
<TextInput value={state} onChange={handleChange} />
<Forms.FormText className={"vc-cmt-preview-text"}>{preview}</Forms.FormText>
<TextInput value={state} onChange={handleChange}/>
</>
);
};
const MessagePreview = findComponentByCodeLazy<{
author: any,
message: any,
compact: boolean,
isGroupStart: boolean,
className: string,
hideSimpleEmbedContent: boolean
}>(/previewGuildId:\i,preview:\i,/);
const createMessage = findByCodeLazy(/channelId:\i,content:\i,tts:\i=!1,/);
const populateMessagePrototype = findByCodeLazy(/PREMIUM_REFERRAL&&\(\i=\i.default.isProbablyAValidSnowflake\(/);
const DemoMessage = (props: { msgId, compact, message, date: Date | undefined, isGroupStart?: boolean }) => {
const message = createMessage({
content: props.message || "This is a demo message to preview the custom timestamps.",
channelId: "1337",
state: "SENT"
});
message.id = props.msgId;
message.timestamp = moment(props.date ?? new Date());
const user = UserStore.getCurrentUser();
const populatedMessage = message && populateMessagePrototype(message);
return populatedMessage ? (
<div className="vc-cmt-demo-message">
<MessagePreview
author={{ ...user, nick: user.globalName || user.username }}
message={populatedMessage}
compact={props.compact}
isGroupStart={props.isGroupStart || false}
className="vc-cmt-demo-message-preview"
hideSimpleEmbedContent={true}
/>
</div>
) : <div className="vc-cmt-demo-message">
<Forms.FormText>
{/* @ts-ignore */}
<b>Preview:</b> {Vencord.Plugins.plugins.CustomTimestamps.renderTimestamp(date, "cozy")}
</Forms.FormText>
</div>;
};
const DemoMessageContainer = ErrorBoundary.wrap(() => {
const [isCompact, setIsCompact] = useState(false);
const today = useRef<Date>(new Date());
const yesterday = useRef<Date>(new Date(Date.now() + timeFormats.lastDayFormat.offset));
const lastWeek = useRef<Date>(new Date(Date.now() + timeFormats.lastWeekFormat.offset));
const aMonthAgo = useRef<Date>(new Date(Date.now() + timeFormats.sameElseFormat.offset));
return (
<div className={"vc-cmt-demo-message-container"} onClick={() => setIsCompact(!isCompact)}>
<DemoMessage compact={isCompact} msgId={"1337"}
message={`Click me to switch to ${isCompact ? "cozy" : "compact"} mode`} isGroupStart={true}
date={aMonthAgo.current}/>
<DemoMessage compact={isCompact} msgId={"1338"} message={"This message was sent in the last week"}
isGroupStart={true} date={lastWeek.current}/>
<DemoMessage compact={isCompact} msgId={"1339"} message={"Hover over timestamps to see tooltip formats"}
isGroupStart={true} date={yesterday.current}/>
<DemoMessage compact={isCompact} msgId={"1340"} message={"Edit the formats below to see them live update here"} isGroupStart={true}
date={today.current}/>
</div>
);
}, { noop: true });
const settings = definePluginSettings({
formats: {
type: OptionType.COMPONENT,
@ -140,25 +194,29 @@ const settings = definePluginSettings({
componentProps.setValue(newSettings);
};
return Object.entries(timeFormats).map(([key, value]) => (
<Forms.FormSection key={key}>
{key === "sameDayFormat" && (
<div className={Margins.bottom20}>
<Forms.FormDivider style={{ marginBottom: "10px" }} />
<Forms.FormTitle tag="h1">Calendar formats</Forms.FormTitle>
<Forms.FormText>
How to format the [calendar] value if used in the above timestamps.
</Forms.FormText>
</div>
)}
<TimeRow
id={key}
format={value}
onChange={setNewValue}
pluginSettings={settingsState}
/>
</Forms.FormSection>
));
return (
<>
<DemoMessageContainer/>
{Object.entries(timeFormats).map(([key, value]) => (
<Forms.FormSection key={key}>
{key === "sameDayFormat" && (
<div className={Margins.bottom20}>
<Forms.FormDivider style={{ marginBottom: "10px" }}/>
<Forms.FormTitle tag="h1">Calendar formats</Forms.FormTitle>
<Forms.FormText>
How to format the [calendar] value if used in the above timestamps.
</Forms.FormText>
</div>
)}
<TimeRow
id={key}
format={value}
onChange={setNewValue}
pluginSettings={settingsState}
/>
</Forms.FormSection>
))}
</>);
}
}
}).withPrivateSettings<{
@ -171,7 +229,7 @@ const settings = definePluginSettings({
lastDayFormat: string;
lastWeekFormat: string;
sameElseFormat: string;
};
}
}>();
export default definePlugin({
@ -230,16 +288,16 @@ export default definePlugin({
switch (type) {
case "cozy":
formatTemplate = settings.use(["formats"]).formats?.cozyFormat || timeFormats.cozyFormat.default;
formatTemplate = settings.store.formats?.cozyFormat || timeFormats.cozyFormat.default;
break;
case "compact":
formatTemplate = settings.use(["formats"]).formats?.compactFormat || timeFormats.compactFormat.default;
formatTemplate = settings.store.formats?.compactFormat || timeFormats.compactFormat.default;
break;
case "tooltip":
formatTemplate = settings.use(["formats"]).formats?.tooltipFormat || timeFormats.tooltipFormat.default;
formatTemplate = settings.store.formats?.tooltipFormat || timeFormats.tooltipFormat.default;
break;
case "ariaLabel":
formatTemplate = settings.use(["formats"]).formats?.ariaLabelFormat || timeFormats.ariaLabelFormat.default;
formatTemplate = settings.store.formats?.ariaLabelFormat || timeFormats.ariaLabelFormat.default;
}
useEffect(() => {

View file

@ -6,7 +6,12 @@
margin: 10px 0;
}
.vc-cmt-preview-text {
color: yellow;
margin: 8px 0;
.vc-cmt-demo-message-container{
position: sticky;
background: var(--background-base-lowest);
padding: 10px 0;
cursor: pointer;
top: -8px;
border: solid grey 1px;
border-radius: 5px;
}