Skip to content

Commit 139000c

Browse files
committed
Add Vanilla Macros navigation and update dependencies; refactor context and components
1 parent 35ff59b commit 139000c

File tree

23 files changed

+1311
-727
lines changed

23 files changed

+1311
-727
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"test": "vitest"
1212
},
1313
"dependencies": {
14-
"@heroui/react": "2.7.2",
14+
"@heroui/react": "2.7.4",
1515
"@heroui/use-infinite-scroll": "2.2.3",
1616
"@heroui/use-theme": "2.1.2",
1717
"@tailwindcss/typography": "^0.5.16",
@@ -26,6 +26,7 @@
2626
"react-toastify": "^11.0.3",
2727
"rehype-raw": "^7.0.0",
2828
"remark-gfm": "^4.0.1",
29+
"tailwind-scrollbar": "^4.0.1",
2930
"tailwind-variants": "^0.3.1",
3031
"use-dark-mode": "^2.3.1"
3132
},

pnpm-lock.yaml

Lines changed: 661 additions & 629 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Routes/Routes.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { DownloadAddon, RoutesNotFound } from '@/components'
22
import { useSEO } from '@/hook/useSEO'
3-
import { Addons, ElvUI, Guides, Home, Notes, Post, WeakAuras } from '@/pages'
3+
import { Addons, ElvUI, Guides, Home, Notes, Post, Vmacros, WeakAuras } from '@/pages'
44
import { AnimatePresence, motion } from 'framer-motion'
55
import { Navigate, Route, Routes, useLocation } from 'react-router-dom'
66

