mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-11-03 07:50:36 +01:00
Compare commits
5
Commits
015d457d23
...
ff02f06cbc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff02f06cbc | ||
|
|
7a817cbe8c | ||
|
|
58e0876aa0 | ||
|
|
f84f846e76 | ||
|
|
ddb869e767 |
No files matched your search
Vendored
+1
@@ -221,6 +221,7 @@
|
|||||||
"tungstentip",
|
"tungstentip",
|
||||||
"Turretless",
|
"Turretless",
|
||||||
"TYPELESS",
|
"TYPELESS",
|
||||||
|
"uasset",
|
||||||
"ubjson",
|
"ubjson",
|
||||||
"Unicum",
|
"Unicum",
|
||||||
"UNLOCALIZED",
|
"UNLOCALIZED",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"license": "BlitzKit License",
|
"license": "BlitzKit License",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"build:game": "cd packages/game && dotnet build",
|
||||||
"build:assets": "cd packages/scripts && bun run build:assets",
|
"build:assets": "cd packages/scripts && bun run build:assets",
|
||||||
"build:averages": "bun --filter=@blitzkit/scripts run build:averages",
|
"build:averages": "bun --filter=@blitzkit/scripts run build:averages",
|
||||||
"build:bot": "cd packages/scripts && bun run build:bot",
|
"build:bot": "cd packages/scripts && bun run build:bot",
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[*.cs]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<NodeApiAssemblyJSModuleType>esm</NodeApiAssemblyJSModuleType>
|
<NodeApiAssemblyJSModuleType>esm</NodeApiAssemblyJSModuleType>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -7,22 +7,41 @@ namespace game.src.classes;
|
|||||||
[JSExport]
|
[JSExport]
|
||||||
public class BlitzProvider
|
public class BlitzProvider
|
||||||
{
|
{
|
||||||
private readonly DefaultFileProvider provider;
|
private readonly DefaultFileProvider provider;
|
||||||
|
|
||||||
public BlitzProvider(string directory)
|
public string[] files;
|
||||||
{
|
public string[] tanksDirectoryNations;
|
||||||
provider = new(
|
|
||||||
directory: directory,
|
|
||||||
searchOption: SearchOption.AllDirectories,
|
|
||||||
versions: new(EGame.GAME_UE5_5),
|
|
||||||
pathComparer: StringComparer.OrdinalIgnoreCase
|
|
||||||
);
|
|
||||||
provider.Initialize();
|
|
||||||
provider.Mount();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string[] Files()
|
public BlitzProvider(string directory)
|
||||||
{
|
{
|
||||||
return provider.Files.Keys.ToArray();
|
provider = new(
|
||||||
}
|
directory: directory,
|
||||||
|
searchOption: SearchOption.AllDirectories,
|
||||||
|
versions: new(EGame.GAME_UE5_5),
|
||||||
|
pathComparer: StringComparer.OrdinalIgnoreCase
|
||||||
|
);
|
||||||
|
provider.Initialize();
|
||||||
|
provider.Mount();
|
||||||
|
|
||||||
|
files = [.. provider.Files.Keys];
|
||||||
|
|
||||||
|
var tanksBase = "Blitz/Content/Tanks/";
|
||||||
|
tanksDirectoryNations =
|
||||||
|
[
|
||||||
|
.. files
|
||||||
|
.Where(path => path.StartsWith(tanksBase))
|
||||||
|
.Select(path => path[tanksBase.Length..])
|
||||||
|
.Select(path => path.Split('/')[0])
|
||||||
|
.Where(nation => !nation.EndsWith(".uasset") && nation != "TankStub")
|
||||||
|
.Distinct(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] Files => files;
|
||||||
|
public string[] TanksDirectoryNations => tanksDirectoryNations;
|
||||||
|
|
||||||
|
public byte[] TankBigIcon(string tankId, string pdaName)
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
import { api } from "../core/api/dynamic";
|
import { api } from "../core/api/dynamic";
|
||||||
import { tools } from "../core/tools/tools";
|
import { tools } from "../core/tools/tools";
|
||||||
import { Heading } from "./Heading";
|
import { Heading } from "./Heading";
|
||||||
|
import { Scroller } from "./Scroller";
|
||||||
import { Section } from "./Section";
|
import { Section } from "./Section";
|
||||||
import { TankCard } from "./TankCard";
|
import { TankCard } from "./TankCard";
|
||||||
import ToolCard from "./ToolCard.astro";
|
import ToolCard from "./ToolCard.astro";
|
||||||
@@ -35,8 +36,6 @@ const popular = [
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tanks {
|
.tanks {
|
||||||
/* overflow-x: scroll; */
|
|
||||||
overflow-x: hidden;
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@@ -50,11 +49,11 @@ const popular = [
|
|||||||
<Section>
|
<Section>
|
||||||
<Heading size="2" className="title">{strings.home.tanks}</Heading>
|
<Heading size="2" className="title">{strings.home.tanks}</Heading>
|
||||||
|
|
||||||
<div class="tanks">
|
<Scroller client:load className="tanks">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{popular.map((tank) => <TankCard {tank} />)}
|
{popular.map((tank) => <TankCard {tank} />)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Scroller>
|
||||||
|
|
||||||
<ToolCard gradient {locale} tool={tools.tanks} />
|
<ToolCard gradient {locale} tool={tools.tanks} />
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export function Scroller() {}
|
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
.scroller {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-3);
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
scrollbar-width: none;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-wrapper {
|
||||||
|
opacity: 0;
|
||||||
|
padding: var(--space-1);
|
||||||
|
background-color: var(--gray-3);
|
||||||
|
|
||||||
|
transition: opacity var(--duration-brief);
|
||||||
|
|
||||||
|
border-radius: var(--max-size);
|
||||||
|
|
||||||
|
.bar-container {
|
||||||
|
height: var(--space-3);
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.bar {
|
||||||
|
height: 100%;
|
||||||
|
min-width: min(100%, var(--space-6));
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
border-radius: var(--max-size);
|
||||||
|
background-color: var(--gray-7);
|
||||||
|
|
||||||
|
cursor: grab;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus-within {
|
||||||
|
.bar-wrapper {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.curtain {
|
||||||
|
width: min(25%, var(--space-7));
|
||||||
|
height: calc(100% - var(--space-3) - 2 * var(--space-1));
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
&[data-side="left"] {
|
||||||
|
left: 0;
|
||||||
|
background: linear-gradient(90deg, var(--gray-1), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-side="right"] {
|
||||||
|
right: 0;
|
||||||
|
background: linear-gradient(90deg, transparent, var(--gray-1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
import { useEffect, useRef, type ComponentProps } from "react";
|
||||||
|
import { clamp } from "three/src/math/MathUtils.js";
|
||||||
|
import { classNames } from "../../core/ui/classNames";
|
||||||
|
import styles from "./index.module.css";
|
||||||
|
|
||||||
|
interface ScrollerProps extends ComponentProps<"div"> {}
|
||||||
|
|
||||||
|
export function Scroller({ children, className, ...props }: ScrollerProps) {
|
||||||
|
const bar = useRef<HTMLDivElement>(null!);
|
||||||
|
const container = useRef<HTMLDivElement>(null!);
|
||||||
|
const content = useRef<HTMLDivElement>(null!);
|
||||||
|
const curtainLeft = useRef<HTMLDivElement>(null!);
|
||||||
|
const curtainRight = useRef<HTMLDivElement>(null!);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function updateBarSize() {
|
||||||
|
const visible = content.current.clientWidth;
|
||||||
|
const total = content.current.scrollWidth;
|
||||||
|
|
||||||
|
if (total <= 0) return;
|
||||||
|
|
||||||
|
bar.current.style.width = `${(visible / total) * 100}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncBar() {
|
||||||
|
const maxTravel = container.current.clientWidth - bar.current.clientWidth;
|
||||||
|
const maxScroll =
|
||||||
|
content.current.scrollWidth - content.current.clientWidth;
|
||||||
|
|
||||||
|
if (maxScroll <= 0 || maxTravel <= 0) {
|
||||||
|
bar.current.style.left = "0";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ratio = content.current.scrollLeft / maxScroll;
|
||||||
|
bar.current.style.left = `${ratio * maxTravel}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncCurtains() {
|
||||||
|
const maxScroll =
|
||||||
|
content.current.scrollWidth - content.current.clientWidth;
|
||||||
|
if (maxScroll <= 0) {
|
||||||
|
curtainLeft.current.style.opacity = "0";
|
||||||
|
curtainRight.current.style.opacity = "0";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fadeDistance = Math.min(60, content.current.clientWidth * 0.15);
|
||||||
|
const leftOpacity = clamp(
|
||||||
|
content.current.scrollLeft / fadeDistance,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
const rightOpacity = clamp(
|
||||||
|
(maxScroll - content.current.scrollLeft) / fadeDistance,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
|
||||||
|
curtainLeft.current.style.opacity = `${leftOpacity}`;
|
||||||
|
curtainRight.current.style.opacity = `${rightOpacity}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastX = 0;
|
||||||
|
|
||||||
|
function handlePointerDown(event: PointerEvent) {
|
||||||
|
lastX = event.clientX;
|
||||||
|
bar.current.setPointerCapture(event.pointerId);
|
||||||
|
|
||||||
|
window.addEventListener("pointermove", handlePointerMove);
|
||||||
|
window.addEventListener("pointerup", handlePointerUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePointerMove(event: PointerEvent) {
|
||||||
|
const dx = event.clientX - lastX;
|
||||||
|
lastX = event.clientX;
|
||||||
|
|
||||||
|
const maxTravel = container.current.clientWidth - bar.current.clientWidth;
|
||||||
|
if (maxTravel <= 0) return;
|
||||||
|
|
||||||
|
const maxScroll =
|
||||||
|
content.current.scrollWidth - content.current.clientWidth;
|
||||||
|
const delta = (dx / maxTravel) * maxScroll;
|
||||||
|
|
||||||
|
content.current.scrollLeft += delta;
|
||||||
|
|
||||||
|
syncBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePointerUp(event: PointerEvent) {
|
||||||
|
bar.current.releasePointerCapture(event.pointerId);
|
||||||
|
window.removeEventListener("pointermove", handlePointerMove);
|
||||||
|
window.removeEventListener("pointerup", handlePointerUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleScroll() {
|
||||||
|
syncBar();
|
||||||
|
syncCurtains();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleResize() {
|
||||||
|
updateBarSize();
|
||||||
|
syncBar();
|
||||||
|
syncCurtains();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateBarSize();
|
||||||
|
syncBar();
|
||||||
|
syncCurtains();
|
||||||
|
|
||||||
|
bar.current.addEventListener("pointerdown", handlePointerDown);
|
||||||
|
content.current.addEventListener("scroll", syncBar);
|
||||||
|
window.addEventListener("resize", handleResize);
|
||||||
|
content.current.addEventListener("scroll", handleScroll);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
bar.current.removeEventListener("pointerdown", handlePointerDown);
|
||||||
|
content.current.removeEventListener("scroll", syncBar);
|
||||||
|
window.removeEventListener("resize", handleResize);
|
||||||
|
content.current.removeEventListener("scroll", handleScroll);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classNames(styles.scroller, className)} {...props}>
|
||||||
|
<div className={styles.content} ref={content}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles["bar-wrapper"]}>
|
||||||
|
<div className={styles["bar-container"]} ref={container}>
|
||||||
|
<div className={styles.bar} ref={bar} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ref={curtainLeft} data-side="left" className={styles.curtain} />
|
||||||
|
<div ref={curtainRight} data-side="right" className={styles.curtain} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user