added MoreSection component to profile page
This commit is contained in:
@@ -105,7 +105,7 @@
|
|||||||
--accent-hover: #9dacff;
|
--accent-hover: #9dacff;
|
||||||
--accent-strong: #7088ff;
|
--accent-strong: #7088ff;
|
||||||
--accent-bg: rgba(138, 157, 255, 0.08);
|
--accent-bg: rgba(138, 157, 255, 0.08);
|
||||||
--accent-bg-hover: rgba(138, 157, 255, 0.14);
|
--accent-bg-hover: rgba(249, 250, 255, 0.554);
|
||||||
|
|
||||||
/* Semantic */
|
/* Semantic */
|
||||||
--success: #5ec98f;
|
--success: #5ec98f;
|
||||||
@@ -159,3 +159,15 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes wiggle {
|
||||||
|
0%, 100% { transform: rotate(0deg); }
|
||||||
|
15% { transform: rotate(-1deg); }
|
||||||
|
30% { transform: rotate(1deg); }
|
||||||
|
45% { transform: rotate(-1deg); }
|
||||||
|
60% { transform: rotate(1deg); }
|
||||||
|
75% { transform: rotate(-1deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiggle {
|
||||||
|
animation: wiggle 0.4s ease-in-out infinite;
|
||||||
|
}
|
||||||
44
components/Links.tsx
Normal file
44
components/Links.tsx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { PROFILE } from "@/data/content";
|
||||||
|
import LinkIcon from "./LinkIcon";
|
||||||
|
import { useStaggerReveal } from "@/hooks/useAnimations";
|
||||||
|
|
||||||
|
export default function Links() {
|
||||||
|
const [hovered, setHovered] = useState<number | null>(null);
|
||||||
|
const visible = useStaggerReveal(PROFILE.links.length + PROFILE.contactMethods.length, 50);
|
||||||
|
return (
|
||||||
|
<div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
|
||||||
|
{PROFILE.links.map((link, i) => (
|
||||||
|
<a key={link.label}
|
||||||
|
href={link.url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
onMouseEnter={() => setHovered(i)}
|
||||||
|
onMouseLeave={() => setHovered(null)}
|
||||||
|
style={{
|
||||||
|
display: "inline-flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: 8,
|
||||||
|
padding: "10px 18px",
|
||||||
|
fontFamily: "var(--mono)",
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: 500,
|
||||||
|
color: hovered === i ? "var(--accent)" : "var(--fg-secondary)",
|
||||||
|
background: hovered === i ? "var(--accent-bg)" : "var(--surface)",
|
||||||
|
border: `1px solid ${hovered === i ? "var(--accent)" : "var(--border)"}`,
|
||||||
|
borderRadius: 6,
|
||||||
|
textDecoration: "none",
|
||||||
|
transition: "all var(--duration-slow)",
|
||||||
|
transform: hovered === i ? "translateY(-2px)" : "none",
|
||||||
|
opacity: visible.has(i) ? 1.0 : 0
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LinkIcon type={link.icon} />
|
||||||
|
{link.label}
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState } from "react";
|
|
||||||
import { PROFILE } from "@/data/content";
|
import { PROFILE } from "@/data/content";
|
||||||
import LinkIcon from "./LinkIcon";
|
|
||||||
import ContactMethods from "./ContactMethods";
|
import ContactMethods from "./ContactMethods";
|
||||||
import { useStaggerReveal } from "@/hooks/useAnimations";
|
import { useStaggerReveal } from "@/hooks/useAnimations";
|
||||||
|
import Links from "./Links";
|
||||||
|
import ProfileMore from "./ProfileMore";
|
||||||
|
|
||||||
export default function Profile() {
|
export default function Profile() {
|
||||||
const [hovered, setHovered] = useState<number | null>(null);
|
|
||||||
const visible = useStaggerReveal(PROFILE.links.length + PROFILE.contactMethods.length, 100);
|
const visible = useStaggerReveal(PROFILE.links.length + PROFILE.contactMethods.length, 100);
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: "48px 0", maxWidth: 640 }}>
|
<div style={{ padding: "48px 0", maxWidth: 640 }}>
|
||||||
@@ -59,37 +58,8 @@ export default function Profile() {
|
|||||||
>
|
>
|
||||||
{PROFILE.bio}
|
{PROFILE.bio}
|
||||||
</p>
|
</p>
|
||||||
<div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
|
<ProfileMore/>
|
||||||
{PROFILE.links.map((link, i) => (
|
<Links/>
|
||||||
<a key={link.label}
|
|
||||||
href={link.url}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
onMouseEnter={() => setHovered(i)}
|
|
||||||
onMouseLeave={() => setHovered(null)}
|
|
||||||
style={{
|
|
||||||
display: "inline-flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: 8,
|
|
||||||
padding: "10px 18px",
|
|
||||||
fontFamily: "var(--mono)",
|
|
||||||
fontSize: 13,
|
|
||||||
fontWeight: 500,
|
|
||||||
color: hovered === i ? "var(--accent)" : "var(--fg-secondary)",
|
|
||||||
background: hovered === i ? "var(--accent-bg)" : "var(--surface)",
|
|
||||||
border: `1px solid ${hovered === i ? "var(--accent)" : "var(--border)"}`,
|
|
||||||
borderRadius: 6,
|
|
||||||
textDecoration: "none",
|
|
||||||
transition: "all var(--duration-slow)",
|
|
||||||
transform: hovered === i ? "translateY(-2px)" : "none",
|
|
||||||
opacity: visible.has(i) ? 1.0 : 0
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<LinkIcon type={link.icon} />
|
|
||||||
{link.label}
|
|
||||||
</a>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<ContactMethods methods={PROFILE.contactMethods} visibleCount={PROFILE.links.length} visibleComponent={visible} isVisible={visible.has(PROFILE.links.length-1)} />
|
<ContactMethods methods={PROFILE.contactMethods} visibleCount={PROFILE.links.length} visibleComponent={visible} isVisible={visible.has(PROFILE.links.length-1)} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
114
components/ProfileMore.tsx
Normal file
114
components/ProfileMore.tsx
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { MoreSection, PROFILE } from "@/data/content";
|
||||||
|
import { useStaggerReveal, useWiggle } from "@/hooks/useAnimations";
|
||||||
|
import "@/styles/more-section.css"
|
||||||
|
|
||||||
|
export default function ProfileMore() {
|
||||||
|
const [delayTimer, setDelayTimer] = useState<number | null>(null);
|
||||||
|
const [hovered, setHovered] = useState<boolean | null>(null);
|
||||||
|
const [morePosition, setMorePosition] = useState<number>(PROFILE.moreSectionsStart ?? 0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const { wiggling, progress, handlers } = useWiggle(500, () => {});
|
||||||
|
|
||||||
|
function handleSectionExpand(){
|
||||||
|
setMorePosition(morePosition + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="more-section-container"
|
||||||
|
style={{
|
||||||
|
minHeight: "100px",
|
||||||
|
width: "100%",
|
||||||
|
overflow: "hidden"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{PROFILE.moreSections.map((item: MoreSection, i)=>{
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
style={{
|
||||||
|
// display: i < morePosition ? "block" : "none",
|
||||||
|
opacity: i < morePosition ? 1.0 : 0.0,
|
||||||
|
transition: "all 0.3s ease",
|
||||||
|
overflow: "hidden",
|
||||||
|
minHeight: i < morePosition ? "5em" : "0em",
|
||||||
|
height: i < morePosition ? "auto" : "0",
|
||||||
|
}}>
|
||||||
|
{item.title && (<h3
|
||||||
|
style={{
|
||||||
|
marginBottom: 8,
|
||||||
|
fontFamily: "var(--mono)",
|
||||||
|
fontSize: 11,
|
||||||
|
color: "var(--muted)",
|
||||||
|
letterSpacing: "0.08em",
|
||||||
|
textTransform: "uppercase",
|
||||||
|
}}>
|
||||||
|
{item.title}
|
||||||
|
</h3>)}
|
||||||
|
<p style={{
|
||||||
|
fontFamily: "var(--sans)",
|
||||||
|
fontSize: 16,
|
||||||
|
lineHeight: 1.7,
|
||||||
|
color: "var(--fg-secondary)",
|
||||||
|
margin: "0 0 40px 0",
|
||||||
|
maxWidth: 560,
|
||||||
|
}}>{item.text}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
<div {...handlers} className={`drop-handle ${wiggling ? "wiggle" : ""}`}
|
||||||
|
onMouseEnter={() => {
|
||||||
|
if (delayTimer) return;
|
||||||
|
setHovered(true);
|
||||||
|
|
||||||
|
let timer = window.setTimeout(() => {
|
||||||
|
handleSectionExpand();
|
||||||
|
}, 500);
|
||||||
|
setDelayTimer(timer);
|
||||||
|
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => {
|
||||||
|
if (delayTimer){
|
||||||
|
clearTimeout(delayTimer);
|
||||||
|
setDelayTimer(null);
|
||||||
|
}
|
||||||
|
setHovered(false);
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: morePosition < PROFILE.moreSections.length ? 1.0 : 0.0,
|
||||||
|
backgroundColor: hovered ? "var(--surface)" : "var(--bg-raised",
|
||||||
|
width: "100%",
|
||||||
|
height: "2em",
|
||||||
|
display: "flex",
|
||||||
|
gap: 12,
|
||||||
|
margin: "0 0 40px 0",
|
||||||
|
border: `1px solid ${hovered ? "var(--accent)" : "var(--border)"}`,
|
||||||
|
bottom: hovered ? "-10px" : "0px",
|
||||||
|
position: "relative",
|
||||||
|
}}>
|
||||||
|
|
||||||
|
<svg height={"30px"} width={"30px"} fill="var(--fg-secondary)" version="1.1" id="Capa_1" style={{scale:"0.5"}} >
|
||||||
|
<g>
|
||||||
|
<path d="M29.994,10.183L15.363,24.812L0.733,10.184c-0.977-0.978-0.977-2.561,0-3.536c0.977-0.977,2.559-0.976,3.536,0
|
||||||
|
l11.095,11.093L26.461,6.647c0.977-0.976,2.559-0.976,3.535,0C30.971,7.624,30.971,9.206,29.994,10.183z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<span style={{
|
||||||
|
fontFamily: "var(--sans)",
|
||||||
|
fontSize: 12,
|
||||||
|
lineHeight: 0.5,
|
||||||
|
color: "var(--fg-secondary)",
|
||||||
|
alignSelf: "center",
|
||||||
|
textTransform: "uppercase"
|
||||||
|
}}>more?</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -65,18 +65,12 @@ export default function SimpleGallery({
|
|||||||
}}
|
}}
|
||||||
onClick={handleEnlarge}
|
onClick={handleEnlarge}
|
||||||
title="Enlarge image"
|
title="Enlarge image"
|
||||||
onMouseEnter={(e) =>
|
|
||||||
(e.currentTarget.style.background = "rgba(0,0,0,0.8)")
|
|
||||||
}
|
|
||||||
onMouseLeave={(e) =>
|
|
||||||
(e.currentTarget.style.background = "rgba(0,0,0,0.55)")
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg className="action-button-svg" stroke="current" width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M1 5V1H5" stroke="white" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
<path d="M1 5V1H5" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
<path d="M13 9V13H9" stroke="white" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
<path d="M13 9V13H9" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
<path d="M1 1L5.5 5.5" stroke="white" strokeWidth="1.5" strokeLinecap="round" />
|
<path d="M1 1L5.5 5.5" strokeWidth="1.5" strokeLinecap="round" />
|
||||||
<path d="M13 13L8.5 8.5" stroke="white" strokeWidth="1.5" strokeLinecap="round" />
|
<path d="M13 13L8.5 8.5" strokeWidth="1.5" strokeLinecap="round" />
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
@@ -91,13 +85,7 @@ export default function SimpleGallery({
|
|||||||
right: 8
|
right: 8
|
||||||
}}
|
}}
|
||||||
onClick={handleShrink}
|
onClick={handleShrink}
|
||||||
title="Shrink image"
|
title="Shrink image"
|
||||||
onMouseEnter={(e) =>
|
|
||||||
(e.currentTarget.style.background = "rgba(0,0,0,0.8)")
|
|
||||||
}
|
|
||||||
onMouseLeave={(e) =>
|
|
||||||
(e.currentTarget.style.background = "rgba(0,0,0,0.55)")
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<svg viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg" width="14" height="14">
|
<svg viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg" width="14" height="14">
|
||||||
<line x1="15" y1="15" x2="45" y2="45" stroke="white" strokeWidth="6" strokeLinecap="round" />
|
<line x1="15" y1="15" x2="45" y2="45" stroke="white" strokeWidth="6" strokeLinecap="round" />
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
|
||||||
|
export type MoreSection = {
|
||||||
|
title?: string;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
export type SocialLink = {
|
export type SocialLink = {
|
||||||
label: string;
|
label: string;
|
||||||
url: string;
|
url: string;
|
||||||
@@ -5,9 +11,9 @@ export type SocialLink = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type ContactMethod = {
|
export type ContactMethod = {
|
||||||
masked: boolean,
|
masked: boolean;
|
||||||
label: string,
|
label: string;
|
||||||
icon: string
|
icon: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Project = {
|
export type Project = {
|
||||||
@@ -28,7 +34,39 @@ export const PROFILE = {
|
|||||||
name: "Hunter W",
|
name: "Hunter W",
|
||||||
title: "Software Engineer",
|
title: "Software Engineer",
|
||||||
email: "contact@hwilliams.dev",
|
email: "contact@hwilliams.dev",
|
||||||
bio: "I build user experiences before I write code. Experience with full-stack development across a variety of frameworks and languages including Vue, React, Next.JS, Nuxt, Node.JS, Express, Flask, FastAPI, Gunicorn, and more.",
|
bio: `I build user experiences before I write code.
|
||||||
|
Experience with full-stack development across a variety of frameworks and languages including Vue,
|
||||||
|
React, Next.JS, Nuxt, Node.JS, Express, Flask, FastAPI, Gunicorn, and more.`,
|
||||||
|
moreSections: [
|
||||||
|
{
|
||||||
|
title:"A little more about me",
|
||||||
|
text: `I graduated with a B.S. in Computer Science from Georgia Southern University in May 2025.
|
||||||
|
I have been working with AWS building analytics and monitoring dashboards with a sprinkle of prompt
|
||||||
|
engineering on major production projects.`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "I make mods for video games such as Space Engineers and Rimworld in my free time."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title:"My goals",
|
||||||
|
text: `User experience. \n \n Nothing makes me happier than seeing someone excited to use the software I make, and the way that happens is by practicing
|
||||||
|
development techniques that make a good user experience. I especially enjoy peeling back the layers of old systems to explore how an existing
|
||||||
|
user experience can be improved. I love the words 'Wow, it used to be difficult to do this!'.
|
||||||
|
`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title:"My dreams",
|
||||||
|
text: `Stop me if you've heard this one before: I left college with a burning passion for machine learning and artificial intelligence. It's still there, and despite
|
||||||
|
the trouble going on in the world right now I see a bright future for how these incredibly advanced statistical models can still be applied in new ways.
|
||||||
|
\n
|
||||||
|
`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title:"Wow, you're still here?",
|
||||||
|
text: `I appreciate you, but I am totally out of things to talk about.`
|
||||||
|
}
|
||||||
|
] satisfies MoreSection[],
|
||||||
|
moreSectionsStart: 1,
|
||||||
links: [
|
links: [
|
||||||
{ label: "GitHub", url: "https://github.com/FerrenF", icon: "gh" },
|
{ label: "GitHub", url: "https://github.com/FerrenF", icon: "gh" },
|
||||||
{ label: "LinkedIn", url: "https://www.linkedin.com/in/hwilliamsf/", icon: "li" }
|
{ label: "LinkedIn", url: "https://www.linkedin.com/in/hwilliamsf/", icon: "li" }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect, useRef, useCallback } from "react";
|
||||||
|
|
||||||
export function useStaggerReveal(count: number, baseDelay = 80) {
|
export function useStaggerReveal(count: number, baseDelay = 80) {
|
||||||
const [visible, setVisible] = useState<Set<number>>(new Set());
|
const [visible, setVisible] = useState<Set<number>>(new Set());
|
||||||
@@ -31,3 +31,63 @@ export function useMountTransition(delay = 50) {
|
|||||||
|
|
||||||
return mounted;
|
return mounted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function useWiggle(durationMs = 1500, onComplete: () => void) {
|
||||||
|
const [wiggling, setWiggling] = useState(false);
|
||||||
|
const [progress, setProgress] = useState(0);
|
||||||
|
|
||||||
|
const startTime = useRef<number>(0);
|
||||||
|
const rafId = useRef<number>(0);
|
||||||
|
const completeTimer = useRef<ReturnType<typeof setTimeout>>(null);
|
||||||
|
const completedRef = useRef(false);
|
||||||
|
|
||||||
|
const stop = useCallback(() => {
|
||||||
|
setWiggling(false);
|
||||||
|
setProgress(0);
|
||||||
|
cancelAnimationFrame(rafId.current);
|
||||||
|
if (completeTimer.current) clearTimeout(completeTimer.current);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const tick = useCallback(() => {
|
||||||
|
const elapsed = Date.now() - startTime.current;
|
||||||
|
const p = Math.min(1, elapsed / durationMs);
|
||||||
|
setProgress(p);
|
||||||
|
if (p < 1) {
|
||||||
|
rafId.current = requestAnimationFrame(tick);
|
||||||
|
}
|
||||||
|
}, [durationMs]);
|
||||||
|
|
||||||
|
const start = useCallback(() => {
|
||||||
|
completedRef.current = false;
|
||||||
|
startTime.current = Date.now();
|
||||||
|
setWiggling(true);
|
||||||
|
setProgress(0);
|
||||||
|
rafId.current = requestAnimationFrame(tick);
|
||||||
|
|
||||||
|
completeTimer.current = setTimeout(() => {
|
||||||
|
completedRef.current = true;
|
||||||
|
stop();
|
||||||
|
onComplete();
|
||||||
|
}, durationMs);
|
||||||
|
}, [durationMs, onComplete, tick, stop]);
|
||||||
|
|
||||||
|
const release = useCallback(() => {
|
||||||
|
if (!completedRef.current) stop();
|
||||||
|
}, [stop]);
|
||||||
|
|
||||||
|
// cleanup on unmount
|
||||||
|
useEffect(() => () => {
|
||||||
|
cancelAnimationFrame(rafId.current);
|
||||||
|
if (completeTimer.current) clearTimeout(completeTimer.current);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handlers = {
|
||||||
|
onPointerDown: start,
|
||||||
|
onPointerEnter: start,
|
||||||
|
onPointerUp: release,
|
||||||
|
onPointerLeave: release,
|
||||||
|
};
|
||||||
|
|
||||||
|
return { wiggling, progress, handlers };
|
||||||
|
}
|
||||||
@@ -7,18 +7,27 @@
|
|||||||
height: 28;
|
height: 28;
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
border: 1px solid var(--accent);
|
border: 1px solid var(--accent);
|
||||||
background: var(--accent-bg);
|
background: var(--surface);
|
||||||
color: #fff;
|
color: var(--fg);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
backdrop-filter: blur(4px);
|
|
||||||
z-index: 1001;
|
z-index: 1001;
|
||||||
transition: background 0.15s ease, border-color 0.15s ease;
|
transition: background 0.15s ease, border-color 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gallery-action-button:hover {
|
||||||
|
background: var(---surface-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button-svg {
|
||||||
|
stroke: var(--fg-secondary);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.project-card {
|
.project-card {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
21
styles/more-section.css
Normal file
21
styles/more-section.css
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
.more-section-container {
|
||||||
|
|
||||||
|
}
|
||||||
|
.drop-handle {
|
||||||
|
width: 100%;
|
||||||
|
height: 2em;
|
||||||
|
display: flex;
|
||||||
|
gap: 12;
|
||||||
|
margin: 0 0 40px 0;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
align-content: center;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
bottom: 0px;
|
||||||
|
background-color: var(--bg-raised);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user