Plugin

SendTimestamps

Send timestamps easily via chat box button & text shortcuts. Read the extended description!

Chat Commands
index.tsx
Download

Source

src/plugins/sendTimestamps/index.tsx
1import "./styles.css";
2
3import { ChatBarButton, ChatBarButtonFactory } from "@api/ChatButtons";
4import { definePluginSettings } from "@api/Settings";
5import { Devs } from "@utils/constants";
6import { classNameFactory } from "@utils/css";
7import { getTheme, insertTextIntoChatInputBox, Theme } from "@utils/discord";
8import { Margins } from "@utils/margins";
9import definePlugin, { IconComponent, OptionType } from "@utils/types";
10import { RenderModalProps } from "@vencord/discord-types";
11import { Forms, Modal,openModal, Parser, Select, useMemo, useState } from "@webpack/common";
12
13const settings = definePluginSettings({
14 replaceMessageContents: {
15 description: "Replace timestamps in message contents",
16 type: OptionType.BOOLEAN,
17 default: true,
18 },
19});
20
21function parseTime(time: string) {
22 const cleanTime = time.slice(1, -1).replace(/(\d)(AM|PM)$/i, "$1 $2");
23
24 let ms = new Date(`${new Date().toDateString()} ${cleanTime}`).getTime() / 1000;
25 if (isNaN(ms)) return time;
26
27 // add 24h if time is in the past
28 if (Date.now() / 1000 > ms) ms += 86400;
29
30 return `<t:${Math.round(ms)}:t>`;
31}
32
33const Formats = ["", "t", "T", "d", "D", "f", "F", "s", "S", "R"] as const;
34type Format = typeof Formats[number];
35
36const cl = classNameFactory("vc-st-");
37
38function PickerModal(props: RenderModalProps) {
39 const [value, setValue] = useState<string>();
40 const [format, setFormat] = useState<Format>("");
41 const time = Math.round((new Date(value!).getTime() || Date.now()) / 1000);
42
43 const formatTimestamp = (time: number, format: Format) => `<t:${time}${format && `:${format}`}>`;
44
45 const [formatted, rendered] = useMemo(() => {
46 const formatted = formatTimestamp(time, format);
47 return [formatted, Parser.parse(formatted)];
48 }, [time, format]);
49
50 return (
51 <Modal
52 {...props}
53 title="Timestamp Picker"
54 actions={[{
55 text: "Insert",
56 variant: "primary",
57 onClick() {
58 insertTextIntoChatInputBox(formatted + " ");
59 props.onClose();
60 }
61 }]}
62 >
63 <input
64 className={cl("date-picker")}
65 type="datetime-local"
66 value={value}
67 onChange={e => setValue(e.currentTarget.value)}
68 style={{
69 colorScheme: getTheme() === Theme.Light ? "light" : "dark",
70 }}
71 />
72
73 <Forms.FormTitle>Timestamp Format</Forms.FormTitle>
74 <div className={cl("format-select")}>
75 <Select
76 options={
77 Formats.map(m => ({
78 label: m,
79 value: m
80 }))
81 }
82 isSelected={v => v === format}
83 select={v => setFormat(v)}
84 serialize={v => v}
85 renderOptionLabel={o => (
86 <div className={cl("format-label")}>
87 {Parser.parse(formatTimestamp(time, o.value))}
88 </div>
89 )}
90 renderOptionValue={() => rendered}
91 />
92 </div>
93
94 <Forms.FormTitle className={Margins.bottom8}>Preview</Forms.FormTitle>
95 <Forms.FormText className={cl("preview-text")}>
96 {rendered} ({formatted})
97 </Forms.FormText>
98 </Modal>
99 );
100}
101
102const SendTimestampIcon: IconComponent = ({ height = 20, width = 20, className }) => {
103 return (
104 <svg
105 aria-hidden="true"
106 role="img"
107 width={width}
108 height={height}
109 className={className}
110 viewBox="0 0 24 24"
111 style={{ scale: "1.2" }}
112 >
113 <g fill="none" fillRule="evenodd">
114 <path fill="currentColor" d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7v-5z" />
115 <rect width="24" height="24" />
116 </g>
117 </svg>
118 );
119};
120
121const SendTimestampButton: ChatBarButtonFactory = ({ isAnyChat }) => {
122 if (!isAnyChat) return null;
123
124 return (
125 <ChatBarButton
126 tooltip="Insert Timestamp"
127 onClick={() => openModal(props => <PickerModal {...props} />)}
128 buttonProps={{ "aria-haspopup": "dialog" }}
129 >
130 <SendTimestampIcon />
131 </ChatBarButton>
132 );
133};
134
135export default definePlugin({
136 name: "SendTimestamps",
137 description: "Send timestamps easily via chat box button & text shortcuts. Read the extended description!",
138 tags: ["Chat", "Commands"],
139 authors: [Devs.Ven, Devs.Tyler, Devs.Grzesiek11],
140 settings,
141
142 chatBarButton: {
143 icon: SendTimestampIcon,
144 render: SendTimestampButton
145 },
146
147 onBeforeMessageSend(_, msg) {
148 if (settings.store.replaceMessageContents) {
149 msg.content = msg.content.replace(/`\d{1,2}:\d{2} ?(?:AM|PM)?`/gi, parseTime);
150 }
151 },
152
153 settingsAboutComponent() {
154 const samples = [
155 "12:00",
156 "3:51",
157 "17:59",
158 "24:00",
159 "12:00 AM",
160 "0:13PM"
161 ].map(s => `\`${s}\``);
162
163 return (
164 <>
165 <Forms.FormText>
166 To quickly send time only timestamps, include timestamps formatted as `HH:MM` (including the backticks!) in your message
167 </Forms.FormText>
168 <Forms.FormText>
169 See below for examples.
170 If you need anything more specific, use the Date button in the chat bar!
171 </Forms.FormText>
172 <Forms.FormText>
173 Examples:
174 <ul>
175 {samples.map(s => (
176 <li key={s}>
177 <code>{s}</code> {"->"} {Parser.parse(parseTime(s))}
178 </li>
179 ))}
180 </ul>
181 </Forms.FormText>
182 </>
183 );
184 },
185});
186