diff --git a/i18n/en-US.json b/i18n/en-US.json index 7b1df86be..26621b57b 100644 --- a/i18n/en-US.json +++ b/i18n/en-US.json @@ -70,6 +70,9 @@ "REPLUGGED_PLUGIN": "Plugin", "REPLUGGED_PLUGINS": "Plugins", "REPLUGGED_QUICKCSS": "Quick CSS", + "REPLUGGED_QUICKCSS_CHANGES_APPLY": "Apply Changes", + "REPLUGGED_QUICKCSS_FOLDER_OPEN": "Open Quick CSS Folder", + "REPLUGGED_QUICKCSS_POPPED_OUT": "Quick CSS Editor has been popped out", "REPLUGGED_SETTINGS_ADVANCED_DESC": "Don't touch stuff in here if you don't know what you're doing. Unexpected things can happen to your cat.", "REPLUGGED_SETTINGS_BACKEND": "Backend URL", "REPLUGGED_SETTINGS_BACKEND_DESC": "URL used to fetch some assets and to query Replugged's REST API.", @@ -175,7 +178,6 @@ "REPLUGGED_LIST_RESULTS": "{count, plural, =1 {# match} other {# matches}}", "REPLUGGED_NO_ADDON_RESULTS": "No {type} matched your search.", "REPLUGGED_NO_ADDONS_INSTALLED": "No {type} installed.", - "REPLUGGED_QUICKCSS_CHANGES_APPLY": "Apply Changes", "REPLUGGED_SEARCH_FOR_ADDON": "Search for a {type}", "REPLUGGED_TOAST_ADDON_DISABLE_SUCCESS": "Disabled {name}", "REPLUGGED_TOAST_ADDON_ENABLE_SUCCESS": "Enabled {name}", @@ -197,7 +199,6 @@ "REPLUGGED_TOAST_INSTALLER_ADDON_INSTALL_SUCCESS": "{name} installed successfully.", "REPLUGGED_TOAST_INSTALLER_ADDON_FETCH_INFO_FAILED": "Failed to get info for addon.", "REPLUGGED_TOAST_INSTALLER_ADDON_CANCELED_INSTALL": "Install canceled.", - "REPLUGGED_QUICKCSS_FOLDER_OPEN": "Open Quick CSS Folder", "REPLUGGED_ADDON_AUTHORS_ONE": "by {author1}", "REPLUGGED_ADDON_AUTHORS_TWO": "by {author1} and {author2}", "REPLUGGED_ADDON_AUTHORS_THREE": "by {author1}, {author2}, and {author3}", diff --git a/src/renderer/coremods/settings/icons/Pin.tsx b/src/renderer/coremods/settings/icons/Pin.tsx new file mode 100644 index 000000000..86b9a7517 --- /dev/null +++ b/src/renderer/coremods/settings/icons/Pin.tsx @@ -0,0 +1,5 @@ +export default (): React.ReactElement => ( + + + +); diff --git a/src/renderer/coremods/settings/icons/Popout.tsx b/src/renderer/coremods/settings/icons/Popout.tsx new file mode 100644 index 000000000..35542e904 --- /dev/null +++ b/src/renderer/coremods/settings/icons/Popout.tsx @@ -0,0 +1,5 @@ +export default (): React.ReactElement => ( + + + +); diff --git a/src/renderer/coremods/settings/icons/Unpin.tsx b/src/renderer/coremods/settings/icons/Unpin.tsx new file mode 100644 index 000000000..1dcf38103 --- /dev/null +++ b/src/renderer/coremods/settings/icons/Unpin.tsx @@ -0,0 +1,18 @@ +export default (): React.ReactElement => ( + + + + + + + + + + +); diff --git a/src/renderer/coremods/settings/icons/index.ts b/src/renderer/coremods/settings/icons/index.ts index e6c8be8d6..3b99bb216 100644 --- a/src/renderer/coremods/settings/icons/index.ts +++ b/src/renderer/coremods/settings/icons/index.ts @@ -4,6 +4,9 @@ import Link from "./Link"; import Reload from "./Reload"; import Settings from "./Settings"; import Trash from "./Trash"; +import Popout from "./Popout"; +import Pin from "./Pin"; +import Unpin from "./Unpin"; export default { Discord, @@ -12,4 +15,7 @@ export default { Reload, Settings, Trash, + Popout, + Pin, + Unpin, }; diff --git a/src/renderer/coremods/settings/index.tsx b/src/renderer/coremods/settings/index.tsx index 296f3ebfc..fe3299a5f 100644 --- a/src/renderer/coremods/settings/index.tsx +++ b/src/renderer/coremods/settings/index.tsx @@ -2,7 +2,7 @@ import { Messages } from "@common/i18n"; import { Text } from "@components"; import { Injector } from "@replugged"; import { Divider, Header, Section, insertSections, settingsTools } from "./lib"; -import { General, Plugins, QuickCSS, Themes, Updater } from "./pages"; +import { ConnectedQuickCSS, General, Plugins, Themes, Updater } from "./pages"; const injector = new Injector(); @@ -28,7 +28,7 @@ export function start(): void { Section({ name: "rp-quickcss", label: () => Messages.REPLUGGED_QUICKCSS, - elem: QuickCSS, + elem: ConnectedQuickCSS as unknown as (args: unknown) => React.ReactElement, }), Section({ name: "rp-plugins", diff --git a/src/renderer/coremods/settings/pages/QuickCSS.css b/src/renderer/coremods/settings/pages/QuickCSS.css index 24d5baf1a..50f7d7136 100644 --- a/src/renderer/coremods/settings/pages/QuickCSS.css +++ b/src/renderer/coremods/settings/pages/QuickCSS.css @@ -21,6 +21,10 @@ /* Scrollbar */ #replugged-quickcss-wrapper .cm-scroller { overflow: auto; + max-height: 75vh; +} +#replugged-quickcss-wrapper[data-popout="true"] .cm-scroller { + max-height: 100vh; } #replugged-quickcss-wrapper .cm-scroller::-webkit-scrollbar { width: 16px; @@ -183,3 +187,28 @@ #replugged-quickcss-wrapper .cm-specialChar { color: var(--red-400); } + +.replugged-quickcss-header { + height: 30px; + color: var(--text-normal); + display: flex; + align-items: center; + justify-content: space-between; + font-size: 14px; + padding: 7px 15px; + background-color: var(--background-secondary); +} + +#replugged-quickcss-wrapper[data-popout="true"] .replugged-quickcss-header { + height: 16px; +} + +.replugged-quickcss-header span, +.replugged-quickcss-header div, +.replugged-quickcss-header svg { + width: 100%; + height: 100%; +} +[class^="content"]:has(> #replugged-quickcss-wrapper) { + display: block; +} diff --git a/src/renderer/coremods/settings/pages/QuickCSS.tsx b/src/renderer/coremods/settings/pages/QuickCSS.tsx index daef371e9..8f484f3b4 100644 --- a/src/renderer/coremods/settings/pages/QuickCSS.tsx +++ b/src/renderer/coremods/settings/pages/QuickCSS.tsx @@ -1,13 +1,16 @@ -import { React, toast } from "@common"; +import { React, flux, toast } from "@common"; import { Messages } from "@common/i18n"; import { EditorView, basicSetup } from "codemirror"; import { EditorState } from "@codemirror/state"; import { css } from "@codemirror/lang-css"; import { githubDark, githubLight } from "./codemirror-github"; import { webpack } from "@replugged"; -import { Button, Divider, Flex, Text } from "@components"; -import "./QuickCSS.css"; +import { Button, ButtonItem, Clickable, Divider, Flex, Text, Tooltip } from "@components"; import { generalSettings } from "./General"; +import { Store } from "@common/flux"; +import Icons from "../icons"; + +import "./QuickCSS.css"; interface UseCodeMirrorOptions { value?: string; @@ -22,6 +25,29 @@ type ThemeModule = { removeChangeListener: (listener: () => unknown) => unknown; }; +const PopoutModule = await webpack.waitForModule( + webpack.filters.bySource('type:"POPOUT_WINDOW_OPEN"'), +)!; +const openPopout = webpack.getFunctionBySource< + (key: string, render: React.ComponentType, features: Record) => void +>(PopoutModule, "POPOUT_WINDOW_OPEN")!; +const closePopout = webpack.getFunctionBySource<(key: string) => void>( + PopoutModule, + "POPOUT_WINDOW_CLOSE", +)!; +const setAlwaysOnTop = webpack.getFunctionBySource<(key: string, alwaysOnTop: boolean) => void>( + PopoutModule, + "POPOUT_WINDOW_SET_ALWAYS_ON_TOP", +)!; +const PopoutWindowStore = webpack.getByStoreName< + Store & { + getWindow: (key: string) => Window; + getWindowOpen: (key: string) => boolean; + getIsAlwaysOnTop: (key: string) => boolean; + } +>("PopoutWindowStore")!; +let PopoutWindow = webpack.getBySource(".EMBEDDED_ACTIVITIES_ARE_YOU_SURE_WANT_TO_LEAVE"); + function useTheme(): "light" | "dark" { const [theme, setTheme] = React.useState<"light" | "dark">("dark"); @@ -109,7 +135,7 @@ function useCodeMirror({ value: initialValueParam, onChange, container }: UseCod return { value, setValue: customSetValue }; } -export const QuickCSS = (): React.ReactElement => { +const QuickCSS = (props: { popout: boolean } & Record): React.ReactElement => { const ref = React.useRef(null); const { value, setValue } = useCodeMirror({ container: ref.current, @@ -169,24 +195,98 @@ export const QuickCSS = (): React.ReactElement => { if (autoApply) setReloadTimer(setTimeout(reload, 500)); }, [value]); + if (props.popout) { + React.useEffect(() => { + const window = PopoutWindowStore.getWindow("DISCORD_REPLUGGED_QUICKCSS"); + let el = window.document.createElement("link"); + el.rel = "stylesheet"; + el.href = `replugged://renderer.css?t=${Date.now()}`; + window.document.head.appendChild(el); + }, []) + } + const [alwaysOnTop, setAlwaysOnTop_] = React.useState(props.popoutOnTop); + return ( <> - - {Messages.REPLUGGED_QUICKCSS} -
- {autoApply ? null : ( - - )} - + {!props.popout ? <> + + {Messages.REPLUGGED_QUICKCSS} +
+ {autoApply ? null : ( + + )} + +
+
+ + : null} + + {!props.popout && props.isPopoutOpen ? ( + { + closePopout("DISCORD_REPLUGGED_QUICKCSS"); + }}> + {Messages.REPLUGGED_QUICKCSS_POPPED_OUT} + + ) : ( +
+
+ {props.popout ? ( + + { + setAlwaysOnTop("DISCORD_REPLUGGED_QUICKCSS", !alwaysOnTop); + setAlwaysOnTop_(!alwaysOnTop); + }}> + {alwaysOnTop ? : } + + + ) : ( + + { + if (!PopoutWindow) + PopoutWindow = webpack.getBySource(".EMBEDDED_ACTIVITIES_ARE_YOU_SURE_WANT_TO_LEAVE"); + openPopout( + "DISCORD_REPLUGGED_QUICKCSS", + () => ( + + + + ), + {}, + ); + }}> + + + + )} +
+
- - -
+ )} ); }; +console.log("omg") +export const ConnectedQuickCSS = flux.connectStores< + { popout: boolean }, + { popout: boolean; isPopoutOpen: boolean } +>([PopoutWindowStore], (props) => { + return { + isPopoutOpen: PopoutWindowStore.getWindowOpen("DISCORD_REPLUGGED_QUICKCSS"), + popoutOnTop: PopoutWindowStore.getIsAlwaysOnTop("DISCORD_REPLUGGED_QUICKCSS"), + ...props, + }; +})(QuickCSS);