mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-09 03:37:45 +03:00
refactor: migrate shared modals styles from VE to SCSS + BEM
This commit is contained in:
parent
c51b61501e
commit
19976da82e
@ -0,0 +1,10 @@
|
||||
@use "../../../scss/globals.scss";
|
||||
|
||||
.hydra-cloud-modal {
|
||||
&__container {
|
||||
display: flex;
|
||||
width: 500px;
|
||||
flex-direction: column;
|
||||
gap: calc(globals.$spacing-unit * 2);
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { Button, Modal } from "@renderer/components";
|
||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import "./hydra-cloud-modal.scss";
|
||||
|
||||
export interface HydraCloudModalProps {
|
||||
feature: string;
|
||||
@ -22,13 +22,8 @@ export const HydraCloudModal = ({
|
||||
return (
|
||||
<Modal visible={visible} title={t("hydra_cloud")} onClose={onClose}>
|
||||
<div
|
||||
className="hydra-cloud-modal__container"
|
||||
data-hydra-cloud-feature={feature}
|
||||
style={{
|
||||
display: "flex",
|
||||
width: "500px",
|
||||
flexDirection: "column",
|
||||
gap: `${SPACING_UNIT * 2}px`,
|
||||
}}
|
||||
>
|
||||
{t("hydra_cloud_feature_found")}
|
||||
<Button onClick={handleClickOpenCheckout}>{t("learn_more")}</Button>
|
||||
|
@ -0,0 +1,64 @@
|
||||
@use "../../../scss/globals.scss";
|
||||
|
||||
.user-friend-item {
|
||||
&__container {
|
||||
display: flex;
|
||||
gap: calc(globals.$spacing-unit * 3);
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
border: solid 1px globals.$border-color;
|
||||
width: 100%;
|
||||
height: 54px;
|
||||
min-height: 54px;
|
||||
transition: all ease 0.2s;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
&__button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
color: globals.$body-color;
|
||||
gap: calc(globals.$spacing-unit + globals.$spacing-unit / 2);
|
||||
padding: 0 globals.$spacing-unit;
|
||||
}
|
||||
|
||||
&__display-name {
|
||||
font-weight: bold;
|
||||
font-size: globals.$body-font-size;
|
||||
text-align: left;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__accept-button {
|
||||
cursor: pointer;
|
||||
color: globals.$body-color;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
|
||||
&:hover {
|
||||
color: globals.$success-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__cancel-button {
|
||||
cursor: pointer;
|
||||
color: globals.$body-color;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
|
||||
&:hover {
|
||||
color: globals.$danger-color;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
import { CheckCircleIcon, XCircleIcon } from "@primer/octicons-react";
|
||||
import * as styles from "./user-friend-modal.css";
|
||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Avatar } from "@renderer/components";
|
||||
import "./user-friend-item.scss";
|
||||
|
||||
export type UserFriendItemProps = {
|
||||
userId: string;
|
||||
@ -31,10 +30,9 @@ export const UserFriendItem = (props: UserFriendItemProps) => {
|
||||
|
||||
const getRequestDescription = () => {
|
||||
if (type === "ACCEPTED" || type === null) return null;
|
||||
|
||||
return (
|
||||
<small>
|
||||
{type == "SENT" ? t("request_sent") : t("request_received")}
|
||||
{type === "SENT" ? t("request_sent") : t("request_received")}
|
||||
</small>
|
||||
);
|
||||
};
|
||||
@ -45,7 +43,7 @@ export const UserFriendItem = (props: UserFriendItemProps) => {
|
||||
if (type === "SENT") {
|
||||
return (
|
||||
<button
|
||||
className={styles.cancelRequestButton}
|
||||
className="user-friend-item__cancel-button"
|
||||
onClick={() => props.onClickCancelRequest(userId)}
|
||||
title={t("cancel_request")}
|
||||
>
|
||||
@ -58,14 +56,14 @@ export const UserFriendItem = (props: UserFriendItemProps) => {
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className={styles.acceptRequestButton}
|
||||
className="user-friend-item__accept-button"
|
||||
onClick={() => props.onClickAcceptRequest(userId)}
|
||||
title={t("accept_request")}
|
||||
>
|
||||
<CheckCircleIcon size={28} />
|
||||
</button>
|
||||
<button
|
||||
className={styles.cancelRequestButton}
|
||||
className="user-friend-item__cancel-button"
|
||||
onClick={() => props.onClickRefuseRequest(userId)}
|
||||
title={t("ignore_request")}
|
||||
>
|
||||
@ -78,7 +76,7 @@ export const UserFriendItem = (props: UserFriendItemProps) => {
|
||||
if (type === "ACCEPTED") {
|
||||
return (
|
||||
<button
|
||||
className={styles.cancelRequestButton}
|
||||
className="user-friend-item__cancel-button"
|
||||
onClick={() => props.onClickUndoFriendship(userId)}
|
||||
title={t("undo_friendship")}
|
||||
>
|
||||
@ -90,7 +88,7 @@ export const UserFriendItem = (props: UserFriendItemProps) => {
|
||||
if (type === "BLOCKED") {
|
||||
return (
|
||||
<button
|
||||
className={styles.cancelRequestButton}
|
||||
className="user-friend-item__cancel-button"
|
||||
onClick={() => props.onClickUnblock(userId)}
|
||||
title={t("unblock")}
|
||||
>
|
||||
@ -104,10 +102,9 @@ export const UserFriendItem = (props: UserFriendItemProps) => {
|
||||
|
||||
if (type === "BLOCKED") {
|
||||
return (
|
||||
<div className={styles.friendListContainer}>
|
||||
<div className={styles.friendListButton} style={{ cursor: "inherit" }}>
|
||||
<div className="user-friend-item__container">
|
||||
<div className="user-friend-item__button" style={{ cursor: "inherit" }}>
|
||||
<Avatar size={35} src={profileImageUrl} alt={displayName} />
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
@ -117,16 +114,15 @@ export const UserFriendItem = (props: UserFriendItemProps) => {
|
||||
minWidth: 0,
|
||||
}}
|
||||
>
|
||||
<p className={styles.friendListDisplayName}>{displayName}</p>
|
||||
<p className="user-friend-item__display-name">{displayName}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: "8px",
|
||||
display: "flex",
|
||||
gap: `${SPACING_UNIT}px`,
|
||||
gap: "8px",
|
||||
}}
|
||||
>
|
||||
{getRequestActions()}
|
||||
@ -136,10 +132,10 @@ export const UserFriendItem = (props: UserFriendItemProps) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.friendListContainer}>
|
||||
<div className="user-friend-item__container">
|
||||
<button
|
||||
type="button"
|
||||
className={styles.friendListButton}
|
||||
className="user-friend-item__button"
|
||||
onClick={() => props.onClickItem(userId)}
|
||||
>
|
||||
<Avatar size={35} src={profileImageUrl} alt={displayName} />
|
||||
@ -152,17 +148,16 @@ export const UserFriendItem = (props: UserFriendItemProps) => {
|
||||
minWidth: 0,
|
||||
}}
|
||||
>
|
||||
<p className={styles.friendListDisplayName}>{displayName}</p>
|
||||
<p className="user-friend-item__display-name">{displayName}</p>
|
||||
{getRequestDescription()}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: "8px",
|
||||
display: "flex",
|
||||
gap: `${SPACING_UNIT}px`,
|
||||
gap: "8px",
|
||||
}}
|
||||
>
|
||||
{getRequestActions()}
|
||||
|
@ -0,0 +1,21 @@
|
||||
@use "../../../scss/globals.scss";
|
||||
|
||||
.user-friend-modal-add-friend {
|
||||
&__actions {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: globals.$spacing-unit;
|
||||
}
|
||||
|
||||
&__button {
|
||||
align-self: end;
|
||||
}
|
||||
|
||||
&__pending-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: calc(globals.$spacing-unit * 2);
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
import { Button, TextField } from "@renderer/components";
|
||||
import { useToast, useUserDetails } from "@renderer/hooks";
|
||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { UserFriendItem } from "./user-friend-item";
|
||||
import "./user-friend-modal-add-friend.scss";
|
||||
|
||||
export interface UserFriendModalAddFriendProps {
|
||||
closeModal: () => void;
|
||||
@ -76,15 +76,7 @@ export const UserFriendModalAddFriend = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
gap: `${SPACING_UNIT}px`,
|
||||
}}
|
||||
>
|
||||
<div className="user-friend-modal-add-friend__actions">
|
||||
<TextField
|
||||
label={t("friend_code")}
|
||||
value={friendCode}
|
||||
@ -95,7 +87,7 @@ export const UserFriendModalAddFriend = ({
|
||||
/>
|
||||
<Button
|
||||
disabled={isAddingFriend}
|
||||
style={{ alignSelf: "end" }}
|
||||
className="user-friend-modal-add-friend__button"
|
||||
type="button"
|
||||
onClick={handleClickAddFriend}
|
||||
>
|
||||
@ -105,20 +97,14 @@ export const UserFriendModalAddFriend = ({
|
||||
<Button
|
||||
onClick={handleClickSeeProfile}
|
||||
disabled={isAddingFriend}
|
||||
style={{ alignSelf: "end" }}
|
||||
className="user-friend-modal-add-friend__button"
|
||||
type="button"
|
||||
>
|
||||
{t("see_profile")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: `${SPACING_UNIT * 2}px`,
|
||||
}}
|
||||
>
|
||||
<div className="user-friend-modal-add-friend__pending-container">
|
||||
<h3>{t("pending")}</h3>
|
||||
{friendRequests.length === 0 && <p>{t("no_pending_invites")}</p>}
|
||||
{friendRequests.map((request) => {
|
||||
|
@ -0,0 +1,16 @@
|
||||
@use "../../../scss/globals.scss";
|
||||
|
||||
.user-friend-modal-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: calc(globals.$spacing-unit * 2);
|
||||
max-height: 400px;
|
||||
overflow-y: scroll;
|
||||
|
||||
&__skeleton {
|
||||
width: 100%;
|
||||
height: 54px;
|
||||
overflow: hidden;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
import { SPACING_UNIT, vars } from "@renderer/theme.css";
|
||||
import type { UserFriend } from "@types";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { UserFriendItem } from "./user-friend-item";
|
||||
@ -6,6 +5,7 @@ import { useNavigate } from "react-router-dom";
|
||||
import { useToast, useUserDetails } from "@renderer/hooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Skeleton, { SkeletonTheme } from "react-loading-skeleton";
|
||||
import "./user-friend-modal-list.scss";
|
||||
|
||||
export interface UserFriendModalListProps {
|
||||
userId: string;
|
||||
@ -94,41 +94,21 @@ export const UserFriendModalList = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<SkeletonTheme baseColor={vars.color.background} highlightColor="#444">
|
||||
<div
|
||||
ref={listContainer}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: `${SPACING_UNIT * 2}px`,
|
||||
maxHeight: "400px",
|
||||
overflowY: "scroll",
|
||||
}}
|
||||
>
|
||||
<SkeletonTheme baseColor="#1c1c1c" highlightColor="#444">
|
||||
<div ref={listContainer} className="user-friend-modal-list">
|
||||
{!isLoading && friends.length === 0 && <p>{t("no_friends_added")}</p>}
|
||||
{friends.map((friend) => {
|
||||
return (
|
||||
<UserFriendItem
|
||||
userId={friend.id}
|
||||
displayName={friend.displayName}
|
||||
profileImageUrl={friend.profileImageUrl}
|
||||
onClickItem={handleClickFriend}
|
||||
onClickUndoFriendship={handleUndoFriendship}
|
||||
type={isMe ? "ACCEPTED" : null}
|
||||
key={"modal" + friend.id}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{isLoading && (
|
||||
<Skeleton
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "54px",
|
||||
overflow: "hidden",
|
||||
borderRadius: "4px",
|
||||
}}
|
||||
{friends.map((friend) => (
|
||||
<UserFriendItem
|
||||
userId={friend.id}
|
||||
displayName={friend.displayName}
|
||||
profileImageUrl={friend.profileImageUrl}
|
||||
onClickItem={handleClickFriend}
|
||||
onClickUndoFriendship={handleUndoFriendship}
|
||||
type={isMe ? "ACCEPTED" : null}
|
||||
key={"modal" + friend.id}
|
||||
/>
|
||||
)}
|
||||
))}
|
||||
{isLoading && <Skeleton className="user-friend-modal-list__skeleton" />}
|
||||
</div>
|
||||
</SkeletonTheme>
|
||||
);
|
||||
|
@ -0,0 +1,34 @@
|
||||
@use "../../../scss/globals.scss";
|
||||
|
||||
.user-friend-modal {
|
||||
&__container {
|
||||
display: flex;
|
||||
width: 500px;
|
||||
flex-direction: column;
|
||||
gap: calc(globals.$spacing-unit * 2);
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
gap: globals.$spacing-unit;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__friend-code-button {
|
||||
color: globals.$body-color;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
gap: calc(globals.$spacing-unit / 2);
|
||||
align-items: center;
|
||||
transition: all ease 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: globals.$muted-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__tabs {
|
||||
display: flex;
|
||||
gap: globals.$spacing-unit;
|
||||
}
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
import { Button, Modal } from "@renderer/components";
|
||||
import { SPACING_UNIT } from "@renderer/theme.css";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { UserFriendModalAddFriend } from "./user-friend-modal-add-friend";
|
||||
import { useToast, useUserDetails } from "@renderer/hooks";
|
||||
import { UserFriendModalList } from "./user-friend-modal-list";
|
||||
import { CopyIcon } from "@primer/octicons-react";
|
||||
import * as styles from "./user-friend-modal.css";
|
||||
import "./user-friend-modal.scss";
|
||||
|
||||
export enum UserFriendModalTab {
|
||||
FriendsList,
|
||||
@ -27,15 +26,11 @@ export const UserFriendModal = ({
|
||||
userId,
|
||||
}: UserFriendsModalProps) => {
|
||||
const { t } = useTranslation("user_profile");
|
||||
|
||||
const tabs = [t("friends_list"), t("add_friends")];
|
||||
|
||||
const [currentTab, setCurrentTab] = useState(
|
||||
initialTab || UserFriendModalTab.FriendsList
|
||||
);
|
||||
|
||||
const { showSuccessToast } = useToast();
|
||||
|
||||
const { userDetails } = useUserDetails();
|
||||
const isMe = userDetails?.id == userId;
|
||||
|
||||
@ -64,44 +59,29 @@ export const UserFriendModal = ({
|
||||
|
||||
return (
|
||||
<Modal visible={visible} title={t("friends")} onClose={onClose}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
width: "500px",
|
||||
flexDirection: "column",
|
||||
gap: `${SPACING_UNIT * 2}px`,
|
||||
}}
|
||||
>
|
||||
<div className="user-friend-modal__container">
|
||||
{isMe && (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: `${SPACING_UNIT}px`,
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<div className="user-friend-modal__header">
|
||||
<p>{t("your_friend_code")}</p>
|
||||
<button
|
||||
className={styles.friendCodeButton}
|
||||
className="user-friend-modal__friend-code-button"
|
||||
onClick={copyToClipboard}
|
||||
>
|
||||
<h3>{userDetails.id}</h3>
|
||||
<CopyIcon />
|
||||
</button>
|
||||
</div>
|
||||
<section style={{ display: "flex", gap: `${SPACING_UNIT}px` }}>
|
||||
{tabs.map((tab, index) => {
|
||||
return (
|
||||
<Button
|
||||
key={tab}
|
||||
theme={index === currentTab ? "primary" : "outline"}
|
||||
onClick={() => setCurrentTab(index)}
|
||||
>
|
||||
{tab}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
<section className="user-friend-modal__tabs">
|
||||
{tabs.map((tab, index) => (
|
||||
<Button
|
||||
key={tab}
|
||||
theme={index === currentTab ? "primary" : "outline"}
|
||||
onClick={() => setCurrentTab(index)}
|
||||
>
|
||||
{tab}
|
||||
</Button>
|
||||
))}
|
||||
</section>
|
||||
</>
|
||||
)}
|
||||
|
Loading…
Reference in New Issue
Block a user