chore: 提示面板封装

This commit is contained in:
streakingman 2022-10-09 23:11:58 +08:00
parent 557a6a705a
commit 84fa8483d9
7 changed files with 155 additions and 102 deletions

View File

@ -9,4 +9,7 @@ module.exports = {
'stylelint-config-standard-scss', 'stylelint-config-standard-scss',
'stylelint-config-prettier-scss', 'stylelint-config-prettier-scss',
], ],
rules: {
'selector-class-pattern': '^[a-z][a-zA-Z0-9]+$',
},
}; };

View File

@ -0,0 +1,63 @@
.panel {
position: fixed;
width: 36px;
height: 36px;
border-radius: 18px;
transition: 0.3s;
padding: 16px;
background-color: rgb(0 0 0/ 50%);
color: white;
overflow: hidden;
backdrop-filter: blur(8px);
box-sizing: border-box;
cursor: pointer;
font-size: 14px;
> * {
opacity: 0;
}
&.leftBottom {
left: 8px;
bottom: 8px;
}
.closeBtn {
position: absolute;
border-radius: 8px;
background-color: rgb(0 0 0/20%);
width: 36px;
height: 36px;
right: 0;
top: 0;
display: flex;
align-items: center;
justify-content: center;
transform: scale(0);
color: white;
cursor: pointer;
user-select: none;
}
&.open {
height: 100px;
border-radius: 8px;
cursor: default;
z-index: 5 !important;
@media screen and (max-width: 500px) {
width: calc(100% - 16px);
}
@media screen and (min-width: 501px) {
width: 500px;
}
> * {
opacity: 1;
}
.closeBtn {
transform: scale(1);
}
}
}

View File

@ -0,0 +1,48 @@
import React, { FC, ReactNode, useState } from 'react';
import style from './FixedAnimateScalePanel.module.scss';
import classNames from 'classnames';
export const FixedAnimateScalePanel: FC<{
children: ReactNode;
className?: string;
openClassName?: string;
closeClassName?: string;
initOpen?: boolean;
}> = ({
children,
className,
openClassName,
closeClassName,
initOpen = false,
}) => {
const [open, setOpen] = useState<boolean>(initOpen);
return (
<div
onClick={() => !open && setOpen(true)}
className={classNames(
style.panel,
open && style.open,
className,
open ? openClassName : closeClassName
)}
>
{children}
<div className={style.closeBtn} onClick={() => setOpen(false)}>
<svg
width="13"
height="14"
viewBox="0 0 13 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.9498 7.04945L0 11.9993L1.41421 13.4135L6.36401 8.46367L11.3138 13.4135L12.728 11.9993L7.77823 7.04945L12.7279 2.09976L11.3137 0.685547L6.36401 5.63524L1.41432 0.685547L0.0001055 2.09976L4.9498 7.04945Z"
fill="#888888"
/>
</svg>
</div>
</div>
);
};

View File

