mirror of
https://github.com/DefectingCat/DefectingCat.github.io
synced 2025-07-16 01:01:38 +00:00
Add new post
add new code sandbox component
This commit is contained in:
@ -1,14 +1,11 @@
|
||||
import classNames from 'classnames';
|
||||
import useMounted from 'lib/hooks/useMounted';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FiMoon, FiSun } from 'react-icons/fi';
|
||||
|
||||
const DarkModeBtn = () => {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const { mounted } = useMounted();
|
||||
const { systemTheme, theme, setTheme } = useTheme();
|
||||
// When mounted on client, now we can show the UI
|
||||
useEffect(() => setMounted(true), []);
|
||||
|
||||
const currentTheme = theme === 'system' ? systemTheme : theme;
|
||||
|
||||
if (!mounted)
|
||||
|
72
components/RUA/RUACodeSandbox.tsx
Normal file
72
components/RUA/RUACodeSandbox.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import classNames from 'classnames';
|
||||
import useInView from 'lib/hooks/useInView';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import RUALoading from './loading/RUALoading';
|
||||
|
||||
const partten =
|
||||
/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;
|
||||
const commonClass = classNames(
|
||||
'rounded-lg h-[500px] border-0',
|
||||
'overflow-hidden w-full'
|
||||
);
|
||||
|
||||
type Props = {
|
||||
url: string;
|
||||
};
|
||||
|
||||
const RUACodeSandbox = ({ url }: Props) => {
|
||||
const isUrl = partten.test(url);
|
||||
const { systemTheme, theme } = useTheme();
|
||||
const currentTheme = theme === 'system' ? systemTheme : theme ?? 'light';
|
||||
|
||||
const { ref, inView } = useInView();
|
||||
const sandUrl = new URL(url);
|
||||
const embed = sandUrl.pathname.split('/')[2];
|
||||
const [src, setSrc] = useState('');
|
||||
useEffect(() => {
|
||||
inView &&
|
||||
setSrc(
|
||||
`https://codesandbox.io/embed/${embed}?fontsize=14&hidenavigation=1&theme=${currentTheme}&view=preview`
|
||||
);
|
||||
}, [currentTheme, embed, inView]);
|
||||
|
||||
const [load, setLoad] = useState(false);
|
||||
const handleLoad = useCallback(() => {
|
||||
setLoad(true);
|
||||
}, []);
|
||||
|
||||
if (!isUrl) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classNames(commonClass, 'relative')}>
|
||||
<div
|
||||
className={classNames(
|
||||
commonClass,
|
||||
'absolute flex items-center justify-center',
|
||||
load && 'hidden',
|
||||
'transition-all z-10'
|
||||
)}
|
||||
>
|
||||
<RUALoading />
|
||||
</div>
|
||||
|
||||
<iframe
|
||||
ref={ref}
|
||||
src={src}
|
||||
className={classNames(
|
||||
commonClass,
|
||||
!load && 'blur-sm',
|
||||
'transition-all'
|
||||
)}
|
||||
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
|
||||
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
|
||||
onLoad={handleLoad}
|
||||
></iframe>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default RUACodeSandbox;
|
@ -1,3 +0,0 @@
|
||||
.head:hover:before {
|
||||
content: unset !important;
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
import { getHeadings } from 'lib/utils';
|
||||
import Anchor from 'components/mdx/Anchor';
|
||||
import styles from './PostTOC.module.css';
|
||||
import classNames from 'classnames';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { FiChevronDown } from 'react-icons/fi';
|
||||
|
||||
interface Props {
|
||||
headings: ReturnType<typeof getHeadings>;
|
||||
}
|
||||
|
||||
const PostTOC = ({ headings }: Props) => {
|
||||
const [show, setShow] = useState(false);
|
||||
const handleClick = useCallback(() => setShow((show) => !show), []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={classNames(
|
||||
'rounded-lg transition-all',
|
||||
'duration-500 overflow-hidden',
|
||||
'my-4'
|
||||
)}
|
||||
style={{
|
||||
maxHeight: show ? (headings?.length ?? 0) * 50 + 70 : 70,
|
||||
}}
|
||||
>
|
||||
<h2
|
||||
className={classNames(
|
||||
styles.head,
|
||||
'bg-white !m-[unset] p-4',
|
||||
'rounded-lg border border-gray-300',
|
||||
'dark:bg-rua-gray-800 dark:border-rua-gray-600',
|
||||
'select-none cursor-pointer',
|
||||
'flex justify-between items-center',
|
||||
'!text-2xl'
|
||||
)}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<span>What's inside?</span>
|
||||
|
||||
<FiChevronDown
|
||||
className={classNames(
|
||||
show && 'rotate-180',
|
||||
'transition-all duration-500'
|
||||
)}
|
||||
/>
|
||||
</h2>
|
||||
|
||||
<ul className="pl-4 border-l-4 border-gray-300 toc">
|
||||
{headings?.map((h) => (
|
||||
<li key={h.link}>
|
||||
<Anchor href={h.link} external={false}>
|
||||
{h.text}
|
||||
</Anchor>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PostTOC;
|
@ -1,9 +1,9 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import useMounted from 'lib/hooks/useMounted';
|
||||
import { useEffect } from 'react';
|
||||
import tocbot from 'tocbot';
|
||||
|
||||
const SlideToc = () => {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
useEffect(() => setMounted(true), []);
|
||||
const { mounted } = useMounted();
|
||||
|
||||
useEffect(() => {
|
||||
// Waiting the right time.
|
||||
|
Reference in New Issue
Block a user