mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-03 00:33:49 +03:00
refactor: migrate settings page styles from VE to SCSS + BEM
This commit is contained in:
parent
eed28d7444
commit
c51b61501e
@ -0,0 +1,27 @@
|
|||||||
|
@use "../../scss/globals.scss";
|
||||||
|
|
||||||
|
.add-download-source-modal {
|
||||||
|
&__container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: globals.$spacing-unit;
|
||||||
|
min-width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__validation-result {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: calc(globals.$spacing-unit * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__validation-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: calc(globals.$spacing-unit / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__validate-button {
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@ import { useCallback, useContext, useEffect, useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { Button, Modal, TextField } from "@renderer/components";
|
import { Button, Modal, TextField } from "@renderer/components";
|
||||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
|
||||||
import { settingsContext } from "@renderer/context";
|
import { settingsContext } from "@renderer/context";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
@ -11,6 +10,7 @@ import { yupResolver } from "@hookform/resolvers/yup";
|
|||||||
import { downloadSourcesTable } from "@renderer/dexie";
|
import { downloadSourcesTable } from "@renderer/dexie";
|
||||||
import type { DownloadSourceValidationResult } from "@types";
|
import type { DownloadSourceValidationResult } from "@types";
|
||||||
import { downloadSourcesWorker } from "@renderer/workers";
|
import { downloadSourcesWorker } from "@renderer/workers";
|
||||||
|
import "./add-download-source-modal.scss";
|
||||||
|
|
||||||
interface AddDownloadSourceModalProps {
|
interface AddDownloadSourceModalProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@ -138,14 +138,7 @@ export function AddDownloadSourceModal({
|
|||||||
description={t("add_download_source_description")}
|
description={t("add_download_source_description")}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
>
|
>
|
||||||
<div
|
<div className="add-download-source-modal__container">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: `${SPACING_UNIT}px`,
|
|
||||||
minWidth: "500px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<TextField
|
<TextField
|
||||||
{...register("url")}
|
{...register("url")}
|
||||||
label={t("download_source_url")}
|
label={t("download_source_url")}
|
||||||
@ -155,7 +148,7 @@ export function AddDownloadSourceModal({
|
|||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
theme="outline"
|
theme="outline"
|
||||||
style={{ alignSelf: "flex-end" }}
|
className="add-download-source-modal__validate-button"
|
||||||
onClick={handleSubmit(onSubmit)}
|
onClick={handleSubmit(onSubmit)}
|
||||||
disabled={isSubmitting || isLoading}
|
disabled={isSubmitting || isLoading}
|
||||||
>
|
>
|
||||||
@ -165,21 +158,8 @@ export function AddDownloadSourceModal({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{validationResult && (
|
{validationResult && (
|
||||||
<div
|
<div className="add-download-source-modal__validation-result">
|
||||||
style={{
|
<div className="add-download-source-modal__validation-info">
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
alignItems: "center",
|
|
||||||
marginTop: `${SPACING_UNIT * 3}px`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: `${SPACING_UNIT / 2}px`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<h4>{validationResult?.name}</h4>
|
<h4>{validationResult?.name}</h4>
|
||||||
<small>
|
<small>
|
||||||
{t("found_download_option", {
|
{t("found_download_option", {
|
||||||
|
67
src/renderer/src/pages/settings/settings-account.scss
Normal file
67
src/renderer/src/pages/settings/settings-account.scss
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
@use "../../scss/globals.scss";
|
||||||
|
|
||||||
|
.settings-account {
|
||||||
|
&__form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: calc(globals.$spacing-unit * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: globals.$spacing-unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__actions {
|
||||||
|
display: flex;
|
||||||
|
gap: globals.$spacing-unit;
|
||||||
|
margin-top: globals.$spacing-unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subscription-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: calc(globals.$spacing-unit * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subscription-button {
|
||||||
|
place-self: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__blocked-users {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: globals.$spacing-unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__blocked-user {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: globals.$spacing-unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__user-info {
|
||||||
|
display: flex;
|
||||||
|
gap: globals.$spacing-unit;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__user-avatar {
|
||||||
|
filter: grayscale(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__unblock-button {
|
||||||
|
color: globals.$danger-color;
|
||||||
|
cursor: pointer;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,6 @@
|
|||||||
import { Avatar, Button, SelectField } from "@renderer/components";
|
import { Avatar, Button, SelectField } from "@renderer/components";
|
||||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import * as styles from "./settings-account.css";
|
|
||||||
import { useDate, useToast, useUserDetails } from "@renderer/hooks";
|
import { useDate, useToast, useUserDetails } from "@renderer/hooks";
|
||||||
import { useCallback, useContext, useEffect, useState } from "react";
|
import { useCallback, useContext, useEffect, useState } from "react";
|
||||||
import {
|
import {
|
||||||
@ -14,6 +11,7 @@ import {
|
|||||||
} from "@primer/octicons-react";
|
} from "@primer/octicons-react";
|
||||||
import { settingsContext } from "@renderer/context";
|
import { settingsContext } from "@renderer/context";
|
||||||
import { AuthPage } from "@shared";
|
import { AuthPage } from "@shared";
|
||||||
|
import "./settings-account.scss";
|
||||||
|
|
||||||
interface FormValues {
|
interface FormValues {
|
||||||
profileVisibility: "PUBLIC" | "FRIENDS" | "PRIVATE";
|
profileVisibility: "PUBLIC" | "FRIENDS" | "PRIVATE";
|
||||||
@ -145,7 +143,7 @@ export function SettingsAccount() {
|
|||||||
if (!userDetails) return null;
|
if (!userDetails) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
|
<form className="settings-account__form" onSubmit={handleSubmit(onSubmit)}>
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="profileVisibility"
|
name="profileVisibility"
|
||||||
@ -158,7 +156,7 @@ export function SettingsAccount() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section className="settings-account__section">
|
||||||
<SelectField
|
<SelectField
|
||||||
label={t("profile_visibility")}
|
label={t("profile_visibility")}
|
||||||
value={field.value}
|
value={field.value}
|
||||||
@ -177,19 +175,11 @@ export function SettingsAccount() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<section>
|
<section className="settings-account__section">
|
||||||
<h4>{t("current_email")}</h4>
|
<h4>{t("current_email")}</h4>
|
||||||
<p>{userDetails?.email ?? t("no_email_account")}</p>
|
<p>{userDetails?.email ?? t("no_email_account")}</p>
|
||||||
|
|
||||||
<div
|
<div className="settings-account__actions">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "start",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: `${SPACING_UNIT}px`,
|
|
||||||
marginTop: `${SPACING_UNIT * 2}px`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button
|
<Button
|
||||||
theme="outline"
|
theme="outline"
|
||||||
onClick={() => window.electron.openAuthWindow(AuthPage.UpdateEmail)}
|
onClick={() => window.electron.openAuthWindow(AuthPage.UpdateEmail)}
|
||||||
@ -210,28 +200,14 @@ export function SettingsAccount() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section
|
<section className="settings-account__section">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: `${SPACING_UNIT * 2}px`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<h3>Hydra Cloud</h3>
|
<h3>Hydra Cloud</h3>
|
||||||
<div
|
<div className="settings-account__subscription-info">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: `${SPACING_UNIT}px`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{getHydraCloudSectionContent().description}
|
{getHydraCloudSectionContent().description}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
style={{
|
className="settings-account__subscription-button"
|
||||||
placeSelf: "flex-start",
|
|
||||||
}}
|
|
||||||
theme="outline"
|
theme="outline"
|
||||||
onClick={() => window.electron.openCheckout()}
|
onClick={() => window.electron.openCheckout()}
|
||||||
>
|
>
|
||||||
@ -240,29 +216,17 @@ export function SettingsAccount() {
|
|||||||
</Button>
|
</Button>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section
|
<section className="settings-account__section">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: `${SPACING_UNIT * 2}px`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<h3>{t("blocked_users")}</h3>
|
<h3>{t("blocked_users")}</h3>
|
||||||
|
|
||||||
{blockedUsers.length > 0 ? (
|
{blockedUsers.length > 0 ? (
|
||||||
<ul className={styles.blockedUsersList}>
|
<ul className="settings-account__blocked-users">
|
||||||
{blockedUsers.map((user) => {
|
{blockedUsers.map((user) => {
|
||||||
return (
|
return (
|
||||||
<li key={user.id} className={styles.blockedUser}>
|
<li key={user.id} className="settings-account__blocked-user">
|
||||||
<div
|
<div className="settings-account__user-info">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
gap: `${SPACING_UNIT}px`,
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Avatar
|
<Avatar
|
||||||
style={{ filter: "grayscale(100%)" }}
|
className="settings-account__user-avatar"
|
||||||
size={32}
|
size={32}
|
||||||
src={user.profileImageUrl}
|
src={user.profileImageUrl}
|
||||||
alt={user.displayName}
|
alt={user.displayName}
|
||||||
@ -272,7 +236,7 @@ export function SettingsAccount() {
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.unblockButton}
|
className="settings-account__unblock-button"
|
||||||
onClick={() => handleUnblockClick(user.id)}
|
onClick={() => handleUnblockClick(user.id)}
|
||||||
disabled={isUnblocking}
|
disabled={isUnblocking}
|
||||||
>
|
>
|
||||||
|
13
src/renderer/src/pages/settings/settings-behavior.scss
Normal file
13
src/renderer/src/pages/settings/settings-behavior.scss
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
@use "../../scss/globals.scss";
|
||||||
|
|
||||||
|
.settings-behavior {
|
||||||
|
&__checkbox-container {
|
||||||
|
opacity: globals.$disabled-opacity;
|
||||||
|
cursor: not-allowed;
|
||||||
|
|
||||||
|
&--enabled {
|
||||||
|
opacity: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { CheckboxField } from "@renderer/components";
|
import { CheckboxField } from "@renderer/components";
|
||||||
import { useAppSelector } from "@renderer/hooks";
|
import { useAppSelector } from "@renderer/hooks";
|
||||||
import { settingsContext } from "@renderer/context";
|
import { settingsContext } from "@renderer/context";
|
||||||
|
import "./settings-behavior.scss";
|
||||||
|
|
||||||
export function SettingsBehavior() {
|
export function SettingsBehavior() {
|
||||||
const userPreferences = useAppSelector(
|
const userPreferences = useAppSelector(
|
||||||
@ -77,10 +78,11 @@ export function SettingsBehavior() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{showRunAtStartup && (
|
{showRunAtStartup && (
|
||||||
<div style={{ opacity: form.runAtStartup ? 1 : 0.5 }}>
|
<div
|
||||||
|
className={`settings-behavior__checkbox-container ${form.runAtStartup ? "settings-behavior__checkbox-container--enabled" : ""}`}
|
||||||
|
>
|
||||||
<CheckboxField
|
<CheckboxField
|
||||||
label={t("launch_minimized")}
|
label={t("launch_minimized")}
|
||||||
style={{ cursor: form.runAtStartup ? "pointer" : "not-allowed" }}
|
|
||||||
checked={form.runAtStartup && form.startMinimized}
|
checked={form.runAtStartup && form.startMinimized}
|
||||||
disabled={!form.runAtStartup}
|
disabled={!form.runAtStartup}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
@use "../../scss/globals.scss";
|
||||||
|
|
||||||
|
.settings-download-sources {
|
||||||
|
&__list {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
gap: calc(globals.$spacing-unit * 2);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: globals.$dark-background-color;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: calc(globals.$spacing-unit * 2);
|
||||||
|
gap: globals.$spacing-unit;
|
||||||
|
border: solid 1px globals.$border-color;
|
||||||
|
transition: all ease 0.2s;
|
||||||
|
|
||||||
|
&--syncing {
|
||||||
|
opacity: globals.$disabled-opacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item-header {
|
||||||
|
margin-bottom: globals.$spacing-unit;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: globals.$spacing-unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__navigate-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: globals.$spacing-unit;
|
||||||
|
color: globals.$muted-color;
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
cursor: default;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@ import { useContext, useEffect, useState } from "react";
|
|||||||
import { TextField, Button, Badge } from "@renderer/components";
|
import { TextField, Button, Badge } from "@renderer/components";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import * as styles from "./settings-download-sources.css";
|
|
||||||
import type { DownloadSource } from "@types";
|
import type { DownloadSource } from "@types";
|
||||||
import { NoEntryIcon, PlusCircleIcon, SyncIcon } from "@primer/octicons-react";
|
import { NoEntryIcon, PlusCircleIcon, SyncIcon } from "@primer/octicons-react";
|
||||||
import { AddDownloadSourceModal } from "./add-download-source-modal";
|
import { AddDownloadSourceModal } from "./add-download-source-modal";
|
||||||
@ -14,6 +13,7 @@ import { downloadSourcesTable } from "@renderer/dexie";
|
|||||||
import { downloadSourcesWorker } from "@renderer/workers";
|
import { downloadSourcesWorker } from "@renderer/workers";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { setFilters, clearFilters } from "@renderer/features";
|
import { setFilters, clearFilters } from "@renderer/features";
|
||||||
|
import "./settings-download-sources.scss";
|
||||||
|
|
||||||
export function SettingsDownloadSources() {
|
export function SettingsDownloadSources() {
|
||||||
const [showAddDownloadSourceModal, setShowAddDownloadSourceModal] =
|
const [showAddDownloadSourceModal, setShowAddDownloadSourceModal] =
|
||||||
@ -118,7 +118,7 @@ export function SettingsDownloadSources() {
|
|||||||
|
|
||||||
<p>{t("download_sources_description")}</p>
|
<p>{t("download_sources_description")}</p>
|
||||||
|
|
||||||
<div className={styles.downloadSourcesHeader}>
|
<div className="settings-download-sources__header">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
theme="outline"
|
theme="outline"
|
||||||
@ -144,15 +144,13 @@ export function SettingsDownloadSources() {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul className={styles.downloadSources}>
|
<ul className="settings-download-sources__list">
|
||||||
{downloadSources.map((downloadSource) => (
|
{downloadSources.map((downloadSource) => (
|
||||||
<li
|
<li
|
||||||
key={downloadSource.id}
|
key={downloadSource.id}
|
||||||
className={styles.downloadSourceItem({
|
className={`settings-download-sources__item ${isSyncingDownloadSources ? "settings-download-sources__item--syncing" : ""}`}
|
||||||
isSyncing: isSyncingDownloadSources,
|
|
||||||
})}
|
|
||||||
>
|
>
|
||||||
<div className={styles.downloadSourceItemHeader}>
|
<div className="settings-download-sources__item-header">
|
||||||
<h2>{downloadSource.name}</h2>
|
<h2>{downloadSource.name}</h2>
|
||||||
|
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
@ -161,7 +159,7 @@ export function SettingsDownloadSources() {
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.navigateToCatalogueButton}
|
className="settings-download-sources__navigate-button"
|
||||||
disabled={!downloadSource.fingerprint}
|
disabled={!downloadSource.fingerprint}
|
||||||
onClick={() => navigateToCatalogue(downloadSource.fingerprint)}
|
onClick={() => navigateToCatalogue(downloadSource.fingerprint)}
|
||||||
>
|
>
|
||||||
|
12
src/renderer/src/pages/settings/settings-general.scss
Normal file
12
src/renderer/src/pages/settings/settings-general.scss
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
@use "../../scss/globals.scss";
|
||||||
|
|
||||||
|
.settings-general {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: globals.$spacing-unit * 2;
|
||||||
|
|
||||||
|
&__notifications-title {
|
||||||
|
margin-top: calc(globals.$spacing-unit * 2);
|
||||||
|
margin-bottom: globals.$spacing-unit;
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ import { changeLanguage } from "i18next";
|
|||||||
import languageResources from "@locales";
|
import languageResources from "@locales";
|
||||||
import { orderBy } from "lodash-es";
|
import { orderBy } from "lodash-es";
|
||||||
import { settingsContext } from "@renderer/context";
|
import { settingsContext } from "@renderer/context";
|
||||||
|
import "./settings-general.scss";
|
||||||
|
|
||||||
interface LanguageOption {
|
interface LanguageOption {
|
||||||
option: string;
|
option: string;
|
||||||
@ -114,7 +115,7 @@ export function SettingsGeneral() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="settings-general">
|
||||||
<TextField
|
<TextField
|
||||||
label={t("downloads_path")}
|
label={t("downloads_path")}
|
||||||
value={form.downloadsPath}
|
value={form.downloadsPath}
|
||||||
@ -138,7 +139,9 @@ export function SettingsGeneral() {
|
|||||||
}))}
|
}))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<p>{t("notifications")}</p>
|
<p className="settings-general__notifications-title">
|
||||||
|
{t("notifications")}
|
||||||
|
</p>
|
||||||
|
|
||||||
<CheckboxField
|
<CheckboxField
|
||||||
label={t("enable_download_notifications")}
|
label={t("enable_download_notifications")}
|
||||||
@ -171,6 +174,6 @@ export function SettingsGeneral() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
18
src/renderer/src/pages/settings/settings-real-debrid.scss
Normal file
18
src/renderer/src/pages/settings/settings-real-debrid.scss
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
@use "../../scss/globals.scss";
|
||||||
|
|
||||||
|
.settings-real-debrid {
|
||||||
|
&__form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: globals.$spacing-unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__description {
|
||||||
|
margin-bottom: calc(globals.$spacing-unit * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__submit-button {
|
||||||
|
align-self: flex-end;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
@ -2,11 +2,10 @@ import { useContext, useEffect, useState } from "react";
|
|||||||
import { Trans, useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { Button, CheckboxField, Link, TextField } from "@renderer/components";
|
import { Button, CheckboxField, Link, TextField } from "@renderer/components";
|
||||||
import * as styles from "./settings-real-debrid.css";
|
import "./settings-real-debrid.scss";
|
||||||
|
|
||||||
import { useAppSelector, useToast } from "@renderer/hooks";
|
import { useAppSelector, useToast } from "@renderer/hooks";
|
||||||
|
|
||||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
|
||||||
import { settingsContext } from "@renderer/context";
|
import { settingsContext } from "@renderer/context";
|
||||||
|
|
||||||
const REAL_DEBRID_API_TOKEN_URL = "https://real-debrid.com/apitoken";
|
const REAL_DEBRID_API_TOKEN_URL = "https://real-debrid.com/apitoken";
|
||||||
@ -78,8 +77,10 @@ export function SettingsRealDebrid() {
|
|||||||
(form.useRealDebrid && !form.realDebridApiToken) || isLoading;
|
(form.useRealDebrid && !form.realDebridApiToken) || isLoading;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className={styles.form} onSubmit={handleFormSubmit}>
|
<form className="settings-real-debrid__form" onSubmit={handleFormSubmit}>
|
||||||
<p className={styles.description}>{t("real_debrid_description")}</p>
|
<p className="settings-real-debrid__description">
|
||||||
|
{t("real_debrid_description")}
|
||||||
|
</p>
|
||||||
|
|
||||||
<CheckboxField
|
<CheckboxField
|
||||||
label={t("enable_real_debrid")}
|
label={t("enable_real_debrid")}
|
||||||
@ -100,8 +101,12 @@ export function SettingsRealDebrid() {
|
|||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
setForm({ ...form, realDebridApiToken: event.target.value })
|
setForm({ ...form, realDebridApiToken: event.target.value })
|
||||||
}
|
}
|
||||||
|
rightContent={
|
||||||
|
<Button type="submit" disabled={isButtonDisabled}>
|
||||||
|
{t("save_changes")}
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
placeholder="API Token"
|
placeholder="API Token"
|
||||||
containerProps={{ style: { marginTop: `${SPACING_UNIT}px` } }}
|
|
||||||
hint={
|
hint={
|
||||||
<Trans i18nKey="real_debrid_api_token_hint" ns="settings">
|
<Trans i18nKey="real_debrid_api_token_hint" ns="settings">
|
||||||
<Link to={REAL_DEBRID_API_TOKEN_URL} />
|
<Link to={REAL_DEBRID_API_TOKEN_URL} />
|
||||||
@ -109,14 +114,6 @@ export function SettingsRealDebrid() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
style={{ alignSelf: "flex-end", marginTop: `${SPACING_UNIT * 2}px` }}
|
|
||||||
disabled={isButtonDisabled}
|
|
||||||
>
|
|
||||||
{t("save_changes")}
|
|
||||||
</Button>
|
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
27
src/renderer/src/pages/settings/settings.scss
Normal file
27
src/renderer/src/pages/settings/settings.scss
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
@use "../../scss/globals.scss";
|
||||||
|
|
||||||
|
.settings {
|
||||||
|
&__container {
|
||||||
|
padding: 24px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
background-color: globals.$background-color;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: calc(globals.$spacing-unit * 3);
|
||||||
|
border: solid 1px globals.$border-color;
|
||||||
|
box-shadow: 0px 0px 15px 0px #000000;
|
||||||
|
border-radius: 8px;
|
||||||
|
gap: calc(globals.$spacing-unit * 2);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__categories {
|
||||||
|
display: flex;
|
||||||
|
gap: globals.$spacing-unit;
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,8 @@
|
|||||||
import { Button } from "@renderer/components";
|
import { Button } from "@renderer/components";
|
||||||
|
|
||||||
import * as styles from "./settings.css";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { SettingsRealDebrid } from "./settings-real-debrid";
|
import { SettingsRealDebrid } from "./settings-real-debrid";
|
||||||
import { SettingsGeneral } from "./settings-general";
|
import { SettingsGeneral } from "./settings-general";
|
||||||
import { SettingsBehavior } from "./settings-behavior";
|
import { SettingsBehavior } from "./settings-behavior";
|
||||||
|
|
||||||
import { SettingsDownloadSources } from "./settings-download-sources";
|
import { SettingsDownloadSources } from "./settings-download-sources";
|
||||||
import {
|
import {
|
||||||
SettingsContextConsumer,
|
SettingsContextConsumer,
|
||||||
@ -14,10 +11,10 @@ import {
|
|||||||
import { SettingsAccount } from "./settings-account";
|
import { SettingsAccount } from "./settings-account";
|
||||||
import { useUserDetails } from "@renderer/hooks";
|
import { useUserDetails } from "@renderer/hooks";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
import "./settings.scss";
|
||||||
|
|
||||||
export default function Settings() {
|
export default function Settings() {
|
||||||
const { t } = useTranslation("settings");
|
const { t } = useTranslation("settings");
|
||||||
|
|
||||||
const { userDetails } = useUserDetails();
|
const { userDetails } = useUserDetails();
|
||||||
|
|
||||||
const categories = useMemo(() => {
|
const categories = useMemo(() => {
|
||||||
@ -57,9 +54,9 @@ export default function Settings() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={styles.container}>
|
<section className="settings__container">
|
||||||
<div className={styles.content}>
|
<div className="settings__content">
|
||||||
<section className={styles.settingsCategories}>
|
<section className="settings__categories">
|
||||||
{categories.map((category, index) => (
|
{categories.map((category, index) => (
|
||||||
<Button
|
<Button
|
||||||
key={category}
|
key={category}
|
||||||
|
Loading…
Reference in New Issue
Block a user