mirror of
https://github.com/Equicord/Equicord.git
synced 2025-06-20 20:07:03 -04:00
Plugins
This commit is contained in:
parent
38bba2d900
commit
b93c0aa1d4
17 changed files with 1233 additions and 28 deletions
66
src/equicordplugins/unitConverter/ConverterAccessory.tsx
Normal file
66
src/equicordplugins/unitConverter/ConverterAccessory.tsx
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { useState } from "@webpack/common";
|
||||
import { Message } from "discord-types/general";
|
||||
|
||||
export const conversions = new Map<string, (conv: string) => void>();
|
||||
const cl = classNameFactory("vc-converter-");
|
||||
function Dismiss({ onDismiss }: { onDismiss: () => void; }) {
|
||||
return (
|
||||
<button
|
||||
onClick={onDismiss}
|
||||
className={cl("dismiss")}
|
||||
>
|
||||
Dismiss
|
||||
</button>
|
||||
);
|
||||
}
|
||||
// thanks <@408047304864432139>
|
||||
export function ConvertIcon({ height = 24, width = 24, className }: {
|
||||
height?: number,
|
||||
width?: number,
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 98 98"
|
||||
height={height}
|
||||
width={width}
|
||||
className={[cl("icon"), className].join(" ")}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m50 16.668v-7.4609c0-1.875-2.25-2.7891-3.543-1.457l-11.664 11.625c-0.83594 0.83203-0.83594 2.125 0 2.957l11.625 11.625c1.332 1.293 3.582 0.375 3.582-1.5v-7.457c13.793 0 25 11.207 25 25 0 3.293-0.625 6.5-1.832 9.375-0.625 1.5-0.16797 3.207 0.95703 4.332 2.125 2.125 5.707 1.375 6.832-1.4141 1.543-3.793 2.375-7.9609 2.375-12.293 0-18.418-14.914-33.332-33.332-33.332zm0 58.332c-13.793 0-25-11.207-25-25 0-3.293 0.625-6.5 1.832-9.375 0.625-1.5 0.16797-3.207-0.95703-4.332-2.125-2.125-5.707-1.375-6.832 1.4141-1.543 3.793-2.375 7.9609-2.375 12.293 0 18.418 14.914 33.332 33.332 33.332v7.4609c0 1.875 2.25 2.7891 3.543 1.457l11.625-11.625c0.83203-0.83203 0.83203-2.125 0-2.957l-11.625-11.625c-1.293-1.293-3.543-0.375-3.543 1.5z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
export function ConverterAccessory({ message }: { message: Message; }) {
|
||||
const [conversion, setConversion] = useState<string>("");
|
||||
conversions.set(message.id, setConversion);
|
||||
if (!conversion) return null;
|
||||
return (
|
||||
<span className={cl("accessory")}>
|
||||
<ConvertIcon width={16} height={16} />
|
||||
{conversion}
|
||||
{" - "}
|
||||
<Dismiss onDismiss={() => setConversion("")} />
|
||||
</span>
|
||||
);
|
||||
}
|
177
src/equicordplugins/unitConverter/converter.ts
Normal file
177
src/equicordplugins/unitConverter/converter.ts
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { settings } from ".";
|
||||
|
||||
interface regexes {
|
||||
imperial: {
|
||||
[key: string]: {
|
||||
regex: RegExp,
|
||||
convert: (...groups: string[]) => string;
|
||||
};
|
||||
};
|
||||
metric: {
|
||||
[key: string]: {
|
||||
regex: RegExp,
|
||||
convert: (...groups: string[]) => string;
|
||||
};
|
||||
};
|
||||
}
|
||||
// TODO: add grams, kilograms, ounces, and pounds
|
||||
const regexes: regexes = {
|
||||
// matches imperial units, converts them to metric
|
||||
imperial: {
|
||||
farenheight: {
|
||||
regex: /(-?\d+(?:\.\d+)?)°?(f)(?!\w)/ig,
|
||||
convert(...groups) {
|
||||
const c = ((parseFloat(groups[1]) - 32) * (5 / 9)).toFixed(2);
|
||||
return `${c}°C`;
|
||||
},
|
||||
},
|
||||
// feetMark: {
|
||||
// regex: /(\d+(?:\.\d+))(')(?!(\d+(?:\.\d+)?(''|")|'))/g,
|
||||
// convert(...groups) {
|
||||
// },
|
||||
// },
|
||||
// leaving this one in because it is commonly used for something like 5'9'' for a persons height
|
||||
feetInchesMark: {
|
||||
regex: /(\d+)(') ?(\d+(?:\.\d+)?)("|'')?/g,
|
||||
convert(...groups) {
|
||||
let ftin = parseFloat(groups[1]) / 3.281;
|
||||
ftin += parseFloat(groups[3]) / 39.37;
|
||||
return `${ftin.toFixed(2)}m`;
|
||||
},
|
||||
},
|
||||
// inchesMark: {
|
||||
// regex: /(?<!\d+')(\d+(?:\.\d+)?)("|'')/g,
|
||||
// convert(...groups) {
|
||||
// },
|
||||
// },
|
||||
feetWord: {
|
||||
regex: /(\d+(?:\.\d+)?) *(f(ee)?t)(?! *\d)/ig,
|
||||
convert(...groups) {
|
||||
const ft = (parseFloat(groups[1]) / 3.281).toFixed(2);
|
||||
return `${ft}m`;
|
||||
},
|
||||
},
|
||||
inchesWord: {
|
||||
regex: /(?<!\d+ *(?:f(?:ee|oo)?t) *)(\d+(?:\.\d+)?) *(in(?:ches?)?)/ig,
|
||||
convert(...groups) {
|
||||
const inches = (parseFloat(groups[1]) / 2.54).toFixed(2);
|
||||
return `${inches}cm`;
|
||||
},
|
||||
},
|
||||
feetInchesWord: {
|
||||
regex: /(\d+) *(f(?:ee|oo)?t) *(\d+(?:\.\d+)?) *(in(?:ches?)?)/ig,
|
||||
convert(...groups) {
|
||||
let ftin = parseFloat(groups[1]) / 3.281;
|
||||
ftin += parseFloat(groups[3]) / 39.37;
|
||||
return `${ftin.toFixed(2)}m`;
|
||||
},
|
||||
},
|
||||
poundWord: {
|
||||
regex: /(\d+(?:\.\d+)?) *(lbs?|pounds?)(?! ?\d)/ig,
|
||||
convert(...groups: string[]) {
|
||||
const lbs = (parseFloat(groups[1]) / 2.205).toFixed(2);
|
||||
return `${lbs}kg`;
|
||||
},
|
||||
},
|
||||
poundOunceWord: {
|
||||
regex: /(\d+(?:\.\d+)?) *(lbs?|pounds?) *(\d+(?:\.\d+)?) *(ozs?|ounces?)/ig,
|
||||
convert(...groups) {
|
||||
let lbs = (parseInt(groups[1]) / 2.205);
|
||||
lbs += (parseFloat(groups[2]) / 35.274);
|
||||
return `${lbs.toFixed(2)}kg`;
|
||||
}
|
||||
},
|
||||
ounceWord: {
|
||||
regex: /(\d+(?:\.\d+)?) ?(ounces?|oz)/gi,
|
||||
convert(...groups) {
|
||||
const ozs = (parseFloat(groups[1]) * 28.35).toFixed(2);
|
||||
return `${ozs}g`;
|
||||
},
|
||||
},
|
||||
milesPerHour: {
|
||||
regex: /(\d+(?:\.\d+)?) ?(m(?:p|\/)h)/gi,
|
||||
convert(...groups) {
|
||||
const mph = (parseFloat(groups[1]) * 1.609).toFixed(2);
|
||||
return `${mph}km/h`;
|
||||
},
|
||||
}
|
||||
},
|
||||
// matches metric untis, converts them into imperial
|
||||
metric: {
|
||||
// i dont think people ever write metric units as 1m3cm or something like that
|
||||
celcius: {
|
||||
regex: /(-?\d+(?:\.\d+)?) ?°?(c)(?!\w)/ig,
|
||||
convert(...groups) {
|
||||
const f = ((parseFloat(groups[1]) * (9 / 5)) + 32).toFixed(2);
|
||||
return `${f}°F`;
|
||||
}
|
||||
},
|
||||
// convert to inches
|
||||
centimeters: {
|
||||
regex: /(\d+(?:\.\d+)?) *(cm)(?!\w)/ig,
|
||||
convert(...groups) {
|
||||
const cm = (parseFloat(groups[1]) / 2.54).toFixed(2);
|
||||
return `${cm}in`;
|
||||
},
|
||||
},
|
||||
// convert to feet
|
||||
meters: {
|
||||
regex: /(\d+(?:\.\d+)?) *(m)(?!\w)/ig,
|
||||
convert(...groups) {
|
||||
const m = parseFloat((parseFloat(groups[1]) * 3.821).toFixed(2));
|
||||
if (Number.isInteger(m))
|
||||
return `${m}ft`;
|
||||
return `${m.toFixed(0)}ft${((m % 1) * 12).toFixed(2)}in`;
|
||||
},
|
||||
},
|
||||
// covnert to miles
|
||||
kilometers: {
|
||||
regex: /(\d+(?:\.\d+)?) *(km)(?!\w)/ig,
|
||||
convert(...groups) {
|
||||
const m = (parseFloat(groups[1]) / 1.609).toFixed(2);
|
||||
return `${m}mi`;
|
||||
},
|
||||
},
|
||||
grams: {
|
||||
regex: /(\d+(?:\.\d+)?) ?(grams?|g)/gi,
|
||||
convert(...groups) {
|
||||
const g = (parseFloat(groups[1]) / 28.35).toFixed(2);
|
||||
return `${g}oz(s)`;
|
||||
},
|
||||
},
|
||||
kilograms: {
|
||||
regex: /(\d+(?:\.\d+)?) ?(kg|kilos?)/gi,
|
||||
convert(...groups) {
|
||||
const kg = (parseFloat(groups[1]) * 2.205).toFixed(2);
|
||||
return `${kg}lb(s)`;
|
||||
},
|
||||
},
|
||||
kilometersPerHour: {
|
||||
regex: /(\d+(?:\.\d+)?) ?(km?p?\/?h)/gi,
|
||||
convert(...groups) {
|
||||
const kph = (parseFloat(groups[1]) / 1.609).toFixed(2);
|
||||
return `${kph}mph`;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
export function convert(message: string): string {
|
||||
let newMessage = message;
|
||||
if (settings.store.myUnits === "imperial") {
|
||||
for (const unit in regexes.metric) {
|
||||
newMessage = newMessage.replaceAll(regexes.metric[unit].regex, regexes.metric[unit].convert);
|
||||
}
|
||||
} else {
|
||||
for (const unit in regexes.imperial) {
|
||||
newMessage = newMessage.replaceAll(regexes.imperial[unit].regex, regexes.imperial[unit].convert);
|
||||
}
|
||||
}
|
||||
return newMessage;
|
||||
}
|
77
src/equicordplugins/unitConverter/index.tsx
Normal file
77
src/equicordplugins/unitConverter/index.tsx
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2022 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import "./style.css";
|
||||
|
||||
import { addAccessory } from "@api/MessageAccessories";
|
||||
import { addButton } from "@api/MessagePopover";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { ChannelStore } from "@webpack/common";
|
||||
|
||||
import { convert } from "./converter";
|
||||
import { conversions, ConverterAccessory, ConvertIcon } from "./ConverterAccessory";
|
||||
|
||||
|
||||
export const settings = definePluginSettings({
|
||||
myUnits: {
|
||||
type: OptionType.SELECT,
|
||||
description: "the units you use and want things converted to. defaults to imperial",
|
||||
options: [
|
||||
{
|
||||
default: true,
|
||||
label: "Imperial",
|
||||
value: "imperial",
|
||||
},
|
||||
{
|
||||
label: "Metric",
|
||||
value: "metric"
|
||||
}
|
||||
]
|
||||
},
|
||||
// invert: {
|
||||
// type: OptionType.BOOLEAN,
|
||||
// default: false,
|
||||
// // is there a better way to word this?
|
||||
// description: "If this option is set, ignore the units you set and invert every conversion."
|
||||
// }
|
||||
});
|
||||
export default definePlugin({
|
||||
name: "UnitConverter",
|
||||
description: "Converts metric units to Imperal units and vice versa",
|
||||
authors: [EquicordDevs.sadan],
|
||||
start() {
|
||||
addAccessory("vc-converter", props => <ConverterAccessory message={props.message} />);
|
||||
addButton("vc-converter", message => {
|
||||
if (!message.content) return null;
|
||||
return {
|
||||
label: "Convert Units",
|
||||
icon: ConvertIcon,
|
||||
message,
|
||||
channel: ChannelStore.getChannel(message.channel_id),
|
||||
onClick: async () => {
|
||||
const setConversion = conversions.get(message.id);
|
||||
if (!setConversion) return;
|
||||
setConversion(convert(message.content));
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
settings,
|
||||
});
|
24
src/equicordplugins/unitConverter/style.css
Normal file
24
src/equicordplugins/unitConverter/style.css
Normal file
|
@ -0,0 +1,24 @@
|
|||
.vc-converter-dismiss {
|
||||
all: unset;
|
||||
cursor: pointer;
|
||||
color: var(--text-link);
|
||||
}
|
||||
|
||||
.vc-converter-dismiss:is(:hover, :focus) {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.vc-converter-accessory {
|
||||
color: var(--text-muted);
|
||||
margin-top: 0.5em;
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.vc-converter-accessory svg {
|
||||
margin-right: 0.25em;
|
||||
}
|
||||
|
||||
.vc-converter-chat-button {
|
||||
scale: 1.085;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue