Merge pull request #1635 from BetterDiscord/modals
Reduce reliance on internals and improve UI consistency
This commit is contained in:
commit
9f950c10f0
|
@ -1,51 +0,0 @@
|
|||
import ClassName from "@structs/classname";
|
||||
|
||||
import Utilities from "./utilities";
|
||||
import WebpackModules from "./webpackmodules";
|
||||
|
||||
|
||||
const combineClasses = function (...props) {
|
||||
return Object.assign({}, ...props.map(prop => WebpackModules.getByProps(...prop)));
|
||||
};
|
||||
|
||||
const DiscordClassModules = Utilities.memoizeObject({
|
||||
get Text() {
|
||||
return combineClasses(
|
||||
["size20", "size12"],
|
||||
["selectable", "colorMuted"]
|
||||
);
|
||||
},
|
||||
get Titles() {
|
||||
return combineClasses(
|
||||
["wrapper", "base"],
|
||||
["defaultColor", "h4"]
|
||||
);
|
||||
},
|
||||
get EmptyImage() {return WebpackModules.getByProps("emptyImage", "emptyHeader");},
|
||||
get Modal() {return WebpackModules.getByProps("content", "root", "header", "close");},
|
||||
get Scrollers() {return WebpackModules.getByProps("thin", "scrollerBase", "content");},
|
||||
get Margins() {return WebpackModules.getByProps("marginXSmall", "marginBottom8");},
|
||||
get Integrations() {return WebpackModules.getByProps("secondaryHeader", "detailsWrapper");},
|
||||
get Card() {return WebpackModules.getByProps("card", "topDivider", "description");},
|
||||
});
|
||||
|
||||
const emptyClassModule = new Proxy({}, {
|
||||
get() {return "";}
|
||||
});
|
||||
|
||||
const DiscordClasses = new Proxy(DiscordClassModules, {
|
||||
get(list, item) {
|
||||
if (list[item] === undefined) return emptyClassModule;
|
||||
if (typeof(list[item]) === "string") return list[item];
|
||||
|
||||
return new Proxy(list[item], {
|
||||
get(obj, prop) {
|
||||
if (!(prop in obj)) return "";
|
||||
|
||||
return new ClassName(obj[prop]);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export default DiscordClasses;
|
|
@ -12,151 +12,13 @@ import WebpackModules, {Filters} from "./webpackmodules";
|
|||
export default Utilities.memoizeObject({
|
||||
get React() {return WebpackModules.getByProps("createElement", "cloneElement");},
|
||||
get ReactDOM() {return WebpackModules.getByProps("render", "findDOMNode");},
|
||||
get Flux() {return WebpackModules.getByProps("connectStores");},
|
||||
get Events() {return WebpackModules.getByPrototypes("setMaxListeners", "emit");},
|
||||
|
||||
/* Guild Info, Stores, and Utilities */
|
||||
get GuildStore() {return WebpackModules.getByProps("getGuild");},
|
||||
get SortedGuildStore() {return WebpackModules.getByProps("getSortedGuilds");},
|
||||
get SelectedGuildStore() {return WebpackModules.getByProps("getLastSelectedGuildId");},
|
||||
get GuildSync() {return WebpackModules.getByProps("getSyncedGuilds");},
|
||||
get GuildInfo() {return WebpackModules.getByProps("getAcronym");},
|
||||
get GuildChannelsStore() {return WebpackModules.getByProps("getChannels", "getDefaultChannel");},
|
||||
get GuildMemberStore() {return WebpackModules.getByProps("getMember");},
|
||||
get MemberCountStore() {return WebpackModules.getByProps("getMemberCounts");},
|
||||
get GuildEmojiStore() {return WebpackModules.getByProps("getEmojis");},
|
||||
get GuildActions() {return WebpackModules.getByProps("markGuildAsRead");},
|
||||
get GuildPermissions() {return WebpackModules.getByProps("getGuildPermissions");},
|
||||
|
||||
/* Channel Store & Actions */
|
||||
get ChannelStore() {return WebpackModules.getByProps("getChannel", "getDMFromUserId");},
|
||||
get SelectedChannelStore() {return WebpackModules.getByProps("getLastSelectedChannelId");},
|
||||
get ChannelActions() {return WebpackModules.getByProps("selectChannel");},
|
||||
get PrivateChannelActions() {return WebpackModules.getByProps("openPrivateChannel");},
|
||||
get ChannelSelector() {return WebpackModules.getByProps("selectGuild", "selectChannel");},
|
||||
|
||||
/* Current User Info, State and Settings */
|
||||
get UserInfoStore() {return WebpackModules.getByProps("getToken");},
|
||||
get LocaleStore() {return WebpackModules.getByProps("locale", "initialize");},
|
||||
get ThemeStore() {return WebpackModules.getByProps("theme", "initialize");},
|
||||
get AccountManager() {return WebpackModules.getByProps("register", "login");},
|
||||
get UserSettingsUpdater() {return WebpackModules.getByProps("updateRemoteSettings");},
|
||||
get OnlineWatcher() {return WebpackModules.getByProps("isOnline");},
|
||||
get CurrentUserIdle() {return WebpackModules.getByProps("getIdleTime");},
|
||||
get RelationshipStore() {return WebpackModules.getByProps("isBlocked", "getFriendIDs");},
|
||||
get RelationshipManager() {return WebpackModules.getByProps("addRelationship");},
|
||||
get MentionStore() {return WebpackModules.getByProps("getMentions");},
|
||||
|
||||
/* User Stores and Utils */
|
||||
get UserStore() {return WebpackModules.getByProps("getCurrentUser", "getUser");},
|
||||
get UserStatusStore() {return WebpackModules.getByProps("getStatus", "getState");},
|
||||
get UserTypingStore() {return WebpackModules.getByProps("isTyping");},
|
||||
get UserActivityStore() {return WebpackModules.getByProps("getActivity");},
|
||||
get UserNameResolver() {return WebpackModules.getByProps("getName");},
|
||||
get UserNoteStore() {return WebpackModules.getByProps("getNote");},
|
||||
get UserNoteActions() {return WebpackModules.getByProps("updateNote");},
|
||||
|
||||
/* Emoji Store and Utils */
|
||||
get EmojiInfo() {return WebpackModules.getByProps("isEmojiDisabled");},
|
||||
get EmojiUtils() {return WebpackModules.getByProps("getGuildEmoji");},
|
||||
get EmojiStore() {return WebpackModules.getByProps("getByCategory", "EMOJI_NAME_RE");},
|
||||
|
||||
/* Invite Store and Utils */
|
||||
get InviteStore() {return WebpackModules.getByProps("getInvites");},
|
||||
get InviteResolver() {return WebpackModules.getByProps("findInvite");},
|
||||
get InviteActions() {return WebpackModules.getByProps("acceptInvite");},
|
||||
|
||||
/* Discord Objects & Utils */
|
||||
get DiscordConstants() {return WebpackModules.getByProps("Permissions", "ActivityTypes", "StatusTypes");},
|
||||
get DiscordPermissions() {return WebpackModules.getByProps("Permissions", "ActivityTypes", "StatusTypes").Permissions;},
|
||||
get PermissionUtils() {return WebpackModules.getByProps("getHighestRole");},
|
||||
get ColorConverter() {return WebpackModules.getByProps("hex2int");},
|
||||
get ColorShader() {return WebpackModules.getByProps("darken");},
|
||||
get TinyColor() {return WebpackModules.getByPrototypes("toRgb");},
|
||||
get ClassResolver() {return WebpackModules.getByProps("getClass");},
|
||||
get ButtonData() {return WebpackModules.getByProps("ButtonSizes");},
|
||||
get IconNames() {return WebpackModules.getByProps("IconNames");},
|
||||
get NavigationUtils() {return WebpackModules.getByProps("transitionTo", "replaceWith", "getHistory");},
|
||||
|
||||
/* Discord Messages */
|
||||
get MessageStore() {return WebpackModules.getByProps("getMessages");},
|
||||
get MessageActions() {return WebpackModules.getByProps("jumpToMessage", "_sendMessage");},
|
||||
get MessageQueue() {return WebpackModules.getByProps("enqueue");},
|
||||
get MessageParser() {return WebpackModules.getByProps("createMessage", "parse", "unparse");},
|
||||
|
||||
/* Text Processing */
|
||||
get hljs() {return WebpackModules.getByProps("highlight", "highlightBlock");},
|
||||
get SimpleMarkdown() {return WebpackModules.getByProps("parseBlock", "parseInline", "defaultOutput");},
|
||||
|
||||
/* Experiments */
|
||||
get ExperimentStore() {return WebpackModules.getByProps("getExperimentOverrides");},
|
||||
get ExperimentsManager() {return WebpackModules.getByProps("isDeveloper");},
|
||||
get CurrentExperiment() {return WebpackModules.getByProps("getExperimentId");},
|
||||
|
||||
/* Images, Avatars and Utils */
|
||||
get ImageResolver() {return WebpackModules.getByProps("getUserAvatarURL", "getGuildIconURL");},
|
||||
get ImageUtils() {return WebpackModules.getByProps("getSizedImageSrc");},
|
||||
get AvatarDefaults() {return WebpackModules.getByProps("getUserAvatarURL", "DEFAULT_AVATARS");},
|
||||
|
||||
/* Window, DOM, HTML */
|
||||
get WindowInfo() {return WebpackModules.getByProps("isFocused", "windowSize");},
|
||||
get TagInfo() {return WebpackModules.getByProps("VALID_TAG_NAMES");},
|
||||
get DOMInfo() {return WebpackModules.getByProps("canUseDOM");},
|
||||
|
||||
/* Locale/Location and Time */
|
||||
get LocaleManager() {return WebpackModules.getByProps("setLocale");},
|
||||
get Moment() {return WebpackModules.getByProps("parseZone");},
|
||||
get LocationManager() {return WebpackModules.getByProps("createLocation");},
|
||||
get Timestamps() {return WebpackModules.getByProps("fromTimestamp");},
|
||||
get TimeFormatter() {return WebpackModules.getByProps("dateFormat");},
|
||||
|
||||
/* Strings and Utils */
|
||||
get Strings() {return WebpackModules.getByProps("Messages").Messages;},
|
||||
get StringFormats() {return WebpackModules.getByProps("a", "z");},
|
||||
get StringUtils() {return WebpackModules.getByProps("toASCII");},
|
||||
|
||||
/* URLs and Utils */
|
||||
get URLParser() {return WebpackModules.getByProps("Url", "parse");},
|
||||
get ExtraURLs() {return WebpackModules.getByProps("getArticleURL");},
|
||||
|
||||
/* Drag & Drop */
|
||||
get DNDActions() {return WebpackModules.getByProps("beginDrag");},
|
||||
get DNDSources() {return WebpackModules.getByProps("addTarget");},
|
||||
get DNDObjects() {return WebpackModules.getByProps("DragSource");},
|
||||
|
||||
/* Media Stuff (Audio/Video) */
|
||||
get MediaDeviceInfo() {return WebpackModules.getByProps("Codecs", "SUPPORTED_BROWSERS");},
|
||||
get MediaInfo() {return WebpackModules.getByProps("getOutputVolume");},
|
||||
get MediaEngineInfo() {return WebpackModules.getByProps("MediaEngineFeatures");},
|
||||
get VoiceInfo() {return WebpackModules.getByProps("EchoCancellation");},
|
||||
get VideoStream() {return WebpackModules.getByProps("getVideoStream");},
|
||||
get SoundModule() {return WebpackModules.getByProps("playSound");},
|
||||
|
||||
/* Electron & Other Internals with Utils*/
|
||||
get ElectronModule() {return WebpackModules.getByProps("setBadge");},
|
||||
get Dispatcher() {return WebpackModules.getByProps("dispatch", "subscribe", "register");},
|
||||
get PathUtils() {return WebpackModules.getByProps("hasBasename");},
|
||||
get NotificationModule() {return WebpackModules.getByProps("showNotification");},
|
||||
get RouterModule() {return WebpackModules.getByProps("Router");},
|
||||
get APIModule() {return WebpackModules.getByProps("getAPIBaseURL");},
|
||||
get AnalyticEvents() {return WebpackModules.getByProps("AnalyticEventConfigs");},
|
||||
get KeyGenerator() {return WebpackModules.getByRegex(/"binary"/);},
|
||||
get Buffers() {return WebpackModules.getByProps("INSPECT_MAX_BYTES", "kMaxLength");},
|
||||
get DeviceStore() {return WebpackModules.getByProps("getDevices");},
|
||||
get SoftwareInfo() {return WebpackModules.getByProps("os");},
|
||||
get CurrentContext() {return WebpackModules.getByProps("setTagsContext");},
|
||||
|
||||
/* Commonly Used Classes */
|
||||
get GuildClasses() {
|
||||
const guildsWrapper = WebpackModules.getByProps("base", "guilds");
|
||||
const guilds = WebpackModules.getByProps("wrapper", "acronym");
|
||||
const pill = WebpackModules.getByProps("circleIconButton");
|
||||
const listItem = WebpackModules.getModule(m => m.listItem && !m.pill && !m.sidebar);
|
||||
return Object.assign({}, guildsWrapper, guilds, pill, listItem);
|
||||
},
|
||||
|
||||
get LayerStack() {return WebpackModules.getByProps("pushLayer");},
|
||||
|
||||
get Tooltip() {
|
||||
// Make fallback component just pass children, so it can at least render that.
|
||||
const fallback = props => props.children?.({}) ?? null;
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
// import Selector from "./selector";
|
||||
|
||||
/**
|
||||
* Representation of a Class Name
|
||||
**/
|
||||
class ClassName {
|
||||
/**
|
||||
*
|
||||
* @param {string} name - name of the class to represent
|
||||
*/
|
||||
constructor(name) {
|
||||
this.value = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates new class names to the current one using spaces.
|
||||
* @param {string} classNames - list of class names to add to this class name
|
||||
* @returns {ClassName} returns self to allow chaining
|
||||
*/
|
||||
add(...classNames) {
|
||||
for (let i = 0; i < classNames.length; i++) this.value += " " + classNames[i];
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw class name, this is how native function get the value.
|
||||
* @returns {string} raw class name.
|
||||
*/
|
||||
toString() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw class name, this is how native function get the value.
|
||||
* @returns {string} raw class name.
|
||||
*/
|
||||
valueOf() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
get single() {
|
||||
return this.value.split(" ")[0];
|
||||
}
|
||||
|
||||
get first() {
|
||||
return this.value.split(" ")[0];
|
||||
}
|
||||
}
|
||||
|
||||
export default ClassName;
|
|
@ -3,9 +3,9 @@ import Utilities from "@modules/utilities";
|
|||
|
||||
|
||||
export default class SimpleMarkdownExt {
|
||||
static parseToReact(str) {
|
||||
static parseToReact(str, inline = true) {
|
||||
if (!this._parser) this._initialize();
|
||||
return this._renderer(this._parse(str, {inline: true}));
|
||||
return this._renderer(this._parse(str, {inline}));
|
||||
}
|
||||
|
||||
static _initialize() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.bd-button {
|
||||
/* .bd-button {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
@ -59,4 +59,539 @@
|
|||
|
||||
.bd-button-disabled:hover {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
} */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Generic Button Styles */
|
||||
.bd-button {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 16px;
|
||||
padding: 2px 16px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.bd-button:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.bd-button .bd-button-content {
|
||||
--button--underline-color: transparent;
|
||||
background-image: linear-gradient(0deg, transparent, transparent 1px, var(--button--underline-color) 0, var(--button--underline-color) 2px, transparent 0);
|
||||
}
|
||||
|
||||
.bd-button:disabled .bd-button-content {
|
||||
background-image: none !important;
|
||||
}
|
||||
|
||||
.bd-button-outlined:disabled {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Button Sizes */
|
||||
.bd-button-tiny {
|
||||
width: 52px;
|
||||
height: 24px;
|
||||
min-width: 52px;
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
.bd-button-small {
|
||||
width: 60px;
|
||||
height: 32px;
|
||||
min-width: 60px;
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.bd-button-medium {
|
||||
width: 96px;
|
||||
height: 38px;
|
||||
min-width: 96px;
|
||||
min-height: 38px;
|
||||
}
|
||||
|
||||
.bd-button-large {
|
||||
width: 130px;
|
||||
height: 44px;
|
||||
min-width: 130px;
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
.bd-button-xlarge {
|
||||
width: 148px;
|
||||
height: 50px;
|
||||
min-width: 148px;
|
||||
min-height: 50px;
|
||||
font-size: 16px;
|
||||
line-height: normal;
|
||||
padding: 2px 20px;
|
||||
}
|
||||
|
||||
.bd-button-icon {
|
||||
height: auto;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.bd-button-grow,
|
||||
.bd-button-icon {
|
||||
width: auto
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Button Looks */
|
||||
.bd-button-filled {
|
||||
-webkit-transition: background-color .17s ease, color .17s ease;
|
||||
transition: background-color .17s ease, color .17s ease
|
||||
}
|
||||
|
||||
.bd-button-outlined {
|
||||
-webkit-transition: color .17s ease, background-color .17s ease, border-color .17s ease;
|
||||
transition: color .17s ease, background-color .17s ease, border-color .17s ease;
|
||||
border-width: 1px;
|
||||
border-style: solid
|
||||
}
|
||||
|
||||
.bd-button-blank {
|
||||
background: transparent;
|
||||
color: currentColor;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
.bd-button-filled .bd-button-content,
|
||||
.bd-button-link .bd-button-content,
|
||||
.bd-button-outlined .bd-button-content {
|
||||
margin: 0 auto;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* COLORS */
|
||||
|
||||
/* Color BD Brand */
|
||||
.bd-button-filled.bd-button-color-brand {
|
||||
color: var(--white-500);
|
||||
background-color: #3E82E5; /* BD Blue */
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-brand:hover {
|
||||
background-color: #3875CE;
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-brand:active {
|
||||
background-color: #3268B7;
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-brand:disabled {
|
||||
background-color: #3E82E5; /* BD Blue */
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-brand {
|
||||
color: var(--button-outline-brand-text);
|
||||
border-color: var(--button-outline-brand-border);
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-brand:hover {
|
||||
background-color: var(--button-outline-brand-background-hover);
|
||||
border-color: var(--button-outline-brand-border-hover);
|
||||
color: var(--button-outline-brand-text-hover);
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-brand:active {
|
||||
background-color: var(--button-outline-brand-background-active);
|
||||
border-color: var(--button-outline-brand-border-active);
|
||||
color: var(--button-outline-brand-text-active);
|
||||
}
|
||||
|
||||
.bd-button-link.bd-button-color-brand {
|
||||
color: #3E82E5; /* BD Blue */
|
||||
}
|
||||
|
||||
.bd-button-link.bd-button-color-brand:hover .bd-button-content {
|
||||
--button--underline-color: #3E82E5; /* BD Blue */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Color Blurple */
|
||||
.bd-button-filled.bd-button-color-blurple {
|
||||
color: var(--white-500);
|
||||
background-color: var(--brand-experiment)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-blurple:hover {
|
||||
background-color: var(--brand-experiment-560)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-blurple:active {
|
||||
background-color: var(--brand-experiment-600)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-blurple:disabled {
|
||||
background-color: var(--brand-experiment)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-blurple {
|
||||
color: var(--button-outline-brand-text);
|
||||
border-color: var(--button-outline-brand-border)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-blurple:hover {
|
||||
background-color: var(--button-outline-brand-background-hover);
|
||||
border-color: var(--button-outline-brand-border-hover);
|
||||
color: var(--button-outline-brand-text-hover)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-blurple:active {
|
||||
background-color: var(--button-outline-brand-background-active);
|
||||
border-color: var(--button-outline-brand-border-active);
|
||||
color: var(--button-outline-brand-text-active)
|
||||
}
|
||||
|
||||
.bd-button-link.bd-button-color-blurple {
|
||||
color: var(--brand-experiment)
|
||||
}
|
||||
|
||||
.bd-button-link.bd-button-color-blurple:hover .bd-button-content {
|
||||
--button--underline-color: var(--brand-experiment)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Color Yellow/Warn */
|
||||
.bd-button-filled.bd-button-color-yellow {
|
||||
color: var(--white-500);
|
||||
background-color: var(--status-warning)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-yellow:active,
|
||||
.bd-button-filled.bd-button-color-yellow:hover {
|
||||
background-color: null;
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-yellow:disabled {
|
||||
background-color: var(--status-warning)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-yellow {
|
||||
color: var(--status-warning);
|
||||
border-color: var(--status-warning)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-yellow:active {
|
||||
background-color: hsl(var(--yellow-300-hsl)/.1)
|
||||
}
|
||||
|
||||
.bd-button-link.bd-button-color-yellow {
|
||||
color: var(--status-warning)
|
||||
}
|
||||
|
||||
.bd-button-link.bd-button-color-yellow:hover .bd-button-content {
|
||||
--button--underline-color: var(--status-warning)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Color Link */
|
||||
.bd-button-filled.bd-button-color-link {
|
||||
color: var(--white-500);
|
||||
background-color: var(--text-link)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-link:active,
|
||||
.bd-button-filled.bd-button-color-link:hover {
|
||||
background-color: null
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-link:disabled {
|
||||
background-color: var(--text-link)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-link {
|
||||
color: var(--text-link);
|
||||
border-color: var(--text-link)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-link:active {
|
||||
background-color: hsl(var(--text-link-hsl)/.1)
|
||||
}
|
||||
|
||||
.bd-button-link.bd-button-color-link {
|
||||
color: var(--text-link)
|
||||
}
|
||||
|
||||
.bd-button-link.bd-button-color-link:hover .bd-button-content {
|
||||
--button--underline-color: var(--text-link)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Color White */
|
||||
.bd-button-filled.bd-button-color-white {
|
||||
color: var(--primary-500);
|
||||
background-color: var(--white-500)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-white:active,
|
||||
.bd-button-filled.bd-button-color-white:hover {
|
||||
background-color: null
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-white:disabled {
|
||||
background-color: var(--white-500)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-white {
|
||||
color: var(--white-500);
|
||||
border-color: var(--white-500)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-white:active {
|
||||
background-color: hsl(var(--white-500-hsl)/.1)
|
||||
}
|
||||
|
||||
.bd-button-link.bd-button-color-white {
|
||||
color: var(--white-500)
|
||||
}
|
||||
|
||||
.bd-button-link.bd-button-color-white:hover .bd-button-content {
|
||||
--button--underline-color: var(--white-500)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Color Red/Danger/Error */
|
||||
.bd-button-filled.bd-button-color-red {
|
||||
color: var(--white-500);
|
||||
background-color: var(--button-danger-background)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-red:hover {
|
||||
background-color: var(--button-danger-background-hover)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-red:active {
|
||||
background-color: var(--button-danger-background-active)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-red:disabled {
|
||||
background-color: var(--button-danger-background-disabled)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-red {
|
||||
color: var(--button-outline-danger-text);
|
||||
border-color: var(--button-outline-danger-border)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-red:hover {
|
||||
background-color: var(--button-outline-danger-background-hover);
|
||||
border-color: var(--button-outline-danger-border-hover);
|
||||
color: var(--button-outline-danger-text-hover)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-red:active {
|
||||
background-color: var(--button-outline-danger-background-active);
|
||||
border-color: var(--button-outline-danger-border-active);
|
||||
color: var(--button-outline-danger-text-active)
|
||||
}
|
||||
|
||||
.bd-button-link.bd-button-color-red {
|
||||
color: var(--text-danger)
|
||||
}
|
||||
|
||||
.bd-button-link.bd-button-color-red:hover .bd-button-content {
|
||||
--button--underline-color: var(--text-danger)
|
||||
}
|
||||
|
||||
|
||||
/* Color Green Success */
|
||||
.bd-button-filled.bd-button-color-green {
|
||||
color: var(--white-500);
|
||||
background-color: var(--button-positive-background)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-green:hover {
|
||||
background-color: var(--button-positive-background-hover)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-green:active {
|
||||
background-color: var(--button-positive-background-active)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-green:disabled {
|
||||
background-color: var(--button-positive-background-disabled)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-green {
|
||||
color: var(--button-outline-positive-text);
|
||||
border-color: var(--button-outline-positive-border)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-green:hover {
|
||||
background-color: var(--button-outline-positive-background-hover);
|
||||
border-color: var(--button-outline-positive-border-hover);
|
||||
color: var(--button-outline-positive-text-hover)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-green:active {
|
||||
background-color: var(--button-outline-positive-background-active);
|
||||
border-color: var(--button-outline-positive-border-active);
|
||||
color: var(--button-outline-positive-text-active)
|
||||
}
|
||||
|
||||
.bd-button-link.bd-button-color-green {
|
||||
color: var(--green-360)
|
||||
}
|
||||
|
||||
.bd-button-link.bd-button-color-green:hover .bd-button-content {
|
||||
--button--underline-color: var(--green-360)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Color Primary/Grey */
|
||||
.bd-button-outlined.bd-button-color-primary {
|
||||
color: var(--button-outline-primary-text);
|
||||
border-color: var(--button-outline-primary-border)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-primary:hover {
|
||||
background-color: var(--button-outline-primary-background-hover);
|
||||
border-color: var(--button-outline-primary-border-hover);
|
||||
color: var(--button-outline-primary-text-hover)
|
||||
}
|
||||
|
||||
.bd-button-outlined.bd-button-color-primary:active {
|
||||
background-color: var(--button-outline-primary-background-active);
|
||||
border-color: var(--button-outline-primary-border-active);
|
||||
color: var(--button-outline-primary-text-active)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-primary {
|
||||
color: var(--white-500);
|
||||
background-color: var(--button-secondary-background)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-primary:hover {
|
||||
background-color: var(--button-secondary-background-hover)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-primary:active {
|
||||
background-color: var(--button-secondary-background-active)
|
||||
}
|
||||
|
||||
.bd-button-filled.bd-button-color-primary:disabled {
|
||||
background-color: var(--button-secondary-background-disabled)
|
||||
}
|
||||
|
||||
.theme-dark .bd-button-link.bd-button-color-primary {
|
||||
color: var(--white-500)
|
||||
}
|
||||
|
||||
.theme-dark .bd-button-link.bd-button-color-primary:hover .bd-button-content {
|
||||
--button--underline-color: var(--white-500)
|
||||
}
|
||||
|
||||
.theme-light .bd-button-link.bd-button-color-primary {
|
||||
color: var(--primary-400)
|
||||
}
|
||||
|
||||
.theme-light .bd-button-link.bd-button-color-primary:hover .bd-button-content {
|
||||
--button--underline-color: var(--primary-400)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Color Transparent */
|
||||
.theme-dark .bd-button-filled.bd-button-color-transparent {
|
||||
color: var(--primary-100);
|
||||
background-color: hsl(var(--white-500-hsl)/.1)
|
||||
}
|
||||
|
||||
.theme-dark .bd-button-filled.bd-button-color-transparent:hover {
|
||||
background-color: hsl(var(--white-500-hsl)/.05)
|
||||
}
|
||||
|
||||
.theme-dark .bd-button-filled.bd-button-color-transparent:active {
|
||||
background-color: hsl(var(--white-500-hsl)/.01)
|
||||
}
|
||||
|
||||
.theme-dark .bd-button-filled.bd-button-color-transparent:disabled {
|
||||
background-color: hsl(var(--white-500-hsl)/.1)
|
||||
}
|
||||
|
||||
.theme-dark .bd-button-outlined.bd-button-color-transparent {
|
||||
color: var(--primary-200);
|
||||
border-color: var(--primary-200)
|
||||
}
|
||||
|
||||
.theme-dark .bd-button-outlined.bd-button-color-transparent:active {
|
||||
background-color: hsl(var(--primary-200-hsl)/.1)
|
||||
}
|
||||
|
||||
.theme-dark .bd-button-link.bd-button-color-transparent {
|
||||
color: var(--primary-200)
|
||||
}
|
||||
|
||||
.theme-dark .bd-button-link.bd-button-color-transparent:hover .bd-button-content {
|
||||
--button--underline-color: var(--primary-200)
|
||||
}
|
||||
|
||||
.theme-light .bd-button-filled.bd-button-color-transparent {
|
||||
color: var(--primary-400);
|
||||
background-color: hsl(var(--primary-400-hsl)/.01)
|
||||
}
|
||||
|
||||
.theme-light .bd-button-filled.bd-button-color-transparent:hover {
|
||||
background-color: hsl(var(--primary-400-hsl)/.2)
|
||||
}
|
||||
|
||||
.theme-light .bd-button-filled.bd-button-color-transparent:active {
|
||||
background-color: hsl(var(--primary-400-hsl)/.25)
|
||||
}
|
||||
|
||||
.theme-light .bd-button-filled.bd-button-color-transparent:disabled {
|
||||
background-color: hsl(var(--primary-400-hsl)/.01)
|
||||
}
|
||||
|
||||
.theme-light .bd-button-outlined.bd-button-color-transparent {
|
||||
color: var(--primary-400);
|
||||
border-color: var(--primary-400)
|
||||
}
|
||||
|
||||
.theme-light .bd-button-outlined.bd-button-color-transparent:active {
|
||||
background-color: hsl(var(--primary-400-hsl)/.1)
|
||||
}
|
||||
|
||||
.theme-light .bd-button-link.bd-button-color-transparent {
|
||||
color: var(--primary-400)
|
||||
}
|
||||
|
||||
.theme-light .bd-button-link.bd-button-color-transparent:hover .bd-button-content {
|
||||
--button--underline-color: var(--primary-400)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
@import "./buttons.css";
|
||||
@import "./spinner.css";
|
||||
@import "./search.css";
|
||||
@import "./text.css";
|
||||
|
||||
.bd-chat-badge {
|
||||
vertical-align: bottom;
|
||||
|
@ -19,23 +20,6 @@
|
|||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.bd-changelog-modal video,
|
||||
.bd-changelog-modal img {
|
||||
width: 100%;
|
||||
border-radius: 5px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.bd-changelog-modal code.inline {
|
||||
padding: 0.2em;
|
||||
margin: -0.2em 0;
|
||||
border-radius: 3px;
|
||||
font-size: 85%;
|
||||
line-height: 1.125rem;
|
||||
white-space: pre-wrap;
|
||||
background: var(--background-secondary);
|
||||
}
|
||||
|
||||
.bd-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
.bd-text-normal {
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.bd-text-muted {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.bd-text-error {
|
||||
color: var(--red-400);
|
||||
}
|
||||
|
||||
.bd-text-brand {
|
||||
color: var(--text-brand);
|
||||
}
|
||||
|
||||
.bd-text-link {
|
||||
color: var(--text-link);
|
||||
}
|
||||
|
||||
.bd-header-primary {
|
||||
color: var(--header-primary);
|
||||
}
|
||||
|
||||
.bd-header-secondary {
|
||||
color: var(--header-secondary);
|
||||
}
|
||||
|
||||
.bd-text-yellow {
|
||||
color: var(--text-warning);
|
||||
}
|
||||
|
||||
.bd-text-green {
|
||||
color: var(--text-positive);
|
||||
}
|
||||
|
||||
.bd-text-red {
|
||||
color: var(--status-danger);
|
||||
}
|
||||
|
||||
.bd-text-white {
|
||||
color: var(--white-500);
|
||||
}
|
||||
|
||||
.bd-text-10 {
|
||||
font-size: 10px;
|
||||
line-height: 12px;
|
||||
}
|
||||
|
||||
.bd-text-12 {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.bd-text-14 {
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.bd-text-16 {
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.bd-text-20 {
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.bd-text-24 {
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.bd-text-32 {
|
||||
font-size: 32px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.bd-text-strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.bd-selectable {
|
||||
user-select: text;
|
||||
}
|
|
@ -166,6 +166,7 @@
|
|||
|
||||
.bd-settings-title {
|
||||
color: var(--header-primary, #FFFFFF);
|
||||
display: flex;
|
||||
font-weight: 600;
|
||||
cursor: default;
|
||||
flex: 1;
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
.bd-changelog-modal video,
|
||||
.bd-changelog-modal img {
|
||||
width: 100%;
|
||||
border-radius: 5px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.bd-changelog-modal code.inline {
|
||||
padding: 0.2em;
|
||||
margin: -0.2em 0;
|
||||
border-radius: 3px;
|
||||
font-size: 85%;
|
||||
line-height: 1.125rem;
|
||||
white-space: pre-wrap;
|
||||
background: var(--background-secondary);
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content {
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content .emoji {
|
||||
object-fit: contain;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content h1 {
|
||||
line-height: 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content h1,
|
||||
.bd-changelog-modal .bd-modal-content h2,
|
||||
.bd-changelog-modal .bd-modal-content strong {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content em,
|
||||
.bd-changelog-modal .bd-modal-content i {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content p + p {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content ol {
|
||||
margin: 16px 0 16px 16px;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content ol li {
|
||||
list-style-type: decimal;
|
||||
margin-bottom: 8px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content ul {
|
||||
margin: 20px 0 8px 20px;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content ul ul {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content ul li {
|
||||
position: relative;
|
||||
list-style: none;
|
||||
margin-bottom: 8px;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content ul li:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content ul li::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: -15px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
margin-top: -4px;
|
||||
margin-left: -3px;
|
||||
border-radius: 50%;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content ul li li::before {
|
||||
top: 12px;
|
||||
height: 2px;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content a {
|
||||
color: hsl(200, calc(var(--saturation-factor, 1) * 100%), 49.4%);
|
||||
transition: 0.05s;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.bd-changelog-modal .bd-modal-content a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.theme-dark .bd-changelog-modal .bd-modal-content ol,
|
||||
.theme-dark .bd-changelog-modal .bd-modal-content p,
|
||||
.theme-dark .bd-changelog-modal .bd-modal-content ul li {
|
||||
color: hsl(210, calc(var(--saturation-factor, 1) * 9.3%), 78.8%);
|
||||
}
|
||||
|
||||
.theme-dark .bd-changelog-modal .bd-modal-content ul li::before {
|
||||
background-color: hsl(216, calc(var(--saturation-factor, 1) * 9.8%), 90%);
|
||||
}
|
||||
|
||||
.theme-light .bd-changelog-modal .bd-modal-content ol,
|
||||
.theme-light .bd-changelog-modal .bd-modal-content p,
|
||||
.theme-light .bd-changelog-modal .bd-modal-content ul li {
|
||||
color: hsl(223, calc(var(--saturation-factor, 1) * 5.8%), 52.9%);
|
||||
}
|
||||
|
||||
.theme-light .bd-changelog-modal .bd-modal-content ul li::before {
|
||||
background-color: hsl(223, calc(var(--saturation-factor, 1) * 5.8%), 52.9%);
|
||||
}
|
||||
|
||||
.bd-changelog-title {
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.bd-changelog-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.bd-changelog-title.bd-changelog-first {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.bd-changelog-title::after {
|
||||
content: "";
|
||||
height: 1px;
|
||||
flex: 1 1 auto;
|
||||
margin-left: 4px;
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
.bd-changelog-added {
|
||||
color: var(--text-positive);
|
||||
}
|
||||
|
||||
.bd-changelog-added::after {
|
||||
background-color: var(--info-positive-foreground);
|
||||
}
|
||||
|
||||
.bd-changelog-fixed {
|
||||
color: hsl(359, calc(var(--saturation-factor, 1)*87.3%), 59.8%);
|
||||
}
|
||||
|
||||
.bd-changelog-fixed::after {
|
||||
background-color: hsl(359, calc(var(--saturation-factor, 1)*87.3%), 59.8%);
|
||||
}
|
||||
|
||||
.bd-changelog-progress {
|
||||
color: var(--text-warning);
|
||||
}
|
||||
|
||||
.bd-changelog-progress::after {
|
||||
background-color: var(--info-warning-foreground);
|
||||
}
|
||||
|
||||
.bd-changelog-improved {
|
||||
color: hsl(235, calc(var(--saturation-factor, 1)*85.6%), 64.7%);
|
||||
}
|
||||
|
||||
.bd-changelog-improved::after {
|
||||
background-color: hsl(235, calc(var(--saturation-factor, 1)*85.6%), 64.7%);
|
||||
}
|
||||
|
||||
.theme-dark .bd-changelog-improved {
|
||||
color: hsl(235, calc(var(--saturation-factor, 1)*86.1%), 77.5%);
|
||||
}
|
||||
|
||||
.theme-dark .bd-changelog-improved::after {
|
||||
background-color: hsl(235, calc(var(--saturation-factor, 1)*86.1%), 77.5%);
|
||||
}
|
||||
|
||||
.theme-dark .bd-changelog-modal video,
|
||||
.theme-dark .bd-changelog-modal img {
|
||||
box-shadow: 0 2px 10px 0 hsl(var(0, calc(var(--saturation-factor, 1)*0%), 0%-hsl)/.2);
|
||||
}
|
||||
|
||||
.theme-light .bd-changelog-modal video,
|
||||
.theme-light .bd-changelog-modal img {
|
||||
box-shadow: 0 2px 10px 0 hsl(var(0, calc(var(--saturation-factor, 1)*0%), 0%-hsl)/.1);
|
||||
}
|
||||
|
||||
/* .socialLink-1qjJIk {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.theme-light .socialLink-1qjJIk {
|
||||
color: hsl(228, calc(var(--saturation-factor, 1)*6%), 32.5%);
|
||||
}
|
||||
|
||||
.theme-dark .socialLink-1qjJIk {
|
||||
color: hsl(210, calc(var(--saturation-factor, 1)*9.3%), 78.8%);
|
||||
} */
|
|
@ -78,4 +78,16 @@
|
|||
scrollbar-color: var(--background-tertiary) var(--background-secondary);
|
||||
background: var(--background-secondary);
|
||||
border: 1px solid var(--background-tertiary);
|
||||
}
|
||||
|
||||
.bd-addon-error-details {
|
||||
display: flex;
|
||||
flex-grow: 0;
|
||||
justify-content: flex-start;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.bd-addon-error-details-icon {
|
||||
margin-right: 4px;
|
||||
color: var(--interactive-normal);
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
.bd-flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.bd-flex-align-start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.bd-flex-align-end {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.bd-flex-align-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.bd-flex-align-stretch {
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.bd-flex-align-baseline {
|
||||
align-items: baseline
|
||||
}
|
||||
|
||||
.bd-flex-justify-start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.bd-flex-justify-end {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.bd-flex-justify-center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.bd-flex-justify-around {
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.bd-flex-justify-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.bd-flex-no-wrap {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.bd-flex-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.bd-flex-wrap-reverse {
|
||||
flex-wrap: wrap-reverse;
|
||||
}
|
||||
|
||||
.bd-flex-horizontal {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.bd-flex-reverse {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.bd-flex-vertical {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.spacer-2upayl {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bd-flex-vertical {}
|
||||
|
||||
.bd-flex-horizontal {}
|
||||
|
||||
.bd-flex-reverse {}
|
||||
|
||||
.bd-flex-horizontal > .spacer-2upayl,
|
||||
.bd-flex-reverse > .spacer-2upayl,
|
||||
.bd-flex-vertical > .spacer-2upayl {
|
||||
min-height: 1px;
|
||||
}
|
||||
|
||||
.flexCenter-1Mwsxg {}
|
||||
|
||||
.bd-flex {}
|
||||
|
||||
.bd-flex-horizontal {}
|
||||
|
||||
.bd-flex-reverse {}
|
||||
|
||||
.bd-flex-horizontal > .bd-flex,
|
||||
.bd-flex-horizontal > .bd-flex-child {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.bd-flex-horizontal > .bd-flex:first-child,
|
||||
.bd-flex-horizontal > .bd-flex-child:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.bd-flex-horizontal > .bd-flex:last-child,
|
||||
.bd-flex-horizontal > .bd-flex-child:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.bd-flex-reverse > .bd-flex,
|
||||
.bd-flex-reverse > .bd-flex-child {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.bd-flex-reverse > .bd-flex:first-child,
|
||||
.bd-flex-reverse > .bd-flex-child:first-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.bd-flex-reverse > .bd-flex:last-child,
|
||||
.bd-flex-reverse > .bd-flex-child:last-child {
|
||||
margin-left: 0;
|
||||
}
|
|
@ -71,3 +71,143 @@
|
|||
@keyframes bd-modal-open {
|
||||
from {transform: scale(0.7);}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.bd-modal-root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--modal-background);
|
||||
border-radius: 4px;
|
||||
margin: 0 auto;
|
||||
pointer-events: all;
|
||||
position: relative;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.bd-close-button {
|
||||
height: 26px;
|
||||
padding: 4px;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
opacity: 0.5;
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
color: var(--interactive-normal);
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.bd-close-button:hover {
|
||||
opacity: 1;
|
||||
color: var(--interactive-hover);
|
||||
}
|
||||
|
||||
.bd-modal-small {
|
||||
width: 440px;
|
||||
max-height: 720px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.bd-modal-standard {
|
||||
font-size: 13px;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
width: 490px;
|
||||
max-height: 800px;
|
||||
}
|
||||
|
||||
.bd-modal-medium {
|
||||
width: 600px;
|
||||
max-height: 800px;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.bd-modal-large {
|
||||
width: 800px;
|
||||
max-height: 960px;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.bd-modal-header,
|
||||
.bd-modal-footer {
|
||||
position: relative;
|
||||
flex: 0 0 auto;
|
||||
padding: 16px;
|
||||
z-index: 1;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.bd-modal-header {
|
||||
border-radius: 4px 4px 0 0;
|
||||
transition: box-shadow 0.1s ease-out;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.bd-modal-footer {
|
||||
border-radius: 0 0 5px 5px;
|
||||
background-color: var(--modal-footer-background);
|
||||
overflow: hidden;
|
||||
box-shadow: inset 0 1px 0 hsl(var(--primary-630-hsl)/0.6);
|
||||
}
|
||||
|
||||
.bd-modal-content {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
border-radius: 5px 5px 0 0;
|
||||
padding-left: 16px;
|
||||
/* padding-right: 16px; */
|
||||
overflow-x: hidden;
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
padding-bottom: 20px;
|
||||
overflow: hidden scroll;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.bd-modal-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: var(--devtools-sidebar-width,0);
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
-webkit-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
#bd-modal-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: var(--devtools-sidebar-width,0);
|
||||
bottom: 0;
|
||||
background: none!important;
|
||||
pointer-events: none;
|
||||
z-index: 1002;
|
||||
}
|
||||
|
||||
.bd-modal-layer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.bd-modal-layer {
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
padding-top: 40px;
|
||||
padding-bottom: 40px;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
.bd-scroller-base {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
min-height: 0;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.bd-scroller-thin {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--scrollbar-thin-thumb) var(--scrollbar-thin-track);
|
||||
}
|
||||
|
||||
.bd-scroller-thin::-webkit-scrollbar-track {
|
||||
border-color: var(--scrollbar-thin-track);
|
||||
background-color: var(--scrollbar-thin-track);
|
||||
border: 2px solid var(--scrollbar-thin-track);
|
||||
}
|
||||
|
||||
.bd-scroller-thin::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.bd-scroller-thin::-webkit-scrollbar-corner {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.bd-scroller-thin::-webkit-scrollbar-thumb {
|
||||
background-clip: padding-box;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 4px;
|
||||
background-color: var(--scrollbar-thin-thumb);
|
||||
min-height: 40px;
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
import React from "@modules/react";
|
||||
import Utilities from "@modules/utilities";
|
||||
|
||||
// S.Looks = y;
|
||||
// S.Colors = I;
|
||||
// S.BorderColors = O;
|
||||
// S.Hovers = T;
|
||||
// S.Sizes = v;
|
||||
|
||||
const {useCallback} = React;
|
||||
|
||||
export const Looks = Object.freeze({
|
||||
FILLED: "bd-button-filled",
|
||||
OUTLINED: "bd-button-outlined",
|
||||
LINK: "bd-button-link",
|
||||
BLANK: "bd-button-blank"
|
||||
});
|
||||
|
||||
export const Colors = Object.freeze({
|
||||
BRAND: "bd-button-color-brand",
|
||||
BLURPLE: "bd-button-color-blurple",
|
||||
RED: "bd-button-color-red",
|
||||
GREEN: "bd-button-color-green",
|
||||
YELLOW: "bd-button-color-yellow",
|
||||
PRIMARY: "bd-button-color-primary",
|
||||
LINK: "bd-button-color-link",
|
||||
WHITE: "bd-button-color-white",
|
||||
TRANSPARENT: "bd-button-color-transparent",
|
||||
CUSTOM: ""
|
||||
});
|
||||
|
||||
|
||||
export const Sizes = Object.freeze({
|
||||
NONE: "",
|
||||
TINY: "bd-button-tiny",
|
||||
SMALL: "bd-button-small",
|
||||
MEDIUM: "bd-button-medium",
|
||||
LARGE: "bd-button-large",
|
||||
ICON: "bd-button-icon"
|
||||
});
|
||||
|
||||
|
||||
export default function Button({
|
||||
className,
|
||||
children,
|
||||
onClick,
|
||||
onKeyDown,
|
||||
buttonRef,
|
||||
disabled = false,
|
||||
type = "button",
|
||||
look = Looks.FILLED,
|
||||
color = Colors.BRAND,
|
||||
size = Sizes.MEDIUM,
|
||||
grow = true
|
||||
}) {
|
||||
|
||||
const handleClick = useCallback(event => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
onClick?.(event);
|
||||
}, [onClick]);
|
||||
|
||||
return <button className={
|
||||
Utilities.className(
|
||||
"bd-button",
|
||||
className,
|
||||
look,
|
||||
color,
|
||||
size,
|
||||
grow ? "bd-button-grow" : ""
|
||||
)}
|
||||
ref={buttonRef}
|
||||
type={type === "button" ? null : type}
|
||||
onClick={disabled ? () => {} : handleClick}
|
||||
onKeyDown={disabled ? () => {} : onKeyDown}
|
||||
>
|
||||
<div className="bd-button-content">{children}</div>
|
||||
</button>;
|
||||
}
|
||||
|
||||
Button.Looks = Looks;
|
||||
Button.Colors = Colors;
|
||||
Button.Sizes = Sizes;
|
||||
// window.BDButton = Button;
|
||||
// (() => {
|
||||
// const buttons = [];
|
||||
// for (const look in window.BDButton.Looks) {
|
||||
// if (!window.BDButton.Looks[look] || look === "BLANK") continue;
|
||||
// for (const color in window.BDButton.Colors) {
|
||||
// if (!window.BDButton.Colors[color]) continue;
|
||||
// for (const size in window.BDButton.Sizes) {
|
||||
// if (!window.BDButton.Sizes[size]) continue;
|
||||
// buttons.push(window.BdApi.React.createElement(window.BDButton, {
|
||||
// look: window.BDButton.Looks[look],
|
||||
// color: window.BDButton.Colors[color],
|
||||
// size: window.BDButton.Sizes[size]
|
||||
// }, "Hello World!"));
|
||||
// buttons.push(window.BdApi.React.createElement("br"));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// window.BdApi.showConfirmationModal("Buttons", buttons);
|
||||
// })();
|
|
@ -0,0 +1,76 @@
|
|||
import React from "@modules/react";
|
||||
import Utilities from "@modules/utilities";
|
||||
|
||||
|
||||
export const Direction = Object.freeze({
|
||||
VERTICAL: "bd-flex-vertical",
|
||||
HORIZONTAL: "bd-flex-horizontal",
|
||||
HORIZONTAL_REVERSE: "bd-flex-reverse"
|
||||
});
|
||||
|
||||
export const Justify = Object.freeze({
|
||||
START: "bd-flex-justify-start",
|
||||
END: "bd-flex-justify-end",
|
||||
CENTER: "bd-flex-justify-center",
|
||||
BETWEEN: "bd-flex-justify-between",
|
||||
AROUND: "bd-flex-justify-around"
|
||||
});
|
||||
|
||||
export const Align = Object.freeze({
|
||||
START: "bd-flex-align-start",
|
||||
END: "bd-flex-align-end",
|
||||
CENTER: "bd-flex-align-center",
|
||||
STRETCH: "bd-flex-align-stretch",
|
||||
BASELINE: "bd-flex-align-baseline"
|
||||
});
|
||||
|
||||
export const Wrap = Object.freeze({
|
||||
NO_WRAP: "bd-flex-no-wrap",
|
||||
WRAP: "bd-flex-wrap",
|
||||
WRAP_REVERSE: "bd-flex-wrap-reverse"
|
||||
});
|
||||
|
||||
|
||||
export function Child(props) {
|
||||
if (!props.className) props.className = "";
|
||||
props.className = Utilities.className(props.className, "bd-flex-child");
|
||||
return <Flex {...props} />;
|
||||
}
|
||||
|
||||
|
||||
export default function Flex({
|
||||
children,
|
||||
className,
|
||||
style,
|
||||
shrink = 1,
|
||||
grow = 1,
|
||||
basis = "auto",
|
||||
direction = Direction.HORIZONTAL,
|
||||
align = Align.STRETCH,
|
||||
justify = Justify.START,
|
||||
wrap = Wrap.NO_WRAP
|
||||
}) {
|
||||
return <div
|
||||
className={Utilities.className(
|
||||
"bd-flex",
|
||||
direction,
|
||||
justify,
|
||||
align,
|
||||
wrap,
|
||||
className
|
||||
)}
|
||||
style={Object.assign({
|
||||
flexShrink: shrink,
|
||||
flexGrow: grow,
|
||||
flexBasis: basis
|
||||
}, style)}
|
||||
>
|
||||
{children}
|
||||
</div>;
|
||||
}
|
||||
|
||||
Flex.Child = Child;
|
||||
Flex.Direction = Direction;
|
||||
Flex.Align = Align;
|
||||
Flex.Justify = Justify;
|
||||
Flex.Wrap = Wrap;
|
|
@ -0,0 +1,35 @@
|
|||
import React from "@modules/react";
|
||||
import WebpackModules from "@modules/webpackmodules";
|
||||
import DiscordModules from "@modules/discordmodules";
|
||||
|
||||
|
||||
const DiscordMarkdown = WebpackModules.find(m => m?.prototype?.render && m.rules);
|
||||
let rules = {};
|
||||
if (DiscordMarkdown) {
|
||||
rules = {
|
||||
...DiscordMarkdown.rules,
|
||||
link: DiscordModules.SimpleMarkdown.defaultRules.link
|
||||
};
|
||||
|
||||
const originalLink = rules.link.react;
|
||||
rules.link.react = function() {
|
||||
const original = Reflect.apply(originalLink, undefined, arguments);
|
||||
original.props.className = "bd-link";
|
||||
original.props.target = "_blank";
|
||||
original.props.rel = "noopener noreferrer";
|
||||
return original;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export default function Markdown({className, children}) {
|
||||
if (!DiscordMarkdown) return <div className="bd-markdown-fallback">{children}</div>;
|
||||
|
||||
return <DiscordMarkdown
|
||||
className={className}
|
||||
parser={DiscordModules.SimpleMarkdown.parserFor(rules)}
|
||||
output={DiscordModules.SimpleMarkdown.reactFor(DiscordModules.SimpleMarkdown.ruleOutput(rules, "react"))}
|
||||
>
|
||||
{children}
|
||||
</DiscordMarkdown>;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
import React from "@modules/react";
|
||||
import Utilities from "@modules/utilities";
|
||||
|
||||
|
||||
export const Colors = Object.freeze({
|
||||
STANDARD: "bd-text-normal",
|
||||
MUTED: "bd-text-muted",
|
||||
ERROR: "bd-text-error",
|
||||
BRAND: "bd-text-brand",
|
||||
LINK: "bd-text-link",
|
||||
HEADER_PRIMARY: "bd-header-primary",
|
||||
HEADER_SECONDARY: "bd-header-secondary",
|
||||
STATUS_YELLOW: "bd-text-yellow",
|
||||
STATUS_GREEN: "bd-text-green",
|
||||
STATUS_RED: "bd-text-red",
|
||||
ALWAYS_WHITE: "bd-text-white",
|
||||
CUSTOM: null
|
||||
});
|
||||
|
||||
|
||||
export const Sizes = Object.freeze({
|
||||
SIZE_10: "bd-text-10",
|
||||
SIZE_12: "bd-text-12",
|
||||
SIZE_14: "bd-text-14",
|
||||
SIZE_16: "bd-text-16",
|
||||
SIZE_20: "bd-text-20",
|
||||
SIZE_24: "bd-text-24",
|
||||
SIZE_32: "bd-text-32"
|
||||
});
|
||||
|
||||
|
||||
export default function Text({tag: Tag = "div", className, children, color = Colors.STANDARD, size = Sizes.SIZE_14, selectable, strong, style}) {
|
||||
return <Tag
|
||||
className={
|
||||
Utilities.className(
|
||||
color, size, className,
|
||||
{
|
||||
"bd-selectable": selectable,
|
||||
"bd-text-strong": strong
|
||||
}
|
||||
)}
|
||||
style={style}
|
||||
>
|
||||
{children}
|
||||
</Tag>;
|
||||
}
|
||||
|
||||
Text.Colors = Colors;
|
||||
Text.Sizes = Sizes;
|
||||
|
||||
// te = WebpackModules.getModule(m => m?.Sizes?.SIZE_32 && m.Colors)
|
||||
// foo = []
|
||||
// for (const color in te.Colors) foo.push(BdApi.React.createElement(te, {color: te.Colors[color]}, color))
|
||||
// for (const size in te.Sizes) foo.push(BdApi.React.createElement(te, {size: te.Sizes[size]}, size))
|
||||
// BdApi.showConfirmationModal("Text Elements", foo)
|
|
@ -1,13 +1,15 @@
|
|||
import SimpleMarkdown from "@structs/markdown";
|
||||
|
||||
import React from "@modules/react";
|
||||
import DiscordClasses from "@modules/discordclasses";
|
||||
import WebpackModules from "@modules/webpackmodules";
|
||||
|
||||
|
||||
const EmptyImageClasses = WebpackModules.getByProps("emptyImage", "emptyHeader") ?? {emptyContainer: "emptyContainer-poti7J", emptyImage: "emptyImage-2pCD2j", emptyHeader: "emptyHeader-2cxTFP"};
|
||||
|
||||
export default function EmptyImage(props) {
|
||||
return <div className={`bd-empty-image-container ${DiscordClasses.EmptyImage.emptyContainer}` + (props.className ? ` ${props.className}` : "")}>
|
||||
<div className={`bd-empty-image ${DiscordClasses.EmptyImage.emptyImage}`}></div>
|
||||
<div className={`bd-empty-image-header ${DiscordClasses.EmptyImage.emptyHeader}`}>
|
||||
return <div className={`bd-empty-image-container ${EmptyImageClasses.emptyContainer}` + (props.className ? ` ${props.className}` : "")}>
|
||||
<div className={`bd-empty-image ${EmptyImageClasses.emptyImage}`}></div>
|
||||
<div className={`bd-empty-image-header ${EmptyImageClasses.emptyHeader}`}>
|
||||
{props.title || "You don't have anything!"}
|
||||
</div>
|
||||
<div className={`bd-empty-image-message`}>
|
||||
|
|
|
@ -7,18 +7,30 @@ import React from "@modules/react";
|
|||
import ReactDOM from "@modules/reactdom";
|
||||
import Strings from "@modules/strings";
|
||||
import Settings from "@modules/settingsmanager";
|
||||
import Events from "@modules/emitter";
|
||||
import DiscordModules from "@modules/discordmodules";
|
||||
import WebpackModules from "@modules/webpackmodules";
|
||||
import DiscordClasses from "@modules/discordclasses";
|
||||
import DOMManager from "@modules/dommanager";
|
||||
|
||||
import AddonErrorModal from "./addonerrormodal";
|
||||
import AddonErrorModal from "./modals/addonerrormodal";
|
||||
import ErrorBoundary from "./errorboundary";
|
||||
import TextElement from "./base/text";
|
||||
import ModalRoot from "./modals/root";
|
||||
import ModalHeader from "./modals/header";
|
||||
import ModalContent from "./modals/content";
|
||||
import ModalFooter from "./modals/footer";
|
||||
|
||||
import ConfirmationModal from "./modals/confirmation";
|
||||
import Button from "./base/button";
|
||||
import CustomMarkdown from "./base/markdown";
|
||||
import ChangelogModal from "./modals/changelog";
|
||||
import ModalStack, {generateKey} from "./modals/stack";
|
||||
|
||||
|
||||
export default class Modals {
|
||||
|
||||
static get shouldShowAddonErrors() {return Settings.get("settings", "addons", "addonErrors");}
|
||||
static get hasModalOpen() {return !!document.getElementsByClassName("bd-modal").length;}
|
||||
|
||||
static get ModalActions() {
|
||||
return this._ModalActions ??= {
|
||||
|
@ -26,21 +38,11 @@ export default class Modals {
|
|||
closeModal: WebpackModules.getModule(m => typeof m === "function" && m?.toString().includes("onCloseCallback()"), {searchExports: true})
|
||||
};
|
||||
}
|
||||
static get ModalStack() {return this._ModalStack ??= WebpackModules.getByProps("push", "update", "pop", "popWithKey");}
|
||||
static get ModalComponents() {return this._ModalComponents ??= WebpackModules.getByProps("Header", "Footer");}
|
||||
static get ModalRoot() {return this._ModalRoot ??= WebpackModules.getModule(m => m?.toString?.()?.includes("ENTERING") && m?.toString?.()?.includes("headerId"), {searchExports: true});}
|
||||
static get ModalClasses() {return this._ModalClasses ??= WebpackModules.getByProps("modal", "content");}
|
||||
static get FlexElements() {return this._FlexElements ??= WebpackModules.getByProps("Child", "Align");}
|
||||
static get TextElement() {return this._TextElement ??= WebpackModules.getModule(m => m?.Sizes?.SIZE_32 && m.Colors);}
|
||||
static get ConfirmationModal() {return this._ConfirmationModal ??= WebpackModules.getModule(m => m?.toString?.()?.includes(".confirmButtonColor"), {searchExports: true});}
|
||||
static get Markdown() {return this._Markdown ??= WebpackModules.find(m => m?.prototype?.render && m.rules);}
|
||||
static get Buttons() {return this._Buttons ??= WebpackModules.getModule(m => m.BorderColors, {searchExports: true});}
|
||||
|
||||
static get ModalQueue() {return this._ModalQueue ??= [];}
|
||||
|
||||
static get hasModalOpen() {return !!document.getElementsByClassName("bd-modal").length;}
|
||||
|
||||
static async initialize() {
|
||||
const names = ["ConfirmationModal", "ModalActions", "Markdown", "ModalRoot", "ModalComponents", "Buttons", "TextElement", "FlexElements"];
|
||||
const names = ["ModalActions"];
|
||||
|
||||
for (const name of names) {
|
||||
let value = this[name];
|
||||
|
@ -164,8 +166,6 @@ export default class Modals {
|
|||
* @returns {string} - the key used for this modal
|
||||
*/
|
||||
static showConfirmationModal(title, content, options = {}) {
|
||||
const Markdown = this.Markdown;
|
||||
const ConfirmationModal = this.ConfirmationModal;
|
||||
const ModalActions = this.ModalActions;
|
||||
|
||||
if (content instanceof FormattableString) content = content.toString();
|
||||
|
@ -173,7 +173,7 @@ export default class Modals {
|
|||
const emptyFunction = () => {};
|
||||
const {onConfirm = emptyFunction, onCancel = emptyFunction, confirmText = Strings.Modals.okay, cancelText = Strings.Modals.cancel, danger = false, key = undefined} = options;
|
||||
|
||||
if (!this.ModalActions || !this.ConfirmationModal || !this.Markdown) {
|
||||
if (!this.ModalActions) {
|
||||
return this.default(title, content, [
|
||||
confirmText && {label: confirmText, action: onConfirm},
|
||||
cancelText && {label: cancelText, action: onCancel, danger}
|
||||
|
@ -181,9 +181,9 @@ export default class Modals {
|
|||
}
|
||||
|
||||
if (!Array.isArray(content)) content = [content];
|
||||
content = content.map(c => typeof(c) === "string" ? React.createElement(Markdown, null, c) : c);
|
||||
content = content.map(c => typeof(c) === "string" ? React.createElement(CustomMarkdown, null, c) : c);
|
||||
|
||||
const modalKey = ModalActions.openModal(props => {
|
||||
const modalKey = this.openModal(props => {
|
||||
return React.createElement(ErrorBoundary, {
|
||||
onError: () => {
|
||||
setTimeout(() => {
|
||||
|
@ -196,7 +196,7 @@ export default class Modals {
|
|||
}
|
||||
}, React.createElement(ConfirmationModal, Object.assign({
|
||||
header: title,
|
||||
confirmButtonColor: danger ? this.Buttons.Colors.RED : this.Buttons.Colors.BRAND,
|
||||
danger: danger,
|
||||
confirmText: confirmText,
|
||||
cancelText: cancelText,
|
||||
onConfirm: onConfirm,
|
||||
|
@ -209,87 +209,22 @@ export default class Modals {
|
|||
static showAddonErrors({plugins: pluginErrors = [], themes: themeErrors = []}) {
|
||||
if (!pluginErrors || !themeErrors || !this.shouldShowAddonErrors) return;
|
||||
if (!pluginErrors.length && !themeErrors.length) return;
|
||||
|
||||
if (this.addonErrorsRef && this.addonErrorsRef.current) {
|
||||
return this.addonErrorsRef.current.refreshTabs(Array.isArray(pluginErrors) ? pluginErrors : [], Array.isArray(themeErrors) ? themeErrors : []);
|
||||
}
|
||||
|
||||
this.addonErrorsRef = React.createRef();
|
||||
this.ModalActions.openModal(props => React.createElement(ErrorBoundary, null, React.createElement(this.ModalRoot, Object.assign(props, {
|
||||
size: "medium",
|
||||
className: "bd-error-modal",
|
||||
children: [
|
||||
React.createElement(AddonErrorModal, {
|
||||
ref: this.addonErrorsRef,
|
||||
pluginErrors: Array.isArray(pluginErrors) ? pluginErrors : [],
|
||||
themeErrors: Array.isArray(themeErrors) ? themeErrors : [],
|
||||
onClose: props.onClose
|
||||
}),
|
||||
React.createElement(this.ModalComponents.Footer, {
|
||||
className: "bd-error-modal-footer",
|
||||
}, React.createElement(this.Buttons, {
|
||||
onClick: props.onClose,
|
||||
className: "bd-button"
|
||||
}, Strings.Modals.okay))
|
||||
]
|
||||
}))));
|
||||
const options = {
|
||||
ref: this.addonErrorsRef,
|
||||
pluginErrors: Array.isArray(pluginErrors) ? pluginErrors : [],
|
||||
themeErrors: Array.isArray(themeErrors) ? themeErrors : []
|
||||
};
|
||||
this.openModal(props => {
|
||||
return React.createElement(ErrorBoundary, null, React.createElement(AddonErrorModal, Object.assign(options, props)));
|
||||
});
|
||||
}
|
||||
|
||||
static showChangelogModal(options = {}) {
|
||||
const OriginalModalClasses = WebpackModules.getByProps("hideOnFullscreen", "root");
|
||||
const ChangelogModalClasses = WebpackModules.getModule(m => m.modal && m.maxModalWidth);
|
||||
const ChangelogClasses = WebpackModules.getByProps("fixed", "improved") ?? {maxModalWidth: "490px",video: "video-8B-TdZ",container: "container-3PVapX",image: "image-ZPv20Y",title: "title-2ftWWc",lead: "lead-2VtcIe",added: "added-mQcv9V title-2ftWWc",fixed: "fixed-cTX7Hp title-2ftWWc",improved: "improved-2SJXHz title-2ftWWc",progress: "progress-1DcfFh title-2ftWWc",marginTop: "marginTop-VGmU1T",footer: "footer-1gMODG",socialLink: "socialLink-1qjJIk",premiumBanner: "premiumBanner-FU1Urp",premiumIcon: "premiumIcon-rhwgnW",date: "date-2tmzZM"};
|
||||
const TextElement = this.TextElement;
|
||||
const FlexChild = this.FlexElements;
|
||||
const MarkdownParser = WebpackModules.getByProps("defaultRules", "parse");
|
||||
options = Object.assign({image: "https://i.imgur.com/wuh5yMK.png", description: "", changes: [], title: "BetterDiscord", subtitle: `v${Config.version}`}, options);
|
||||
|
||||
if (!OriginalModalClasses || !ChangelogModalClasses || !ChangelogClasses || !TextElement || !FlexChild || !MarkdownParser) return Logger.warn("Modals", "showChangelogModal missing modules");
|
||||
|
||||
const {image = "https://i.imgur.com/wuh5yMK.png", description = "", changes = [], title = "BetterDiscord", subtitle = `v${Config.version}`, footer} = options;
|
||||
const ce = React.createElement;
|
||||
const changelogItems = [options.video ? ce("video", {src: options.video, poster: options.poster, controls: true, className: ChangelogClasses.video}) : ce("img", {src: image})];
|
||||
if (description) changelogItems.push(ce("p", null, MarkdownParser.parse(description)));
|
||||
for (let c = 0; c < changes.length; c++) {
|
||||
const entry = changes[c];
|
||||
const type = ChangelogClasses[entry.type] ? ChangelogClasses[entry.type] : ChangelogClasses.added;
|
||||
const margin = c == 0 ? ChangelogClasses.marginTop : "";
|
||||
changelogItems.push(ce("h1", {className: `${type} ${margin}`,}, entry.title));
|
||||
if (entry.description) changelogItems.push(ce("p", null, MarkdownParser.parse(entry.description)));
|
||||
const list = ce("ul", null, entry.items.map(i => ce("li", null, MarkdownParser.parse(i))));
|
||||
changelogItems.push(list);
|
||||
}
|
||||
const renderHeader = function() {
|
||||
return ce(FlexChild, {className: OriginalModalClasses.header, grow: 0, shrink: 0, direction: FlexChild.Direction.VERTICAL},
|
||||
ce(TextElement, {tag: "h1", size: TextElement.Sizes.SIZE_20, strong: true}, title),
|
||||
ce(TextElement, {size: TextElement.Sizes.SIZE_12, color: TextElement.Colors.STANDARD, className: ChangelogClasses.date}, subtitle)
|
||||
);
|
||||
};
|
||||
|
||||
const renderFooter = () => {
|
||||
const AnchorClasses = WebpackModules.getByProps("anchorUnderlineOnHover") || {anchor: "anchor-3Z-8Bb", anchorUnderlineOnHover: "anchorUnderlineOnHover-2ESHQB"};
|
||||
const joinSupportServer = (click) => {
|
||||
click.preventDefault();
|
||||
click.stopPropagation();
|
||||
DiscordModules.InviteActions.acceptInviteAndTransitionToInviteChannel({inviteKey: "0Tmfo5ZbORCRqbAd"});
|
||||
};
|
||||
const supportLink = ce("a", {className: `${AnchorClasses.anchor} ${AnchorClasses.anchorUnderlineOnHover}`, onClick: joinSupportServer}, "Join our Discord Server.");
|
||||
const defaultFooter = ce(TextElement, {size: TextElement.Sizes.SIZE_12, color: TextElement.Colors.STANDARD}, "Need support? ", supportLink);
|
||||
return ce(FlexChild, {className: OriginalModalClasses.footer + " " + OriginalModalClasses.footerSeparator},
|
||||
ce(FlexChild.Child, {grow: 1, shrink: 1}, footer ? footer : defaultFooter)
|
||||
);
|
||||
};
|
||||
|
||||
const body = ce("div", {
|
||||
className: `${OriginalModalClasses.content} ${ChangelogClasses.container} ${ChangelogModalClasses.content} ${DiscordClasses.Scrollers.thin}`
|
||||
}, changelogItems);
|
||||
|
||||
const key = this.ModalActions.openModal(props => {
|
||||
return React.createElement(ErrorBoundary, null, React.createElement(this.ModalRoot, Object.assign({
|
||||
className: `bd-changelog-modal ${OriginalModalClasses.root} ${OriginalModalClasses.small} ${ChangelogModalClasses.modal}`,
|
||||
selectable: true,
|
||||
onScroll: _ => _,
|
||||
onClose: _ => _,
|
||||
}, props), renderHeader(), body, renderFooter()));
|
||||
const key = this.openModal(props => {
|
||||
return React.createElement(ErrorBoundary, null, React.createElement(ChangelogModal, Object.assign(options, props)));
|
||||
});
|
||||
return key;
|
||||
}
|
||||
|
@ -315,7 +250,7 @@ export default class Modals {
|
|||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) return null;
|
||||
if (this.state.hasError) return React.createElement(TextElement, {color: TextElement.Colors.STATUS_RED}, Strings.Addons.settingsError);
|
||||
const props = {
|
||||
className: "bd-addon-settings-wrap",
|
||||
ref: this.elementRef
|
||||
|
@ -327,23 +262,35 @@ export default class Modals {
|
|||
}
|
||||
if (typeof(child) === "function") child = React.createElement(child);
|
||||
|
||||
const mc = this.ModalComponents;
|
||||
const modal = props => {
|
||||
return React.createElement(ErrorBoundary, {}, React.createElement(this.ModalRoot, Object.assign({size: mc.Sizes.MEDIUM, className: "bd-addon-modal" + " " + mc.Sizes.MEDIUM}, props),
|
||||
React.createElement(mc.Header, {separator: false, className: "bd-addon-modal-header"},
|
||||
React.createElement(this.TextElement, {tag: "h1", size: this.TextElement.Sizes.SIZE_20, strong: true}, `${name} Settings`)
|
||||
),
|
||||
React.createElement(mc.Content, {className: "bd-addon-modal-settings"},
|
||||
React.createElement(ErrorBoundary, {}, child)
|
||||
),
|
||||
React.createElement(mc.Footer, {className: "bd-addon-modal-footer"},
|
||||
React.createElement(this.Buttons, {onClick: props.onClose, className: "bd-button"}, Strings.Modals.done)
|
||||
)
|
||||
));
|
||||
const options = {
|
||||
className: "bd-addon-modal",
|
||||
size: ModalRoot.Sizes.MEDIUM,
|
||||
header: `${name} Settings`,
|
||||
cancelText: null,
|
||||
confirmText: Strings.Modals.done
|
||||
};
|
||||
|
||||
return this.ModalActions.openModal(props => {
|
||||
return React.createElement(ErrorBoundary, null, React.createElement(modal, props));
|
||||
return React.createElement(ErrorBoundary, null, React.createElement(ConfirmationModal, Object.assign(options, props), child));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
static makeStack() {
|
||||
const div = DOMManager.parseHTML(`<div id="bd-modal-container">`);
|
||||
DOMManager.bdBody.append(div);
|
||||
ReactDOM.render(<ModalStack />, div);
|
||||
this.hasInitialized = true;
|
||||
}
|
||||
|
||||
static openModal(render, options = {}) {
|
||||
if (!this.hasInitialized) this.makeStack();
|
||||
options.modalKey = generateKey(options.modalKey);
|
||||
Events.emit("open-modal", render, options);
|
||||
return options.modalKey;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Modals.makeStack();
|
|
@ -1,13 +1,21 @@
|
|||
import React from "@modules/react";
|
||||
import Strings from "@modules/strings";
|
||||
import DiscordClasses from "@modules/discordclasses";
|
||||
import WebpackModules from "@modules/webpackmodules";
|
||||
|
||||
import Text from "@ui/base/text";
|
||||
import Button from "@ui/base/button";
|
||||
import Flex from "@ui/base/flex";
|
||||
|
||||
import Extension from "@ui/icons/extension";
|
||||
import ThemeIcon from "@ui/icons/theme";
|
||||
|
||||
import Divider from "@ui/divider";
|
||||
|
||||
import Header from "./header";
|
||||
import Content from "./content";
|
||||
import ModalRoot from "./root";
|
||||
import Footer from "./footer";
|
||||
|
||||
const Parser = Object(WebpackModules.getByProps("defaultRules", "parse")).defaultRules;
|
||||
const {useState, useCallback, useMemo} = React;
|
||||
|
||||
|
@ -35,12 +43,12 @@ function AddonError({err, index}) {
|
|||
{err.type == "plugin" ? <Extension /> : <ThemeIcon />}
|
||||
</div>
|
||||
<div className="bd-addon-error-header-inner">
|
||||
<h3 className={`bd-addon-error-file ${DiscordClasses.Text.colorHeaderPrimary} ${DiscordClasses.Integrations.secondaryHeader} ${DiscordClasses.Text.size16}`}>{err.name}</h3>
|
||||
<div className={`bd-addon-error-details ${DiscordClasses.Integrations.detailsWrapper}`}>
|
||||
<svg className={DiscordClasses.Integrations.detailsIcon} aria-hidden="false" width="16" height="16" viewBox="0 0 12 12">
|
||||
<Text tag="h3" size={Text.Sizes.SIZE_16} color={Text.Colors.HEADER_PRIMARY} strong={true}>{err.name}</Text>
|
||||
<div className="bd-addon-error-details">
|
||||
<svg className="bd-addon-error-details-icon" aria-hidden="false" width="16" height="16" viewBox="0 0 12 12">
|
||||
<path fill="currentColor" d="M6 1C3.243 1 1 3.244 1 6c0 2.758 2.243 5 5 5s5-2.242 5-5c0-2.756-2.243-5-5-5zm0 2.376a.625.625 0 110 1.25.625.625 0 010-1.25zM7.5 8.5h-3v-1h1V6H5V5h1a.5.5 0 01.5.5v2h1v1z"></path>
|
||||
</svg>
|
||||
<div className={`${DiscordClasses.Text.colorHeaderSecondary} ${DiscordClasses.Text.size12}`}>{err.message}</div>
|
||||
<Text color={Text.Colors.HEADER_SECONDARY} size={Text.Sizes.SIZE_12}>{err.message}</Text>
|
||||
</div>
|
||||
</div>
|
||||
<svg className="bd-addon-error-expander" width="24" height="24" viewBox="0 0 24 24">
|
||||
|
@ -56,7 +64,7 @@ function generateTab(id, errors) {
|
|||
return {id, errors, name: Strings.Panels[id]};
|
||||
}
|
||||
|
||||
export default function AddonErrorModal({pluginErrors, themeErrors}) {
|
||||
export default function AddonErrorModal({transitionState, onClose, pluginErrors, themeErrors}) {
|
||||
const tabs = useMemo(() => {
|
||||
return [
|
||||
pluginErrors.length && generateTab("plugins", pluginErrors),
|
||||
|
@ -68,17 +76,22 @@ export default function AddonErrorModal({pluginErrors, themeErrors}) {
|
|||
const switchToTab = useCallback((id) => setTab(id), []);
|
||||
const selectedTab = tabs.find(e => e.id === tabId);
|
||||
|
||||
return <>
|
||||
<div className={`bd-error-modal-header ${DiscordClasses.Modal.header} ${DiscordClasses.Modal.separator}`}>
|
||||
<h4 className={`${DiscordClasses.Titles.defaultColor} ${DiscordClasses.Text.size14} ${DiscordClasses.Titles.h4} ${DiscordClasses.Margins.marginBottom8}`}>{Strings.Modals.addonErrors}</h4>
|
||||
<div className="bd-tab-bar">
|
||||
{tabs.map(tab => <div onClick={() => {switchToTab(tab.id);}} className={joinClassNames("bd-tab-item", tab.id === selectedTab.id && "selected")}>{tab.name}</div>)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`bd-error-modal-content ${DiscordClasses.Modal.content} ${DiscordClasses.Scrollers.thin}`}>
|
||||
<div className="bd-addon-errors">
|
||||
{selectedTab.errors.map((error, index) => <AddonError index={index} err={error} />)}
|
||||
</div>
|
||||
</div>
|
||||
</>;
|
||||
return <ModalRoot transitionState={transitionState} className="bd-error-modal" size={ModalRoot.Sizes.MEDIUM}>
|
||||
<Header className="bd-error-modal-header">
|
||||
<Flex direction={Flex.Direction.VERTICAL}>
|
||||
<Text tag="h1" size={Text.Sizes.SIZE_14} color={Text.Colors.HEADER_PRIMARY} strong={true} style={{"text-transform": "uppercase", "margin-bottom": "8px"}}>{Strings.Modals.addonErrors}</Text>
|
||||
<div className="bd-tab-bar">
|
||||
{tabs.map(tab => <div onClick={() => {switchToTab(tab.id);}} className={joinClassNames("bd-tab-item", tab.id === selectedTab.id && "selected")}>{tab.name}</div>)}
|
||||
</div>
|
||||
</Flex>
|
||||
</Header>
|
||||
<Content className="bd-error-modal-content">
|
||||
<div className="bd-addon-errors">
|
||||
{selectedTab.errors.map((error, index) => <AddonError index={index} err={error} />)}
|
||||
</div>
|
||||
</Content>
|
||||
<Footer className="bd-error-modal-footer">
|
||||
<Button onClick={onClose}>{Strings.Modals.okay}</Button>
|
||||
</Footer>
|
||||
</ModalRoot>;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
import React from "@modules/react";
|
||||
import WebpackModules from "@modules/webpackmodules";
|
||||
import Utilities from "@modules/utilities";
|
||||
|
||||
const Spring = WebpackModules.getByProps("useSpring", "animated");
|
||||
|
||||
|
||||
export default function Backdrop({isVisible, className, onClick}) {
|
||||
const transition = Spring.useTransition(isVisible, {
|
||||
keys: e => e ? "backdrop" : "empty",
|
||||
config: {duration: 300},
|
||||
from: {
|
||||
opacity: 0,
|
||||
background: "var(--black-500)"
|
||||
},
|
||||
enter: {
|
||||
opacity: 0.85,
|
||||
background: "var(--black-500)"
|
||||
},
|
||||
leave: {
|
||||
opacity: 0,
|
||||
background: "var(--black-500)"
|
||||
}
|
||||
});
|
||||
|
||||
return transition((styles, visible) => {
|
||||
if (!visible) return null;
|
||||
|
||||
return <Spring.animated.div
|
||||
className={Utilities.className("bd-modal-backdrop", className)}
|
||||
style={styles}
|
||||
onClick={onClick}
|
||||
/>;
|
||||
});
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
import React from "@modules/react";
|
||||
import WebpackModules from "@modules/webpackmodules";
|
||||
import DiscordModules from "@modules/discordmodules";
|
||||
|
||||
import Root from "./root";
|
||||
import Header from "./header";
|
||||
import Footer from "./footer";
|
||||
import Content from "./content";
|
||||
|
||||
import Flex from "../base/flex";
|
||||
import Text from "../base/text";
|
||||
import CloseButton from "./close";
|
||||
|
||||
import SimpleMarkdownExt from "@structs/markdown";
|
||||
|
||||
const {useMemo} = React;
|
||||
|
||||
|
||||
const AnchorClasses = WebpackModules.getByProps("anchorUnderlineOnHover") || {anchor: "anchor-3Z-8Bb", anchorUnderlineOnHover: "anchorUnderlineOnHover-2ESHQB"};
|
||||
const joinSupportServer = (click) => {
|
||||
click.preventDefault();
|
||||
click.stopPropagation();
|
||||
DiscordModules.InviteActions.acceptInviteAndTransitionToInviteChannel({inviteKey: "0Tmfo5ZbORCRqbAd"});
|
||||
};
|
||||
|
||||
const supportLink = <a className={`${AnchorClasses.anchor} ${AnchorClasses.anchorUnderlineOnHover}`} onClick={joinSupportServer}>Join our Discord Server.</a>;
|
||||
const defaultFooter = <Text>Need support? {supportLink}</Text>;
|
||||
|
||||
|
||||
export default function ChangelogModal({transitionState, footer, title, subtitle, onClose, video, poster, image, description, changes}) {
|
||||
|
||||
const ChangelogHeader = useMemo(() => <Header justify={Flex.Justify.BETWEEN}>
|
||||
<Flex direction={Flex.Direction.VERTICAL}>
|
||||
<Text tag="h1" size={Text.Sizes.SIZE_20} strong={true}>{title}</Text>
|
||||
<Text size={Text.Sizes.SIZE_12} color={Text.Colors.HEADER_SECONDARY}>{subtitle}</Text>
|
||||
</Flex>
|
||||
<CloseButton onClick={onClose} />
|
||||
</Header>, [title, subtitle, onClose]);
|
||||
|
||||
const ChangelogFooter = useMemo(() => <Footer>
|
||||
<Flex.Child grow="1" shrink="1">
|
||||
{footer ? footer : defaultFooter}
|
||||
</Flex.Child>
|
||||
</Footer>, [footer]);
|
||||
|
||||
const changelogItems = useMemo(() => {
|
||||
const items = [video ? <video src={video} poster={poster} controls={true} className="bd-changelog-poster" /> : <img src={image} className="bd-changelog-poster" />];
|
||||
if (description) items.push(<p>{SimpleMarkdownExt.parseToReact(description)}</p>);
|
||||
for (let c = 0; c < changes.length; c++) {
|
||||
const entry = changes[c];
|
||||
const type = "bd-changelog-" + entry.type;
|
||||
const margin = c == 0 ? " bd-changelog-first" : "";
|
||||
items.push(<h1 className={`bd-changelog-title ${type}${margin}`}>{entry.title}</h1>);
|
||||
if (entry.description) items.push(<p>{SimpleMarkdownExt.parseToReact(entry.description)}</p>);
|
||||
const list = <ul>{entry.items.map(i => <li>{SimpleMarkdownExt.parseToReact(i)}</li>)}</ul>;
|
||||
items.push(list);
|
||||
}
|
||||
return items;
|
||||
}, [description, video, image, poster, changes]);
|
||||
|
||||
return <Root className="bd-changelog-modal" transitionState={transitionState} size={Root.Sizes.SMALL} style={Root.Styles.STANDARD}>
|
||||
{ChangelogHeader}
|
||||
<Content>{changelogItems}</Content>
|
||||
{ChangelogFooter}
|
||||
</Root>;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import React from "@modules/react";
|
||||
|
||||
import Button from "../base/button";
|
||||
import Close from "../icons/close";
|
||||
|
||||
|
||||
export default function CloseButton({onClick}) {
|
||||
return <Button
|
||||
className="bd-close-button"
|
||||
size={Button.Sizes.ICON}
|
||||
look={Button.Looks.BLANK}
|
||||
color={Button.Colors.TRANSPARENT}
|
||||
onClick={onClick}
|
||||
>
|
||||
<Close size="24px" />
|
||||
</Button>;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
import React from "@modules/react";
|
||||
import Strings from "@modules/strings";
|
||||
|
||||
import Root from "./root";
|
||||
import Header from "./header";
|
||||
import Footer from "./footer";
|
||||
import Content from "./content";
|
||||
|
||||
import Text from "../base/text";
|
||||
import Button from "../base/button";
|
||||
|
||||
const {useRef, useEffect} = React;
|
||||
|
||||
|
||||
export default function ConfirmationModal({transitionState, onClose, className, size = Root.Sizes.SMALL, header, children, danger = false, onCancel = () => {}, onConfirm = () => {}, cancelText = Strings.Modals.cancel, confirmText = Strings.Modals.okay}) {
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => buttonRef?.current?.focus?.(), 0);
|
||||
}, []);
|
||||
|
||||
const buttonRef = useRef(null);
|
||||
|
||||
|
||||
return <Root transitionState={transitionState} size={size} className={className}>
|
||||
<Header>
|
||||
<Text tag="h1" size={Text.Sizes.SIZE_20} color={Text.Colors.HEADER_PRIMARY} strong={true}>{header}</Text>
|
||||
</Header>
|
||||
<Content>{children}</Content>
|
||||
<Footer>
|
||||
{confirmText && <Button
|
||||
type="submit"
|
||||
buttonRef={buttonRef}
|
||||
color={danger ? Button.Colors.RED : Button.Colors.BRAND}
|
||||
onClick={() => {
|
||||
onConfirm?.();
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{confirmText}
|
||||
</Button>}
|
||||
{cancelText && <Button
|
||||
type="button"
|
||||
look={Button.Looks.LINK}
|
||||
color={Button.Colors.PRIMARY}
|
||||
onClick={() => {
|
||||
onCancel?.();
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{cancelText}
|
||||
</Button>}
|
||||
</Footer>
|
||||
</Root>;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import React from "@modules/react";
|
||||
import Utilities from "@modules/utilities";
|
||||
|
||||
|
||||
export default function Content({id, className, children, scroller = true}) {
|
||||
return <div id={id} className={Utilities.className("bd-modal-content", {"bd-scroller-base bd-scroller-thin": scroller}, className)}>
|
||||
{children}
|
||||
</div>;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import React from "@modules/react";
|
||||
import Utilities from "@modules/utilities";
|
||||
|
||||
import Flex from "../base/flex";
|
||||
|
||||
|
||||
export default function Footer({id, className, children}) {
|
||||
return <Flex
|
||||
id={id}
|
||||
className={Utilities.className("bd-modal-footer", className)}
|
||||
grow={0}
|
||||
shrink={0}
|
||||
direction={Flex.Direction.HORIZONTAL_REVERSE}
|
||||
justify={Flex.Justify.START}
|
||||
align={Flex.Align.STRETCH}
|
||||
wrap={Flex.Wrap.NO_WRAP}
|
||||
>
|
||||
{children}
|
||||
</Flex>;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import React from "@modules/react";
|
||||
import Utilities from "@modules/utilities";
|
||||
|
||||
import Flex from "../base/flex";
|
||||
|
||||
|
||||
export default function Header({id, className, children}) {
|
||||
return <Flex
|
||||
id={id}
|
||||
className={Utilities.className("bd-modal-header", className)}
|
||||
grow={0}
|
||||
shrink={0}
|
||||
direction={Flex.Direction.HORIZONTAL}
|
||||
justify={Flex.Justify.START}
|
||||
align={Flex.Align.CENTER}
|
||||
wrap={Flex.Wrap.NO_WRAP}
|
||||
>
|
||||
{children}
|
||||
</Flex>;
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
import React from "@modules/react";
|
||||
import Utilities from "@modules/utilities";
|
||||
import WebpackModules from "@modules/webpackmodules";
|
||||
|
||||
const Spring = WebpackModules.getByProps("useSpring", "animated");
|
||||
const Anims = WebpackModules.getByProps("Easing");
|
||||
|
||||
|
||||
export const Sizes = Object.freeze({
|
||||
SMALL: "bd-modal-small",
|
||||
MEDIUM: "bd-modal-medium",
|
||||
LARGE: "bd-modal-large",
|
||||
DYNAMIC: ""
|
||||
});
|
||||
|
||||
export const Styles = Object.freeze({
|
||||
STANDARD: "bd-modal-standard",
|
||||
CUSTOM: ""
|
||||
});
|
||||
|
||||
|
||||
export default function ModalRoot({className, transitionState, children, size = Sizes.DYNAMIC, style = Styles.CUSTOM}) {
|
||||
const visible = transitionState == 0 || transitionState == 1; // 300 ms
|
||||
// const visible = transitionState;
|
||||
const springStyles = Spring.useSpring({
|
||||
opacity: visible ? 1 : 0,
|
||||
transform: visible ? "scale(1)" : "scale(0.7)",
|
||||
config: {
|
||||
duration: visible ? 300 : 100,
|
||||
easing: visible ? Anims.Easing.inOut(Anims.Easing.back()) : Anims.Easing.quad,
|
||||
clamp: true
|
||||
}
|
||||
});
|
||||
|
||||
return <Spring.animated.div
|
||||
className={Utilities.className("bd-modal-root", size, className, style)}
|
||||
style={springStyles}
|
||||
>
|
||||
{children}
|
||||
</Spring.animated.div>;
|
||||
// const [visible, setVisible] = React.useState(true);
|
||||
|
||||
// const visible = transitionState < 2;
|
||||
// const springTransition = Spring.useTransition(transitionState, {
|
||||
// keys: e => e ? "backdrop" : "empty",
|
||||
// from: {
|
||||
// opacity: 0,
|
||||
// transform: "scale(0.7)"
|
||||
// },
|
||||
// enter: {
|
||||
// opacity: 1,
|
||||
// transform: "scale(1)"
|
||||
// },
|
||||
// leave: {
|
||||
// opacity: 0,
|
||||
// transform: "scale(0.7)"
|
||||
// },
|
||||
// // config: (a, b, c, d) => {
|
||||
// // console.log({a, b, c, d});
|
||||
// // return {
|
||||
// // duration: a ? 300 : 100,
|
||||
// // easing: a ? Anims.Easing.inOut(Anims.Easing.back()) : Anims.Easing.quad,
|
||||
// // clamp: true
|
||||
// // };
|
||||
// // }
|
||||
// config: (a, b, c) => {
|
||||
// console.log({a, b, c});
|
||||
// return {
|
||||
// duration: true ? 300 : 100,
|
||||
// easing: true ? Anims.Easing.inOut(Anims.Easing.back()) : Anims.Easing.quad,
|
||||
// clamp: true
|
||||
// };
|
||||
// }
|
||||
// });
|
||||
|
||||
// return springTransition((styles, isVisible) => {
|
||||
// if (!isVisible) console.log("not visible");
|
||||
// return <Spring.animated.div
|
||||
// className={Utilities.className("bd-modal-root", size, className, style)}
|
||||
// style={styles}
|
||||
// >
|
||||
// {children}
|
||||
// </Spring.animated.div>;
|
||||
// });
|
||||
}
|
||||
|
||||
ModalRoot.Sizes = Sizes;
|
||||
ModalRoot.Styles = Styles;
|
|
@ -0,0 +1,76 @@
|
|||
import React from "@modules/react";
|
||||
import Events from "@modules/emitter";
|
||||
import WebpackModules from "@modules/webpackmodules";
|
||||
|
||||
import Backdrop from "./backdrop";
|
||||
|
||||
const {Fragment, useState, useCallback, useEffect} = React;
|
||||
|
||||
|
||||
const Transitions = WebpackModules.getModule(m => m?.defaultProps?.transitionAppear);
|
||||
// const Transitions = WebpackModules.getByProps("TransitionGroup").TransitionGroup;
|
||||
|
||||
class ModalLayer extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {transitionState: null};
|
||||
}
|
||||
|
||||
componentWillEnter(finish) {
|
||||
this.setState({transitionState: 0});
|
||||
setTimeout(() => {
|
||||
this.setState({transitionState: 1});
|
||||
finish();
|
||||
}, 300);
|
||||
|
||||
}
|
||||
componentWillLeave(finish) {
|
||||
this.setState({transitionState: 2});
|
||||
setTimeout(() => {
|
||||
this.setState({transitionState: 3});
|
||||
finish();
|
||||
}, 300);
|
||||
}
|
||||
|
||||
render() {
|
||||
return React.createElement("div", {className: "bd-modal-layer"}, this.props.render({
|
||||
transitionState: this.state.transitionState,
|
||||
onClose: this.props.onClose
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// ENTERING 0
|
||||
// ENTERED 1
|
||||
// EXITING 2
|
||||
// EXITED 3
|
||||
// HIDDEN 4
|
||||
|
||||
let modalKey = 0;
|
||||
export const generateKey = key => key ? `${key}-${modalKey++}` : modalKey++;
|
||||
|
||||
export default function ModalStack() {
|
||||
const [modals, setModals] = useState([]);
|
||||
|
||||
const addModal = useCallback((render, props = {}) => {
|
||||
setModals(m => [...m, {...props, render}]);
|
||||
}, []);
|
||||
const removeModal = useCallback((key) => {
|
||||
setModals(mods => mods.filter(m => {
|
||||
if (m.modalKey === key && m.onClose) m.onClose();
|
||||
return m.modalKey !== key;
|
||||
}));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
Events.on("open-modal", addModal);
|
||||
return () => {
|
||||
Events.off("open-modal", addModal);
|
||||
};
|
||||
}, [addModal]);
|
||||
|
||||
return <Transitions component={Fragment}>
|
||||
<Backdrop isVisible={!!modals.length} onClick={() => removeModal(modals[modals.length - 1].modalKey)} />
|
||||
{modals.length && <ModalLayer key={modals[modals.length - 1].modalKey} {...modals[modals.length - 1]} onClose={() => removeModal(modals[modals.length - 1].modalKey)} />}
|
||||
</Transitions>;
|
||||
}
|
|
@ -65,7 +65,7 @@ function makeButton(title, children, action, {isControl = false, danger = false,
|
|||
const ButtonType = isControl ? "button" : "div";
|
||||
return <DiscordModules.Tooltip color="primary" position="top" text={title}>
|
||||
{(props) => {
|
||||
return <ButtonType {...props} className={(isControl ? "bd-button bd-addon-button" : "bd-addon-button") + (danger ? " bd-button-danger" : "") + (disabled ? " bd-button-disabled" : "")} onClick={action}>{children}</ButtonType>;
|
||||
return <ButtonType {...props} className={(isControl ? "bd-button bd-button-filled bd-addon-button" : "bd-addon-button") + (danger ? " bd-button-color-red" : isControl ? " bd-button-color-brand" : "") + (disabled ? " bd-button-disabled" : "")} onClick={action} disabled={disabled}>{children}</ButtonType>;
|
||||
}}
|
||||
</DiscordModules.Tooltip>;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import React from "@modules/react";
|
||||
|
||||
import Button from "../base/button";
|
||||
|
||||
const {useCallback} = React;
|
||||
|
||||
|
||||
|
@ -18,7 +20,7 @@ export default function SettingsTitle({isGroup, className, button, onClick, text
|
|||
const titleClass = className ? `${baseClass} ${className}` : baseClass;
|
||||
return <h2 className={titleClass} onClick={() => {onClick?.();}}>
|
||||
{text}
|
||||
{button && <button className="bd-button bd-button-title" onClick={click}>{button.title}</button>}
|
||||
{button && <Button className="bd-button-title" onClick={click} size={Button.Sizes.NONE}>{button.title}</Button>}
|
||||
{otherChildren}
|
||||
</h2>;
|
||||
|
||||
|
|
Loading…
Reference in New Issue