@@ -23,6 +23,8 @@ const AppRoutes = () => {
2323
<Route path="/download/:addonName" element={<DownloadAddon />} />
2424
<Route path="/WeakAuras" element={<WeakAuras />} />
2525
<Route path="/ElvUI" element={<ElvUI />} />
26+
<Route path="/Vmacros" element={<Vmacros />} />
27+
{/* <Route path="/Vmacros/:filePath?" element={<Vmacros />} /> */}
2628
<Route path="/Guides" element={<Guides />} />
2729
<Route path="/Post/:folder" element={<Post />} />
2830
<Route path="/Notes/*" element={<Notes />} />

src/assets/Icons/BookTextIcon.tsx

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { motion, useAnimation } from 'framer-motion'
2+
import type { HTMLAttributes } from 'react'
3+
import React, { forwardRef, useCallback, useImperativeHandle, useRef } from 'react'
4+
5+
export interface BookTextIconHandle {
6+
startAnimation: () => void
7+
stopAnimation: () => void
8+
}
9+
10+
interface BookTextIconProps extends HTMLAttributes<HTMLDivElement> {
11+
size?: number
12+
}
13+
14+
const BookTextIcon = forwardRef<BookTextIconHandle, BookTextIconProps>(
15+
({ onMouseEnter, onMouseLeave, className, size = 28, ...props }, ref) => {
16+
const controls = useAnimation()
17+
const isControlledRef = useRef(false)
18+
19+
useImperativeHandle(ref, () => {
20+
isControlledRef.current = true
21+
22+
return {
23+
startAnimation: () => controls.start('animate'),
24+
stopAnimation: () => controls.start('normal')
25+
}
26+
})
27+
28+
const handleMouseEnter = useCallback(
29+
(e: React.MouseEvent<HTMLDivElement>) => {
30+
if (!isControlledRef.current) {
31+
controls.start('animate')
32+
} else {
33+
onMouseEnter?.(e)
34+
}
35+
},
36+
[controls, onMouseEnter]
37+
)
38+
39+
const handleMouseLeave = useCallback(
40+
(e: React.MouseEvent<HTMLDivElement>) => {
41+
if (!isControlledRef.current) {
42+
controls.start('normal')
43+
} else {
44+
onMouseLeave?.(e)
45+
}
46+
},
47+
[controls, onMouseLeave]
48+
)
49+
50+
return (
51+
<div
52+
className={`cursor-pointer select-none p-2 hover:bg-accent rounded-md transition-colors duration-200 flex items-center justify-center ${className}`}
53+
onMouseEnter={handleMouseEnter}
54+
onMouseLeave={handleMouseLeave}
55+
{...props}
56+
>
57+
<motion.svg
58+
animate={controls}
59+
variants={{
60+
animate: {
61+
scale: [1, 1.04, 1],
62+
rotate: [0, -8, 8, -8, 0],
63+
y: [0, -2, 0],
64+
transition: {
65+
duration: 0.6,
66+
ease: 'easeInOut',
67+
times: [0, 0.2, 0.5, 0.8, 1]
68+
}
69+
},
70+
normal: {
71+
scale: 1,
72+
rotate: 0,
73+
y: 0
74+
}
75+
}}
76+
xmlns="http://www.w3.org/2000/svg"
77+
width={size}
78+
height={size}
79+
viewBox="0 0 24 24"
80+
fill="none"
81+
stroke="currentColor"
82+
strokeWidth="2"
83+
strokeLinecap="round"
84+
strokeLinejoin="round"
85+
>
86+
<path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20" />
87+
<path d="M8 11h8" />
88+
<path d="M8 7h6" />
89+
</motion.svg>
90+
</div>
91+
)
92+
}
93+
)
94+
95+
BookTextIcon.displayName = 'BookTextIcon'
96+
97+
export { BookTextIcon }

src/assets/Icons/CircleChevronDownIcon.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
import { IconSvgProps } from '@/types'
12
import type { Transition } from 'framer-motion'
23
import { motion, useAnimation } from 'framer-motion'
34
import { FC } from 'react'
4-
import { IconSvgProps } from '@/types'
55

66
const defaultTransition: Transition = {
77
times: [0, 0.4, 1],
@@ -13,7 +13,7 @@ const CircleChevronDownIcon: FC<IconSvgProps> = ({ size = 24, width, height, ...
1313

1414
return (
1515
<div
16-
className="cursor-pointer select-none p-2 hover:bg-accent rounded-md transition-colors duration-200 flex items-center justify-center"
16+
className="cursor-pointer select-none hover:bg-accent rounded-md transition-colors duration-200 flex items-center justify-center"
1717
onMouseEnter={() => controls.start('animate')}
1818
onMouseLeave={() => controls.start('normal')}
1919
>

src/assets/Icons/MenuIcon.tsx

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import type { Variants } from 'framer-motion'
2+
import { motion, useAnimation } from 'framer-motion'
3+
import type { HTMLAttributes } from 'react'
4+
import React, { forwardRef, useCallback, useImperativeHandle, useRef } from 'react'
5+
6+
export interface MenuIconHandle {
7+
startAnimation: () => void
8+
stopAnimation: () => void
9+
}
10+
11+
interface MenuIconProps extends HTMLAttributes<HTMLDivElement> {
12+
size?: number
13+
}
14+
15+
const lineVariants: Variants = {
16+
normal: {
17+
rotate: 0,
18+
y: 0,
19+
opacity: 1
20+
},
21+
animate: (custom: number) => ({
22+
rotate: custom === 1 ? 45 : custom === 3 ? -45 : 0,
23+
y: custom === 1 ? 6 : custom === 3 ? -6 : 0,
24+
opacity: custom === 2 ? 0 : 1,
25+
transition: {
26+
type: 'spring',
27+
stiffness: 260,
28+
damping: 20
29+
}
30+
})
31+
}
32+
33+
const MenuIcon = forwardRef<MenuIconHandle, MenuIconProps>(
34+
({ onMouseEnter, onMouseLeave, className, size = 28, ...props }, ref) => {
35+
const controls = useAnimation()
36+
const isControlledRef = useRef(false)
37+
38+
useImperativeHandle(ref, () => {
39+
isControlledRef.current = true
40+
41+
return {
42+
startAnimation: () => controls.start('animate'),
43+
stopAnimation: () => controls.start('normal')
44+
}
45+
})
46+
47+
const handleMouseEnter = useCallback(
48+
(e: React.MouseEvent<HTMLDivElement>) => {
49+
if (!isControlledRef.current) {
50+
controls.start('animate')
51+
} else {
52+
onMouseEnter?.(e)
53+
}
54+
},
55+
[controls, onMouseEnter]
56+
)
57+
58+
const handleMouseLeave = useCallback(
59+
(e: React.MouseEvent<HTMLDivElement>) => {
60+
if (!isControlledRef.current) {
61+
controls.start('normal')
62+
} else {
63+
onMouseLeave?.(e)
64+
}
65+
},
66+
[controls, onMouseLeave]
67+
)
68+
return (
69+
<div
70+
className={` select-none p-2 hover:bg-accent rounded-md transition-colors duration-200 flex items-center justify-center ${className}`}
71+
onMouseEnter={handleMouseEnter}
72+
onMouseLeave={handleMouseLeave}
73+
{...props}
74+
>
75+
<svg
76+
xmlns="http://www.w3.org/2000/svg"
77+
width={size}
78+
height={size}
79+
viewBox="0 0 24 24"
80+
fill="none"
81+
stroke="currentColor"
82+
strokeWidth="2"
83+
strokeLinecap="round"
84+
strokeLinejoin="round"
85+
>
86+
<motion.line
87+
x1="4"
88+
y1="6"
89+
x2="20"
90+
y2="6"
91+
variants={lineVariants}
92+
animate={controls}
93+
custom={1}
94+
/>
95+
<motion.line
96+
x1="4"
97+
y1="12"
98+
x2="20"
99+
y2="12"
100+
variants={lineVariants}
101+
animate={controls}
102+
custom={2}
103+
/>
104+
<motion.line
105+
x1="4"
106+
y1="18"
107+
x2="20"
108+
y2="18"
109+
variants={lineVariants}
110+
animate={controls}
111+
custom={3}
112+
/>
113+
</svg>
114+
</div>
115+
)
116+
}
117+
)
118+
119+
MenuIcon.displayName = 'MenuIcon'
120+
121+
export { MenuIcon }

src/assets/Icons/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
export { BookTextIcon } from './BookTextIcon'
12
export { CircleChevronDownIcon } from './CircleChevronDownIcon'
23
export { DeleteIcon } from './DeleteIcon'
34
export { DiscordIcon } from './DiscordIcon'
45
export { DownloadIcon } from './DownloadIcon'
56
export { FlameIcon } from './FlameIcon'
67
export { GithubIcon } from './GithubIcon'
78
export { GroupIcon } from './GroupIcon'
9+
export { MenuIcon } from './MenuIcon'
810
export { MoonIcon } from './MoonIcon'
911
export { SearchIcon } from './SearchIcon'
1012
export { SettingIcon } from './SettingIcon'

src/assets/css/main.css

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,35 @@
22
@import 'tailwindcss/components';
33
@import 'tailwindcss/utilities';
44

5+
@layer utilities {
6+
.scrollbar-thin {
7+
scrollbar-width: thin;
8+
scrollbar-color: rgb(31 29 29) transparent;
9+
}
10+
11+
.scrollbar-webkit::-webkit-scrollbar {
12+
width: 8px;
13+
}
14+
15+
.scrollbar-webkit::-webkit-scrollbar-track {
16+
background: transparent;
17+
}
18+
19+
.scrollbar-webkit::-webkit-scrollbar-thumb {
20+
background-color: rgb(31 41 55);
21+
border-radius: 20px;
22+
border: 2px solid transparent;
23+
-webkit-border-radius: 20px;
24+
-moz-border-radius: 20px;
25+
-ms-border-radius: 20px;
26+
-o-border-radius: 20px;
27+
}
28+
29+
.scrollbar-webkit::-webkit-scrollbar-button {
30+
display: none;
31+
}
32+
}
33+
534
@layer base {
635
html {
736
font-size: 16px;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import hljs from 'highlight.js'
2+
import { useEffect } from 'react'
3+
import ReactMarkdown from 'react-markdown'
4+
import rehypeRaw from 'rehype-raw'
5+
import remarkGfm from 'remark-gfm'
6+
7+
const BASE_CLASSES = 'markdown-body p-1 !bg-transparent'
8+
const DEFAULT_CLASSES =
9+
'text-default-900 gap-4 w-auto p-4 mx-auto flex-col lg:flex-row rounded-md border-small border-primary-200/40 bg-background/60 shadow-medium backdrop-blur-md mb-2 dark:prose-invert prose'
10+
11+
const Markdown = ({ content, className }: { content: string; className?: string }) => {
12+
useEffect(() => {
13+
document.querySelectorAll('pre code').forEach((block) => {
14+
hljs.highlightElement(block as HTMLElement)
15+
})
16+
}, [content])
17+
18+
const markdownClasses = className ? className : DEFAULT_CLASSES
19+
20+
return (
21+
<article className={BASE_CLASSES}>
22+
<ReactMarkdown
23+
remarkPlugins={[remarkGfm]}
24+
rehypePlugins={[rehypeRaw]}
25+
className={markdownClasses}
26+
>
27+
{content}
28+
</ReactMarkdown>
29+
</article>
30+
)
31+
}
32+
33+
export default Markdown

src/components/Navbar/Macros.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { CircleChevronDownIcon } from '@/assets/Icons'
2+
import {
3+
Dropdown,
4+
DropdownItem,
5+
DropdownMenu,
6+
DropdownTrigger,
7+
Link,
8+
NavbarContent,
9+
NavbarItem
10+
} from '@heroui/react'
11+
12+
export default function Macros({ items }: { items: { label: string; href: string }[] }) {
13+
return (
14+
<NavbarContent className="hidden sm:flex" justify="center">
15+
<Dropdown className="bg-inputs mt-3">
16+
<NavbarItem>
17+
<DropdownTrigger>
18+
<Link
19+
showAnchorIcon
20+
href="#"
21+
color="foreground"
22+
anchorIcon={<CircleChevronDownIcon className="w-4 h-4 ml-1" />}
23+
>
24+
Macros
25+
</Link>
26+
</DropdownTrigger>
27+
</NavbarItem>
28+
<DropdownMenu aria-label="Macros" className="w-auto">
29+
{items.map((item, index) => (
30+
<DropdownItem
31+
key={index}
32+
description={`${item.label} variety `}
33+
href={item.href}
34+
>
35+
{item.label}
36+
</DropdownItem>
37+
))}
38+
</DropdownMenu>
39+
</Dropdown>
40+
</NavbarContent>
41+
)
42+
}

0 commit comments

Comments
 (0)