mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
custom scroller for loadout
This commit is contained in:
1 parent
0b740e3f60
commit
3131217600
6 files changed
+128
-62
No files matched your search
@@ -1,4 +1,6 @@
|
|||||||
.scroller {
|
.scroller {
|
||||||
|
--scroller-curtain-color: var(--gray-1);
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--space-3);
|
gap: var(--space-3);
|
||||||
@@ -25,24 +27,74 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.curtain {
|
&[data-orientation="horizontal"] {
|
||||||
width: min(25%, var(--space-7));
|
.curtain {
|
||||||
height: calc(100% - var(--space-3) - 2 * var(--space-1));
|
width: min(25%, var(--space-7));
|
||||||
|
height: calc(100% - var(--space-3) - 2 * var(--space-1));
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
||||||
opacity: 0;
|
&[data-side="start"] {
|
||||||
pointer-events: none;
|
left: 0;
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
var(--scroller-curtain-color),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
&[data-side="left"] {
|
&[data-side="end"] {
|
||||||
left: 0;
|
right: 0;
|
||||||
background: linear-gradient(90deg, var(--gray-1), transparent);
|
background: linear-gradient(
|
||||||
}
|
90deg,
|
||||||
|
transparent,
|
||||||
&[data-side="right"] {
|
var(--scroller-curtain-color)
|
||||||
right: 0;
|
);
|
||||||
background: linear-gradient(90deg, transparent, var(--gray-1));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&[data-orientation="vertical"] {
|
||||||
|
min-height: 0;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-height: 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.curtain {
|
||||||
|
width: calc(100% - var(--space-3) - 2 * var(--space-1));
|
||||||
|
height: min(25%, var(--space-7));
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
&[data-side="start"] {
|
||||||
|
top: 0;
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
var(--scroller-curtain-color),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-side="end"] {
|
||||||
|
bottom: 0;
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
transparent,
|
||||||
|
var(--scroller-curtain-color)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.curtain {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,66 +3,76 @@ import { clamp } from "three/src/math/MathUtils.js";
|
|||||||
import { classNames } from "../../ui/classNames";
|
import { classNames } from "../../ui/classNames";
|
||||||
import styles from "./index.module.css";
|
import styles from "./index.module.css";
|
||||||
|
|
||||||
interface ScrollerProps extends ComponentProps<"div"> {}
|
interface ScrollerProps extends ComponentProps<"div"> {
|
||||||
|
orientation?: "horizontal" | "vertical";
|
||||||
|
}
|
||||||
|
|
||||||
export function Scroller({ children, className, ...props }: ScrollerProps) {
|
export function Scroller({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
orientation = "horizontal",
|
||||||
|
...props
|
||||||
|
}: ScrollerProps) {
|
||||||
const content = useRef<HTMLDivElement>(null!);
|
const content = useRef<HTMLDivElement>(null!);
|
||||||
const curtainLeft = useRef<HTMLDivElement>(null!);
|
const curtainStart = useRef<HTMLDivElement>(null!);
|
||||||
const curtainRight = useRef<HTMLDivElement>(null!);
|
const curtainEnd = useRef<HTMLDivElement>(null!);
|
||||||
|
|
||||||
|
const isHorizontal = orientation === "horizontal";
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function syncCurtains() {
|
function syncCurtains() {
|
||||||
const maxScroll =
|
const maxScroll = isHorizontal
|
||||||
content.current.scrollWidth - content.current.clientWidth;
|
? content.current.scrollWidth - content.current.clientWidth
|
||||||
|
: content.current.scrollHeight - content.current.clientHeight;
|
||||||
|
const scrollPosition = isHorizontal
|
||||||
|
? content.current.scrollLeft
|
||||||
|
: content.current.scrollTop;
|
||||||
|
|
||||||
if (maxScroll <= 0) {
|
if (maxScroll <= 0) {
|
||||||
curtainLeft.current.style.opacity = "0";
|
curtainStart.current.style.opacity = "0";
|
||||||
curtainRight.current.style.opacity = "0";
|
curtainEnd.current.style.opacity = "0";
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fadeDistance = Math.min(60, content.current.clientWidth * 0.15);
|
const dimension = isHorizontal
|
||||||
const leftOpacity = clamp(
|
? content.current.clientWidth
|
||||||
content.current.scrollLeft / fadeDistance,
|
: content.current.clientHeight;
|
||||||
0,
|
const fadeDistance = Math.min(60, dimension * 0.15);
|
||||||
1,
|
const startOpacity = clamp(scrollPosition / fadeDistance, 0, 1);
|
||||||
);
|
const endOpacity = clamp(
|
||||||
const rightOpacity = clamp(
|
(maxScroll - scrollPosition) / fadeDistance,
|
||||||
(maxScroll - content.current.scrollLeft) / fadeDistance,
|
|
||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
|
||||||
curtainLeft.current.style.opacity = `${leftOpacity}`;
|
curtainStart.current.style.opacity = `${startOpacity}`;
|
||||||
curtainRight.current.style.opacity = `${rightOpacity}`;
|
curtainEnd.current.style.opacity = `${endOpacity}`;
|
||||||
}
|
|
||||||
|
|
||||||
function handleScroll() {
|
|
||||||
syncCurtains();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleResize() {
|
|
||||||
syncCurtains();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
syncCurtains();
|
syncCurtains();
|
||||||
|
|
||||||
window.addEventListener("resize", handleResize);
|
window.addEventListener("resize", syncCurtains);
|
||||||
content.current.addEventListener("scroll", handleScroll);
|
content.current.addEventListener("scroll", syncCurtains);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener("resize", handleResize);
|
window.removeEventListener("resize", syncCurtains);
|
||||||
content.current.removeEventListener("scroll", handleScroll);
|
content.current.removeEventListener("scroll", syncCurtains);
|
||||||
};
|
};
|
||||||
}, []);
|
}, [orientation]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(styles.scroller, className)} {...props}>
|
<div
|
||||||
|
className={classNames(styles.scroller, className)}
|
||||||
|
{...props}
|
||||||
|
data-orientation={orientation}
|
||||||
|
>
|
||||||
<div className={styles.content} ref={content}>
|
<div className={styles.content} ref={content}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ref={curtainLeft} data-side="left" className={styles.curtain} />
|
<div ref={curtainStart} data-side="start" className={styles.curtain} />
|
||||||
<div ref={curtainRight} data-side="right" className={styles.curtain} />
|
<div ref={curtainEnd} data-side="end" className={styles.curtain} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
.section {
|
.section {
|
||||||
max-width: 21rem;
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@@ -80,8 +78,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.consumables {
|
.consumables {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-wrap: wrap;
|
grid-template-columns: repeat(3, max-content);
|
||||||
gap: var(--space-3);
|
gap: var(--space-3);
|
||||||
|
|
||||||
.consumable-wrapper {
|
.consumable-wrapper {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ interface TankopediaLoadoutProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function TankopediaLoadout({ characteristics }: TankopediaLoadoutProps) {
|
export function TankopediaLoadout({ characteristics }: TankopediaLoadoutProps) {
|
||||||
const tank = useDuel("protagonist", DuelModule.Tank);
|
// const tank = useDuel("protagonist", DuelModule.Tank);
|
||||||
// const showModules = hasUpgrades(tank);
|
// const showModules = hasUpgrades(tank);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
+8
-5
@@ -13,11 +13,14 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
gap: var(--space-5);
|
|
||||||
padding: var(--space-5);
|
|
||||||
|
|
||||||
overflow-y: auto;
|
|
||||||
|
|
||||||
background-color: var(--gray-2);
|
background-color: var(--gray-2);
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: var(--space-5);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { api } from "../../../../../api/dynamic";
|
import { api } from "../../../../../api/dynamic";
|
||||||
|
import { Scroller } from "../../../../../components/Scroller";
|
||||||
import type { ThicknessRange } from "../../../../../components/StaticArmor";
|
import type { ThicknessRange } from "../../../../../components/StaticArmor";
|
||||||
import { TankopediaCharacteristics } from "../../../../../components/TankopediaCharacteristics";
|
import { TankopediaCharacteristics } from "../../../../../components/TankopediaCharacteristics";
|
||||||
import { TankopediaGameModeAbilities } from "../../../../../components/TankopediaGameModeAbilities";
|
import { TankopediaGameModeAbilities } from "../../../../../components/TankopediaGameModeAbilities";
|
||||||
@@ -52,9 +53,11 @@ export const Page = withErrorWrapper(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.page}>
|
<div className={styles.page}>
|
||||||
<div className={styles.loadout}>
|
<Scroller className={styles.loadout} orientation="vertical">
|
||||||
<TankopediaLoadout characteristics={characteristics} />
|
<div className={styles.content}>
|
||||||
</div>
|
<TankopediaLoadout characteristics={characteristics} />
|
||||||
|
</div>
|
||||||
|
</Scroller>
|
||||||
|
|
||||||
<div className={styles.sandbox}>
|
<div className={styles.sandbox}>
|
||||||
{/* {!skeleton && <TankopediaSandbox thicknessRange={thicknessRange} />} */}
|
{/* {!skeleton && <TankopediaSandbox thicknessRange={thicknessRange} />} */}
|
||||||
|
|||||||
Reference in new issue
Block a user