[WP] migrate to new Vencord components
This commit is contained in:
@@ -7,10 +7,10 @@
|
|||||||
import "./screenSharePicker.css";
|
import "./screenSharePicker.css";
|
||||||
|
|
||||||
import { classNameFactory } from "@vencord/types/api/Styles";
|
import { classNameFactory } from "@vencord/types/api/Styles";
|
||||||
import { CogWheel, FormSwitch, RestartIcon } from "@vencord/types/components";
|
import { Button, Card, CogWheel, FormSwitch, Heading, Paragraph, RestartIcon } from "@vencord/types/components";
|
||||||
import { closeModal, Logger, Modals, ModalSize, openModal, useAwaiter, useForceUpdater } from "@vencord/types/utils";
|
import { closeModal, Logger, Modals, ModalSize, openModal, useAwaiter, useForceUpdater } from "@vencord/types/utils";
|
||||||
import { onceReady } from "@vencord/types/webpack";
|
import { onceReady } from "@vencord/types/webpack";
|
||||||
import { Button, Card, FluxDispatcher, Forms, Select, Text, UserStore, useState } from "@vencord/types/webpack/common";
|
import { FluxDispatcher, Select, UserStore, useState } from "@vencord/types/webpack/common";
|
||||||
import { Node } from "@vencord/venmic";
|
import { Node } from "@vencord/venmic";
|
||||||
import type { Dispatch, SetStateAction } from "react";
|
import type { Dispatch, SetStateAction } from "react";
|
||||||
import { MediaEngineStore } from "renderer/common";
|
import { MediaEngineStore } from "renderer/common";
|
||||||
@@ -165,9 +165,9 @@ function ScreenPicker({ screens, chooseScreen }: { screens: Source[]; chooseScre
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<img src={url} alt="" />
|
<img src={url} alt="" />
|
||||||
<Text className={cl("screen-name")} variant="text-sm/normal">
|
<Paragraph className={cl("screen-name")} size="sm">
|
||||||
{name}
|
{name}
|
||||||
</Text>
|
</Paragraph>
|
||||||
</label>
|
</label>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -188,7 +188,9 @@ function AudioSettingsModal({
|
|||||||
return (
|
return (
|
||||||
<Modals.ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
|
<Modals.ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
|
||||||
<Modals.ModalHeader className={cl("header")}>
|
<Modals.ModalHeader className={cl("header")}>
|
||||||
<Forms.FormTitle tag="h2">Venmic Settings</Forms.FormTitle>
|
<Heading tag="h2" className={cl("header-title")}>
|
||||||
|
Venmic Settings
|
||||||
|
</Heading>
|
||||||
<Modals.ModalCloseButton onClick={close} className={cl("header-close-button")} />
|
<Modals.ModalCloseButton onClick={close} className={cl("header-close-button")} />
|
||||||
</Modals.ModalHeader>
|
</Modals.ModalHeader>
|
||||||
|
|
||||||
@@ -289,7 +291,7 @@ function AudioSettingsModal({
|
|||||||
/>
|
/>
|
||||||
</Modals.ModalContent>
|
</Modals.ModalContent>
|
||||||
<Modals.ModalFooter className={cl("footer")}>
|
<Modals.ModalFooter className={cl("footer")}>
|
||||||
<Button color={Button.Colors.TRANSPARENT} onClick={close}>
|
<Button variant="secondary" onClick={close}>
|
||||||
Back
|
Back
|
||||||
</Button>
|
</Button>
|
||||||
</Modals.ModalFooter>
|
</Modals.ModalFooter>
|
||||||
@@ -310,7 +312,9 @@ function OptionRadio<Settings extends object, Key extends keyof Settings>(props:
|
|||||||
<div className={cl("option-radios")}>
|
<div className={cl("option-radios")}>
|
||||||
{(options as string[]).map((option, idx) => (
|
{(options as string[]).map((option, idx) => (
|
||||||
<label className={cl("option-radio")} data-checked={settings[settingsKey] === option} key={option}>
|
<label className={cl("option-radio")} data-checked={settings[settingsKey] === option} key={option}>
|
||||||
<Text variant="text-sm/bold">{labels?.[idx] ?? option}</Text>
|
<Paragraph size="sm" weight="bold">
|
||||||
|
{labels?.[idx] ?? option}
|
||||||
|
</Paragraph>
|
||||||
<input
|
<input
|
||||||
className={cl("option-input")}
|
className={cl("option-input")}
|
||||||
type="radio"
|
type="radio"
|
||||||
@@ -361,18 +365,18 @@ function StreamSettingsUi({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Forms.FormTitle>What you're streaming</Forms.FormTitle>
|
<Heading>What you're streaming</Heading>
|
||||||
<Card className={cl("card", "preview")}>
|
<Card className={cl("card", "preview")}>
|
||||||
<img src={thumb} alt="" className={cl(isLinux ? "preview-img-linux" : "preview-img")} />
|
<img src={thumb} alt="" className={cl(isLinux ? "preview-img-linux" : "preview-img")} />
|
||||||
<Text variant="text-sm/normal">{source.name}</Text>
|
<Paragraph size="sm">{source.name}</Paragraph>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Forms.FormTitle>Stream Settings</Forms.FormTitle>
|
<Heading>Stream Settings</Heading>
|
||||||
|
|
||||||
<Card className={cl("card")}>
|
<Card className={cl("card")}>
|
||||||
<div className={cl("quality")}>
|
<div className={cl("quality")}>
|
||||||
<section className={cl("quality-section")}>
|
<section className={cl("quality-section")}>
|
||||||
<Forms.FormTitle>Resolution</Forms.FormTitle>
|
<Heading>Resolution</Heading>
|
||||||
<OptionRadio
|
<OptionRadio
|
||||||
options={StreamResolutions}
|
options={StreamResolutions}
|
||||||
settings={qualitySettings}
|
settings={qualitySettings}
|
||||||
@@ -382,7 +386,7 @@ function StreamSettingsUi({
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className={cl("quality-section")}>
|
<section className={cl("quality-section")}>
|
||||||
<Forms.FormTitle>Frame Rate</Forms.FormTitle>
|
<Heading>Frame Rate</Heading>
|
||||||
<OptionRadio
|
<OptionRadio
|
||||||
options={StreamFps}
|
options={StreamFps}
|
||||||
settings={qualitySettings}
|
settings={qualitySettings}
|
||||||
@@ -393,7 +397,7 @@ function StreamSettingsUi({
|
|||||||
</div>
|
</div>
|
||||||
<div className={cl("quality")}>
|
<div className={cl("quality")}>
|
||||||
<section className={cl("quality-section")}>
|
<section className={cl("quality-section")}>
|
||||||
<Forms.FormTitle>Content Type</Forms.FormTitle>
|
<Heading>Content Type</Heading>
|
||||||
<div>
|
<div>
|
||||||
<OptionRadio
|
<OptionRadio
|
||||||
options={["motion", "detail"]}
|
options={["motion", "detail"]}
|
||||||
@@ -578,7 +582,7 @@ function AudioSourcePickerLinux({
|
|||||||
|
|
||||||
if (!sources.ok && sources.isGlibCxxOutdated) {
|
if (!sources.ok && sources.isGlibCxxOutdated) {
|
||||||
return (
|
return (
|
||||||
<Forms.FormText>
|
<Paragraph>
|
||||||
Failed to retrieve Audio Sources because your C++ library is too old to run
|
Failed to retrieve Audio Sources because your C++ library is too old to run
|
||||||
<a href="https://github.com/Vencord/venmic" target="_blank">
|
<a href="https://github.com/Vencord/venmic" target="_blank">
|
||||||
venmic
|
venmic
|
||||||
@@ -588,13 +592,13 @@ function AudioSourcePickerLinux({
|
|||||||
this guide
|
this guide
|
||||||
</a>{" "}
|
</a>{" "}
|
||||||
for possible solutions.
|
for possible solutions.
|
||||||
</Forms.FormText>
|
</Paragraph>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasPipewirePulse && !ignorePulseWarning) {
|
if (!hasPipewirePulse && !ignorePulseWarning) {
|
||||||
return (
|
return (
|
||||||
<Text variant="text-sm/normal">
|
<Paragraph size="sm">
|
||||||
Could not find pipewire-pulse. See{" "}
|
Could not find pipewire-pulse. See{" "}
|
||||||
<a href="https://gist.github.com/the-spyke/2de98b22ff4f978ebf0650c90e82027e#install" target="_blank">
|
<a href="https://gist.github.com/the-spyke/2de98b22ff4f978ebf0650c90e82027e#install" target="_blank">
|
||||||
this guide
|
this guide
|
||||||
@@ -603,7 +607,7 @@ function AudioSourcePickerLinux({
|
|||||||
You can still continue, however, please{" "}
|
You can still continue, however, please{" "}
|
||||||
<b>beware that you can only share audio of apps that are running under pipewire</b>.{" "}
|
<b>beware that you can only share audio of apps that are running under pipewire</b>.{" "}
|
||||||
<a onClick={() => setIgnorePulseWarning(true)}>I know what I'm doing!</a>
|
<a onClick={() => setIgnorePulseWarning(true)}>I know what I'm doing!</a>
|
||||||
</Text>
|
</Paragraph>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,7 +627,7 @@ function AudioSourcePickerLinux({
|
|||||||
<>
|
<>
|
||||||
<div className={cl("audio-sources")}>
|
<div className={cl("audio-sources")}>
|
||||||
<section>
|
<section>
|
||||||
<Forms.FormTitle>{loading ? "Loading Sources..." : "Audio Sources"}</Forms.FormTitle>
|
<Heading>{loading ? "Loading Sources..." : "Audio Sources"}</Heading>
|
||||||
<Select
|
<Select
|
||||||
options={allSources.map(({ name, value }) => ({
|
options={allSources.map(({ name, value }) => ({
|
||||||
label: name,
|
label: name,
|
||||||
@@ -639,7 +643,7 @@ function AudioSourcePickerLinux({
|
|||||||
</section>
|
</section>
|
||||||
{includeSources === "Entire System" && (
|
{includeSources === "Entire System" && (
|
||||||
<section>
|
<section>
|
||||||
<Forms.FormTitle>Exclude Sources</Forms.FormTitle>
|
<Heading>Exclude Sources</Heading>
|
||||||
<Select
|
<Select
|
||||||
options={allSources
|
options={allSources
|
||||||
.filter(x => x.name !== "Entire System")
|
.filter(x => x.name !== "Entire System")
|
||||||
@@ -658,15 +662,11 @@ function AudioSourcePickerLinux({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={cl("settings-buttons")}>
|
<div className={cl("settings-buttons")}>
|
||||||
<Button
|
<Button variant="secondary" onClick={refreshAudioSources} className={cl("settings-button")}>
|
||||||
color={Button.Colors.TRANSPARENT}
|
|
||||||
onClick={refreshAudioSources}
|
|
||||||
className={cl("settings-button")}
|
|
||||||
>
|
|
||||||
<RestartIcon className={cl("settings-button-icon")} />
|
<RestartIcon className={cl("settings-button-icon")} />
|
||||||
Refresh Audio Sources
|
Refresh Audio Sources
|
||||||
</Button>
|
</Button>
|
||||||
<Button color={Button.Colors.TRANSPARENT} onClick={openSettings} className={cl("settings-button")}>
|
<Button variant="secondary" onClick={openSettings} className={cl("settings-button")}>
|
||||||
<CogWheel className={cl("settings-button-icon")} />
|
<CogWheel className={cl("settings-button-icon")} />
|
||||||
Open Audio Settings
|
Open Audio Settings
|
||||||
</Button>
|
</Button>
|
||||||
@@ -702,9 +702,12 @@ function ModalComponent({
|
|||||||
return (
|
return (
|
||||||
<Modals.ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
|
<Modals.ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
|
||||||
<Modals.ModalHeader className={cl("header")}>
|
<Modals.ModalHeader className={cl("header")}>
|
||||||
<Forms.FormTitle tag="h2">ScreenShare</Forms.FormTitle>
|
<Heading tag="h2" className={cl("header-title")}>
|
||||||
<Modals.ModalCloseButton onClick={close} />
|
ScreenShare
|
||||||
|
</Heading>
|
||||||
|
<Modals.ModalCloseButton onClick={close} className={cl("header-close-button")} />
|
||||||
</Modals.ModalHeader>
|
</Modals.ModalHeader>
|
||||||
|
|
||||||
<Modals.ModalContent className={cl("modal")}>
|
<Modals.ModalContent className={cl("modal")}>
|
||||||
{!selected ? (
|
{!selected ? (
|
||||||
<ScreenPicker screens={screens} chooseScreen={setSelected} />
|
<ScreenPicker screens={screens} chooseScreen={setSelected} />
|
||||||
@@ -781,11 +784,11 @@ function ModalComponent({
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{selected && !skipPicker ? (
|
{selected && !skipPicker ? (
|
||||||
<Button color={Button.Colors.TRANSPARENT} onClick={() => setSelected(void 0)}>
|
<Button variant="secondary" onClick={() => setSelected(void 0)}>
|
||||||
Back
|
Back
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<Button color={Button.Colors.TRANSPARENT} onClick={close}>
|
<Button variant="secondary" onClick={close}>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -18,9 +18,10 @@
|
|||||||
|
|
||||||
.vcd-screen-picker-card {
|
.vcd-screen-picker-card {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
padding: 0.5em;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Screen Grid */
|
/* Screen Grid */
|
||||||
.vcd-screen-picker-screen-grid {
|
.vcd-screen-picker-screen-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -54,11 +55,6 @@
|
|||||||
margin-inline: 0.5em;
|
margin-inline: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vcd-screen-picker-card {
|
|
||||||
padding: 0.5em;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vcd-screen-picker-preview-img-linux {
|
.vcd-screen-picker-preview-img-linux {
|
||||||
width: 60%;
|
width: 60%;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Heading, Paragraph } from "@vencord/types/components";
|
||||||
import {
|
import {
|
||||||
Margins,
|
Margins,
|
||||||
ModalCloseButton,
|
ModalCloseButton,
|
||||||
@@ -14,7 +15,7 @@ import {
|
|||||||
openModal,
|
openModal,
|
||||||
useForceUpdater
|
useForceUpdater
|
||||||
} from "@vencord/types/utils";
|
} from "@vencord/types/utils";
|
||||||
import { Button, Forms, Text, Toasts } from "@vencord/types/webpack/common";
|
import { Button, Text, Toasts } from "@vencord/types/webpack/common";
|
||||||
import { Settings } from "shared/settings";
|
import { Settings } from "shared/settings";
|
||||||
|
|
||||||
import { cl, SettingsComponent } from "./Settings";
|
import { cl, SettingsComponent } from "./Settings";
|
||||||
@@ -35,12 +36,12 @@ function openDeveloperOptionsModal(settings: Settings) {
|
|||||||
|
|
||||||
<ModalContent>
|
<ModalContent>
|
||||||
<div style={{ padding: "1em 0" }}>
|
<div style={{ padding: "1em 0" }}>
|
||||||
<Forms.FormTitle tag="h5">Vencord Location</Forms.FormTitle>
|
<Heading tag="h5">Vencord Location</Heading>
|
||||||
<VencordLocationPicker settings={settings} />
|
<VencordLocationPicker settings={settings} />
|
||||||
|
|
||||||
<Forms.FormTitle tag="h5" className={Margins.top16}>
|
<Heading tag="h5" className={Margins.top16}>
|
||||||
Debugging
|
Debugging
|
||||||
</Forms.FormTitle>
|
</Heading>
|
||||||
<div className={cl("button-grid")}>
|
<div className={cl("button-grid")}>
|
||||||
<Button onClick={() => VesktopNative.debug.launchGpu()}>Open chrome://gpu</Button>
|
<Button onClick={() => VesktopNative.debug.launchGpu()}>Open chrome://gpu</Button>
|
||||||
<Button onClick={() => VesktopNative.debug.launchWebrtcInternals()}>
|
<Button onClick={() => VesktopNative.debug.launchWebrtcInternals()}>
|
||||||
@@ -59,7 +60,7 @@ const VencordLocationPicker: SettingsComponent = ({ settings }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Forms.FormText>
|
<Paragraph>
|
||||||
Vencord files are loaded from{" "}
|
Vencord files are loaded from{" "}
|
||||||
{vencordDir ? (
|
{vencordDir ? (
|
||||||
<a
|
<a
|
||||||
@@ -74,7 +75,7 @@ const VencordLocationPicker: SettingsComponent = ({ settings }) => {
|
|||||||
) : (
|
) : (
|
||||||
"the default location"
|
"the default location"
|
||||||
)}
|
)}
|
||||||
</Forms.FormText>
|
</Paragraph>
|
||||||
<div className={cl("button-grid")}>
|
<div className={cl("button-grid")}>
|
||||||
<Button
|
<Button
|
||||||
size={Button.Sizes.SMALL}
|
size={Button.Sizes.SMALL}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
import "./settings.css";
|
import "./settings.css";
|
||||||
|
|
||||||
import { classNameFactory } from "@vencord/types/api/Styles";
|
import { classNameFactory } from "@vencord/types/api/Styles";
|
||||||
import { ErrorBoundary } from "@vencord/types/components";
|
import { Divider, ErrorBoundary } from "@vencord/types/components";
|
||||||
import { Forms, Text } from "@vencord/types/webpack/common";
|
import { Text } from "@vencord/types/webpack/common";
|
||||||
import { ComponentType } from "react";
|
import { ComponentType } from "react";
|
||||||
import { isMac, isWindows } from "renderer/constants";
|
import { isMac, isWindows } from "renderer/constants";
|
||||||
import { Settings, useSettings } from "renderer/settings";
|
import { Settings, useSettings } from "renderer/settings";
|
||||||
@@ -173,7 +173,7 @@ function SettingsSections() {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{i < arr.length - 1 && <Forms.FormDivider className={cl("category-divider")} />}
|
{i < arr.length - 1 && <Divider className={cl("category-divider")} />}
|
||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Paragraph } from "@vencord/types/components";
|
||||||
import { useAwaiter } from "@vencord/types/utils";
|
import { useAwaiter } from "@vencord/types/utils";
|
||||||
import { Button, Text } from "@vencord/types/webpack/common";
|
import { Button } from "@vencord/types/webpack/common";
|
||||||
|
|
||||||
import { cl } from "./Settings";
|
import { cl } from "./Settings";
|
||||||
|
|
||||||
@@ -16,8 +17,12 @@ export function Updater() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cl("updater-card")}>
|
<div className={cl("updater-card")}>
|
||||||
<Text variant="text-md/semibold">Your Vesktop is outdated!</Text>
|
<Paragraph size="md" weight="semibold">
|
||||||
<Text variant="text-sm/normal">Staying up to date is important for security and stability.</Text>
|
Your Vesktop is outdated!
|
||||||
|
</Paragraph>
|
||||||
|
<Paragraph size="sm" weight="normal">
|
||||||
|
Staying up to date is important for security and stability.
|
||||||
|
</Paragraph>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={() => VesktopNative.app.openUpdater()}
|
onClick={() => VesktopNative.app.openUpdater()}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import "./UserAssets.css";
|
import "./UserAssets.css";
|
||||||
|
|
||||||
import { FormSwitch } from "@vencord/types/components";
|
import { FormSwitch, Heading } from "@vencord/types/components";
|
||||||
import {
|
import {
|
||||||
Margins,
|
Margins,
|
||||||
ModalCloseButton,
|
ModalCloseButton,
|
||||||
@@ -73,9 +73,7 @@ function Asset({ asset }: { asset: UserAssetType }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<Text tag="h3" variant="text-md/semibold">
|
<Heading tag="h3">{wordsToTitle(wordsFromCamel(asset))}</Heading>
|
||||||
{wordsToTitle(wordsFromCamel(asset))}
|
|
||||||
</Text>
|
|
||||||
<div className="vcd-user-assets-asset">
|
<div className="vcd-user-assets-asset">
|
||||||
<img
|
<img
|
||||||
className="vcd-user-assets-image"
|
className="vcd-user-assets-image"
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ErrorBoundary } from "@vencord/types/components";
|
import { ErrorBoundary, Heading, Paragraph } from "@vencord/types/components";
|
||||||
import { Margins } from "@vencord/types/utils";
|
import { Margins } from "@vencord/types/utils";
|
||||||
import { Forms, Select } from "@vencord/types/webpack/common";
|
import { Select } from "@vencord/types/webpack/common";
|
||||||
|
|
||||||
import { SettingsComponent } from "./Settings";
|
import { SettingsComponent } from "./Settings";
|
||||||
|
|
||||||
@@ -16,10 +16,10 @@ export const WindowsTransparencyControls: SettingsComponent = ({ settings }) =>
|
|||||||
return (
|
return (
|
||||||
<ErrorBoundary noop>
|
<ErrorBoundary noop>
|
||||||
<div>
|
<div>
|
||||||
<Forms.FormTitle className={Margins.bottom8}>Transparency Options</Forms.FormTitle>
|
<Heading>Transparency Options</Heading>
|
||||||
<Forms.FormText className={Margins.bottom8}>
|
<Paragraph className={Margins.bottom8}>
|
||||||
Requires a full restart. You will need a theme that supports transparency for this to work.
|
Requires a full restart. You will need a theme that supports transparency for this to work.
|
||||||
</Forms.FormText>
|
</Paragraph>
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
placeholder="None"
|
placeholder="None"
|
||||||
|
|||||||
Reference in New Issue
Block a user