@ -1,24 +1,9 @@
/* 可封装 */
.info { .info {
position: fixed;
left: 8px; left: 8px;
bottom: 8px; bottom: 8px;
transition: 0.3s;
padding: 16px;
width: 36px;
height: 36px;
border-radius: 18px;
background: rgb(0 0 0/ 50%);
color: white;
overflow: hidden;
backdrop-filter: blur(8px);
box-sizing: border-box;
cursor: pointer;
font-size: 14px;
p { p {
margin: 0; margin: 0;
opacity: 0;
transition: 0.6s; transition: 0.6s;
} }
@ -33,42 +18,13 @@
font-size: 24px; font-size: 24px;
font-weight: 900; font-weight: 900;
transition: 0.2s; transition: 0.2s;
} opacity: 1;
.close {
position: absolute;
border-radius: 8px;
background-color: rgb(0 0 0/20%);
width: 36px;
height: 36px;
right: 0;
top: 0;
line-height: 36px;
text-align: center;
transform: scale(0);
color: white;
cursor: pointer;
user-select: none;
} }
&.open { &.open {
height: 100px;
border-radius: 8px;
@media screen and (max-width: 500px) { @media screen and (max-width: 500px) {
width: calc(100% - 70px); width: calc(100% - 70px);
} }
@media screen and (min-width: 501px) {
width: 500px;
}
p {
opacity: 1;
}
.close {
transform: scale(1);
}
.icon { .icon {
transform: scale(0); transform: scale(0);

View File

@ -1,12 +1,11 @@
import React, { CSSProperties, FC, useState } from 'react'; import React, { FC } from 'react';
import style from './Info.module.scss'; import style from './Info.module.scss';
import classNames from 'classnames'; import { FixedAnimateScalePanel } from './FixedAnimateScalePanel';
export const Info: FC = () => { export const Info: FC = () => {
const [open, setOpen] = useState(false);
return ( return (
<div <FixedAnimateScalePanel
onClick={() => !open && setOpen(true)} className={style.info}
className={classNames(style.info, open && style.open)} openClassName={style.open}
> >
<div className={style.icon}>i</div> <div className={style.icon}>i</div>
<p> <p>
@ -16,11 +15,27 @@ export const Info: FC = () => {
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
> >
DISCO DISCO
</a>
<a
href="https://music.163.com/#/song?id=135022"
target="_blank"
rel="noreferrer"
>
</a>
<a
href="https://y.qq.com/n/ryqq/songDetail/0020Nusb3QJGn9"
target="_blank"
rel="noreferrer"
>
</a> </a>
</p> </p>
<p> <p>
-{'>'}-{'>'}
<a <a
href="https://play.google.com/store/apps/details?id=tile.master.connect.matching.game" href="https://play.google.com/store/apps/details?id=tile.master.connect.matching.game"
target="_blank" target="_blank"
@ -28,11 +43,16 @@ export const Info: FC = () => {
> >
3 Tiles 3 Tiles
</a> </a>
-{'>'}
<a
href="https://www.bilibili.com/video/BV1zT411N7RT"
target="_blank"
rel="noreferrer"
>
</a>
</p> </p>
<p></p> <p></p>
<div className={style.close} onClick={() => setOpen(false)}> </FixedAnimateScalePanel>
X
</div>
</div>
); );
}; };

View File

@ -12,14 +12,9 @@
} }
} }
.info { .personalInfo {
position: fixed;
right: 8px; right: 8px;
top: 8px; top: 8px;
padding: 4px;
width: 36px;
height: 36px;
border-radius: 18px;
animation: gradient 4s ease infinite; animation: gradient 4s ease infinite;
background-image: linear-gradient( background-image: linear-gradient(
-45deg, -45deg,
@ -30,12 +25,8 @@
); );
background-size: 400% 400%; background-size: 400% 400%;
background-position: 0 0; background-position: 0 0;
box-sizing: border-box;
transition: 0.4s; transition: 0.4s;
backdrop-filter: blur(8px);
z-index: 9; z-index: 9;
overflow: hidden;
color: white;
* { * {
transition: 0.6s; transition: 0.6s;
@ -47,28 +38,13 @@
font-weight: 900; font-weight: 900;
} }
.close {
position: absolute;
border-radius: 8px;
background-color: rgb(0 0 0/20%);
width: 36px;
height: 36px;
right: 0;
top: 0;
line-height: 36px;
text-align: center;
transform: scale(0);
color: white;
cursor: pointer;
user-select: none;
}
.github { .github {
&Icon { &Icon {
position: absolute; position: absolute;
right: 6px; right: 6px;
top: 6px; top: 6px;
cursor: pointer; cursor: pointer;
opacity: 1 !important;
} }
&Link { &Link {
@ -93,18 +69,8 @@
} }
&.open { &.open {
height: 100px;
border-radius: 8px;
@media screen and (max-width: 500px) { @media screen and (max-width: 500px) {
width: calc(100% - 16px); width: calc(100% - 60px) !important;
}
@media screen and (min-width: 501px) {
width: 500px;
}
.close {
transform: scale(1);
} }
.github { .github {

View File

@ -1,6 +1,7 @@
import React, { FC, useState } from 'react'; import React, { FC, useState } from 'react';
import style from './PersonalInfo.module.scss'; import style from './PersonalInfo.module.scss';
import classNames from 'classnames'; import classNames from 'classnames';
import { FixedAnimateScalePanel } from './FixedAnimateScalePanel';
const GithubIcon: FC = () => { const GithubIcon: FC = () => {
return ( return (
@ -63,19 +64,15 @@ export const BiliBiliLink: FC = () => {
}; };
export const PersonalInfo: FC = () => { export const PersonalInfo: FC = () => {
const [open, setOpen] = useState(false);
return ( return (
<div <FixedAnimateScalePanel
onClick={() => !open && setOpen(true)} className={style.personalInfo}
className={classNames(style.info, open && style.open)} openClassName={style.open}
> >
<GithubIcon /> <GithubIcon />
<GithubLink /> <GithubLink />
<BiliBiliIcon /> <BiliBiliIcon />
<BiliBiliLink /> <BiliBiliLink />
<div className={style.close} onClick={() => setOpen(false)}> </FixedAnimateScalePanel>
X
</div>
</div>
); );
}; };