feat: darkmode draft version
This commit is contained in:
@@ -1,57 +1,9 @@
|
||||
import { FC } from "react";
|
||||
import styled from "styled-components";
|
||||
import CheckSign from "../../../assets/icons/check.sign.svg";
|
||||
import ChannelIcon from "../../../common/component/ChannelIcon";
|
||||
import Search from "../Search";
|
||||
import useFilteredChannels from "../../../common/hook/useFilteredChannels";
|
||||
|
||||
const Styled = styled.div`
|
||||
padding: 0 4px 4px 4px;
|
||||
background: #ffffff;
|
||||
max-height: 400px;
|
||||
overflow: auto;
|
||||
box-shadow: 0 24px 48px -12px rgba(16, 24, 40, 0.18);
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
position: relative;
|
||||
> .search {
|
||||
z-index: 1;
|
||||
background-color: #fff;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
input {
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
> .list {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
padding: 8px;
|
||||
.channel {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
.name {
|
||||
color: #616161;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
.check {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
type Props = {
|
||||
select: number;
|
||||
updateFilter: (param: { channel?: number }) => void;
|
||||
@@ -63,27 +15,27 @@ const Channel: FC<Props> = ({ select = 0, updateFilter }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Styled>
|
||||
<div className="search">
|
||||
<div className="rounded-lg p-1 pt-0 bg-white dark:bg-gray-800 overflow-auto max-h-[400px] flex flex-col items-start relative drop-shadow">
|
||||
<div className=" bg-white dark:bg-gray-800 sticky top-0 z-10">
|
||||
<Search embed={true} value={input} updateSearchValue={updateInput} />
|
||||
</div>
|
||||
<ul className="list">
|
||||
<li className="channel" onClick={handleClick.bind(null, undefined)}>
|
||||
<ul className="w-full flex flex-col gap-4 p-2">
|
||||
<li className="relative cursor-pointer flex items-center gap-2" onClick={handleClick.bind(null, undefined)}>
|
||||
<ChannelIcon />
|
||||
<span className="name">Any Channel</span>
|
||||
{!select && <CheckSign className="check" />}
|
||||
<span className="text-gray-500 dark:text-gray-100 font-semibold text-sm">Any Channel</span>
|
||||
{!select && <CheckSign className="absolute right-0 top-1/2 -translate-y-1/2" />}
|
||||
</li>
|
||||
{channels.map(({ gid, is_public, name }) => {
|
||||
return (
|
||||
<li key={gid} className="channel" onClick={handleClick.bind(null, gid)}>
|
||||
<li key={gid} className="relative cursor-pointer flex items-center gap-2" onClick={handleClick.bind(null, gid)}>
|
||||
<ChannelIcon personal={!is_public} />
|
||||
<span className="name">{name}</span>
|
||||
{select == gid && <CheckSign className="check" />}
|
||||
<span className="text-gray-500 dark:text-gray-100 font-semibold text-sm">{name}</span>
|
||||
{select == gid && <CheckSign className="absolute right-0 top-1/2 -translate-y-1/2" />}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</Styled>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default Channel;
|
||||
|
||||
@@ -1,42 +1,6 @@
|
||||
import { FC } from "react";
|
||||
import styled from "styled-components";
|
||||
import CheckSign from "../../../assets/icons/check.sign.svg";
|
||||
|
||||
const Styled = styled.div`
|
||||
padding: 12px;
|
||||
background: #ffffff;
|
||||
min-width: 200px;
|
||||
overflow: auto;
|
||||
box-shadow: 0px 24px 48px -12px rgba(16, 24, 40, 0.18);
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
position: relative;
|
||||
> .list {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
.date {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
color: #616161;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
.check {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const Dates = {
|
||||
today: {
|
||||
@@ -66,22 +30,22 @@ const DateFilter: FC<Props> = ({ select = "", updateFilter }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Styled>
|
||||
<ul className="list">
|
||||
<li className="date" onClick={handleClick.bind(null, undefined)}>
|
||||
<div className="p-3 bg-white min-w-[200px] overflow-auto rounded-lg flex flex-col items-start relative drop-shadow">
|
||||
<ul className="w-full flex flex-col gap-4">
|
||||
<li className="relative cursor-pointer flex items-center gap-4 text-gray-500 font-semibold text-sm" onClick={handleClick.bind(null, undefined)}>
|
||||
Any Time
|
||||
{!select && <CheckSign className="check" />}
|
||||
{!select && <CheckSign className="absolute right-0 top-1/2 -translate-y-1/2" />}
|
||||
</li>
|
||||
{Object.entries(Dates).map(([_key, { title }]) => {
|
||||
return (
|
||||
<li key={title} className="date" onClick={handleClick.bind(null, _key)}>
|
||||
<li key={title} className="relative cursor-pointer flex items-center gap-4 text-gray-500 font-semibold text-sm" onClick={handleClick.bind(null, _key)}>
|
||||
{title}
|
||||
{select == _key && <CheckSign className="check" />}
|
||||
{select == _key && <CheckSign className="absolute right-0 -top-1/2 -translate-y-1/2" />}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</Styled>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default DateFilter;
|
||||
|
||||
@@ -1,53 +1,9 @@
|
||||
import { FC } from "react";
|
||||
import styled from "styled-components";
|
||||
import Search from "../Search";
|
||||
import CheckSign from "../../../assets/icons/check.sign.svg";
|
||||
import User from "../../../common/component/User";
|
||||
import useFilteredUsers from "../../../common/hook/useFilteredUsers";
|
||||
|
||||
const Styled = styled.div`
|
||||
padding: 0 4px 4px 4px;
|
||||
background: #ffffff;
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
box-shadow: 0 24px 48px -12px rgba(16, 24, 40, 0.18);
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
position: relative;
|
||||
> .search {
|
||||
z-index: 1;
|
||||
background-color: #fff;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
input {
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
> .list {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.user {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
&.none {
|
||||
padding: 10px;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #616161;
|
||||
}
|
||||
.check {
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
type Props = {
|
||||
select: number;
|
||||
updateFilter: (param: { from?: number }) => void;
|
||||
@@ -59,25 +15,25 @@ const From: FC<Props> = ({ select = "", updateFilter }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Styled>
|
||||
<div className="search">
|
||||
<div className="rounded-lg p-1 pt-0 bg-white dark:bg-gray-800 overflow-auto max-h-[300px] flex flex-col items-start relative drop-shadow">
|
||||
<div className="bg-white sticky top-0 z-10">
|
||||
<Search embed={true} value={input} updateSearchValue={updateInput} />
|
||||
</div>
|
||||
<ul className="list">
|
||||
<li className="user none" onClick={handleClick.bind(null, undefined)}>
|
||||
<ul className="w-full flex flex-col">
|
||||
<li className="relative cursor-pointer p-2.5 font-semibold text-sm text-gray-500" onClick={handleClick.bind(null, undefined)}>
|
||||
Anyone
|
||||
{!select && <CheckSign className="check" />}
|
||||
{!select && <CheckSign className="absolute right-1.5 top-1/2 -translate-y-1/2" />}
|
||||
</li>
|
||||
{users.map(({ uid }) => {
|
||||
return (
|
||||
<li key={uid} className="user" onClick={handleClick.bind(null, uid)}>
|
||||
<li key={uid} className="relative cursor-pointer" onClick={handleClick.bind(null, uid)}>
|
||||
<User uid={uid} interactive={true} />
|
||||
{select == uid && <CheckSign className="check" />}
|
||||
{select == uid && <CheckSign className="absolute right-1.5 top-1/2 -translate-y-1/2" />}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</Styled>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default From;
|
||||
|
||||
@@ -48,17 +48,17 @@ const Type: FC<Props> = ({ select = "", updateFilter }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-3 bg-white min-w-[100px] overflow-auto shadow-md rounded-lg flex flex-col items-start relative">
|
||||
<div className="p-3 bg-white min-w-[180px] overflow-auto shadow-md rounded-lg flex flex-col items-start relative">
|
||||
<ul className="w-full flex flex-col gap-4">
|
||||
<li className="flex justify-between" onClick={handleClick.bind(null, undefined)}>
|
||||
<li className="relative cursor-pointer flex items-center gap-4 text-gray-500 font-semibold text-sm" onClick={handleClick.bind(null, undefined)}>
|
||||
Any Type
|
||||
{!select && <CheckSign className="check" />}
|
||||
{!select && <CheckSign className="absolute right-0 top-1/2 -translate-y-1/2" />}
|
||||
</li>
|
||||
{Object.entries(FileTypes).map(([type, { title, icon }]) => {
|
||||
return (
|
||||
<li key={title} className="relative cursor-pointer flex items-center gap-2 text-sm text-gray-500 font-semibold" onClick={handleClick.bind(null, type)}>
|
||||
{icon} {title}
|
||||
{select == type && <CheckSign className="absolute right-0 left-1/2 -translate-y-1/2" />}
|
||||
{select == type && <CheckSign className="absolute right-0 top-1/2 -translate-y-1/2" />}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import Tippy from "@tippyjs/react";
|
||||
import Avatar from "../../../common/component/Avatar";
|
||||
import FilterDate, { Dates } from "./Date";
|
||||
@@ -9,41 +8,12 @@ import FilterType, { FileTypes } from "./Type";
|
||||
import ArrowDown from "../../../assets/icons/arrow.down.svg";
|
||||
import { useAppSelector } from "../../../app/store";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import clsx from "clsx";
|
||||
|
||||
const Styled = styled.div`
|
||||
/* padding: 20px 0; */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
.filter {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
border: 1px solid #d0d5dd;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
|
||||
border-radius: var(--br);
|
||||
padding: 7px 12px;
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
&.selected {
|
||||
border: none;
|
||||
color: #fff;
|
||||
background-color: #22ccee;
|
||||
.arrow path {
|
||||
stroke: #fff;
|
||||
}
|
||||
}
|
||||
.avatar {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
`;
|
||||
const getClass = (selected: boolean) => {
|
||||
|
||||
return clsx(`cursor-pointer flex items-center gap-2 border border-solid box-border shadow rounded-lg py-2 px-3 text-xs`, selected && 'text-white bg-primary-400');
|
||||
};
|
||||
export default function Filter({ filter, updateFilter }) {
|
||||
const { t } = useTranslation("file");
|
||||
const [filtersVisible, setFiltersVisible] = useState({
|
||||
@@ -79,8 +49,9 @@ export default function Filter({ filter, updateFilter }) {
|
||||
from: fromVisible
|
||||
} = filtersVisible;
|
||||
|
||||
|
||||
return (
|
||||
<Styled>
|
||||
<div className="flex items-center gap-2">
|
||||
<Tippy
|
||||
interactive
|
||||
onClickOutside={toggleFilterVisible.bind(null, { from: false })}
|
||||
@@ -89,14 +60,14 @@ export default function Filter({ filter, updateFilter }) {
|
||||
content={<FilterFrom select={filter.from} updateFilter={handleUpdateFilter} />}
|
||||
>
|
||||
<div
|
||||
className={`filter ${from && "selected"}`}
|
||||
className={getClass(from)}
|
||||
onClick={toggleFilterVisible.bind(null, { from: true })}
|
||||
>
|
||||
{from && (
|
||||
<Avatar
|
||||
width={16}
|
||||
height={16}
|
||||
className="avatar"
|
||||
className="w-4 h-4 rounded-full"
|
||||
name={userMap[from].name}
|
||||
src={userMap[from].avatar}
|
||||
/>
|
||||
@@ -115,7 +86,7 @@ export default function Filter({ filter, updateFilter }) {
|
||||
content={<FilterChannel select={filter.channel} updateFilter={handleUpdateFilter} />}
|
||||
>
|
||||
<div
|
||||
className={`filter ${channel && "selected"}`}
|
||||
className={getClass(channel)}
|
||||
onClick={toggleFilterVisible.bind(null, { channel: true })}
|
||||
>
|
||||
<span className="txt">{channel ? `In ${channelMap[channel].name}` : t("channel")}</span>
|
||||
@@ -130,7 +101,7 @@ export default function Filter({ filter, updateFilter }) {
|
||||
content={<FilterType select={filter.type} updateFilter={handleUpdateFilter} />}
|
||||
>
|
||||
<div
|
||||
className={`filter ${type && "selected"}`}
|
||||
className={getClass(type)}
|
||||
onClick={toggleFilterVisible.bind(null, { type: true })}
|
||||
>
|
||||
<span className="txt">{type ? FileTypes[type].title : t("type")}</span>
|
||||
@@ -145,13 +116,13 @@ export default function Filter({ filter, updateFilter }) {
|
||||
content={<FilterDate select={filter.date} updateFilter={handleUpdateFilter} />}
|
||||
>
|
||||
<div
|
||||
className={`filter ${date && "selected"}`}
|
||||
className={getClass(date)}
|
||||
onClick={toggleFilterVisible.bind(null, { date: true })}
|
||||
>
|
||||
<span className="txt">{date ? Dates[date].title : t("date")}</span>
|
||||
<ArrowDown className="arrow" />
|
||||
</div>
|
||||
</Tippy>
|
||||
</Styled>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,55 +1,30 @@
|
||||
import { MouseEvent } from "react";
|
||||
import styled from "styled-components";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { updateFileListView } from "../../app/slices/ui";
|
||||
import IconList from "../../assets/icons/file.list.svg";
|
||||
import IconGrid from "../../assets/icons/file.grid.svg";
|
||||
import clsx from "clsx";
|
||||
|
||||
const Styled = styled.ul`
|
||||
display: flex;
|
||||
border: 1px solid #d0d5dd;
|
||||
box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
|
||||
border-radius: 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.view {
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
&.item .item,
|
||||
&.grid .grid {
|
||||
border: 1px solid #52edff;
|
||||
box-shadow: 0 1px 2px rgba(16, 24, 40, 0.05);
|
||||
border-radius: 8px;
|
||||
svg {
|
||||
transition: all 0.2s ease;
|
||||
path {
|
||||
fill: #52edff;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default function View({ view = "item" }) {
|
||||
const getClass = (selected: boolean) => clsx(`cursor-pointer p-2 box-border flex-center`, selected && `border border-solid border-primary-400 shadow rounded-lg`);
|
||||
type Props = {
|
||||
view?: "item" | "grid"
|
||||
}
|
||||
export default function View({ view = "item" }: Props) {
|
||||
const dispatch = useDispatch();
|
||||
const handleChangeView = (evt: MouseEvent<HTMLLIElement>) => {
|
||||
const { view: clickView } = evt.currentTarget.dataset;
|
||||
if (clickView == view) return;
|
||||
dispatch(updateFileListView(view == "item" ? "grid" : "item"));
|
||||
};
|
||||
|
||||
const isGrid = view == "grid";
|
||||
return (
|
||||
<Styled className={view}>
|
||||
<li className="view item" data-view={"item"} onClick={handleChangeView}>
|
||||
<IconList />
|
||||
<ul className={`flex border border-solid shadow rounded-lg box-border`}>
|
||||
<li className={getClass(!isGrid)} data-view={"item"} onClick={handleChangeView}>
|
||||
<IconList className={`${!isGrid ? "fill-primary-400" : ""} dark:fill-white`} />
|
||||
</li>
|
||||
<li className="view grid" data-view={"grid"} onClick={handleChangeView}>
|
||||
<IconGrid />
|
||||
<li className={getClass(isGrid)} data-view={"grid"} onClick={handleChangeView}>
|
||||
<IconGrid className={`${isGrid ? "fill-primary-400" : ""} dark:fill-white`} />
|
||||
</li>
|
||||
</Styled>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ function ResourceManagement({ fileMessages }) {
|
||||
}, [view, filter]);
|
||||
|
||||
return (
|
||||
<div className="h-screen overflow-y-scroll flex flex-col items-start my-2 mr-6 rounded-2xl bg-white">
|
||||
<div className="h-screen overflow-y-scroll flex flex-col items-start my-2 mr-6 rounded-2xl bg-white dark:bg-[#384250]">
|
||||
<Search value={filter.name} updateSearchValue={handleUpdateSearch} />
|
||||
<div className="divider"></div>
|
||||
<div className="flex justify-between w-full px-4 py-5">
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
const Styled = styled.div`
|
||||
height: 100vh;
|
||||
overflow-y: scroll;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
background-color: #fff;
|
||||
margin: 8px 24px 10px 0;
|
||||
border-radius: 16px;
|
||||
.opts {
|
||||
padding: 20px 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
> .list {
|
||||
padding: 0 16px;
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
&.item {
|
||||
gap: 8px;
|
||||
flex-direction: column;
|
||||
}
|
||||
&.grid {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
> .file_box {
|
||||
flex-direction: column;
|
||||
/* margin-right: 8px; */
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default Styled;
|
||||
Reference in New Issue
Block a user