mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-25 19:49:50 +01:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e208507c3 | ||
|
|
33209a6d31 | ||
|
|
13311245a5 | ||
|
|
4067357b54 |
No files matched your search
@@ -8,43 +8,13 @@
|
||||
.content {
|
||||
overflow: auto;
|
||||
|
||||
scrollbar-width: none;
|
||||
padding-bottom: var(--space-4);
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
transition: scrollbar-color var(--duration-brief);
|
||||
scrollbar-color: transparent transparent;
|
||||
|
||||
.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 {
|
||||
scrollbar-color: var(--gray-7) var(--gray-3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,36 +6,11 @@ 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;
|
||||
@@ -61,61 +36,20 @@ export function Scroller({ children, className, ...props }: ScrollerProps) {
|
||||
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);
|
||||
};
|
||||
@@ -127,12 +61,6 @@ export function Scroller({ children, className, ...props }: ScrollerProps) {
|
||||
{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>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
.section {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: var(--space-5);
|
||||
padding: var(--space-4);
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
max-width: var(--page-width);
|
||||
overflow: hidden;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -186,7 +186,7 @@ export class ServerAPI extends AbstractAPI {
|
||||
return strings;
|
||||
}
|
||||
|
||||
// @Cache()
|
||||
@Cache()
|
||||
async gameStrings(locale: string) {
|
||||
const group = this.metadata.group("ClientConfigsEntity");
|
||||
|
||||
@@ -198,36 +198,28 @@ export class ServerAPI extends AbstractAPI {
|
||||
|
||||
const clientConfig = this.metadata.item(group[0].id);
|
||||
const localizationResources = clientConfig.LocalizationResources();
|
||||
|
||||
if (localizationResources.remote_storages.length !== 1) {
|
||||
throw new RangeError(
|
||||
`Don't know how to handle ${group.length} remote_storages`,
|
||||
);
|
||||
}
|
||||
|
||||
const remoteStorageName = localizationResources.remote_storages[0];
|
||||
let remoteStorage: RemoteStorageComponent | undefined = undefined;
|
||||
|
||||
for (const remoteUrl of remoteStorageName.remote_urls) {
|
||||
const item = this.metadata.item(remoteUrl);
|
||||
const candidate = item.RemoteStorage();
|
||||
|
||||
if (
|
||||
remoteStorage === undefined ||
|
||||
candidate.download_speed_weight > remoteStorage.download_speed_weight
|
||||
) {
|
||||
remoteStorage = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
if (remoteStorage === undefined) {
|
||||
throw new Error("No suitable production remote storage found");
|
||||
}
|
||||
|
||||
const strings: Record<string, string> = {};
|
||||
const configPath = `${remoteStorage.url}${remoteStorage.relative_path}/config.yaml`;
|
||||
|
||||
try {
|
||||
for (const remoteStorageSettings of localizationResources.remote_storages) {
|
||||
let remoteStorage: RemoteStorageComponent | undefined = undefined;
|
||||
|
||||
for (const remoteUrl of remoteStorageSettings.remote_urls) {
|
||||
const item = this.metadata.item(remoteUrl);
|
||||
const candidate = item.RemoteStorage();
|
||||
|
||||
if (
|
||||
remoteStorage === undefined ||
|
||||
candidate.download_speed_weight > remoteStorage.download_speed_weight
|
||||
) {
|
||||
remoteStorage = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
if (remoteStorage === undefined) {
|
||||
throw new Error("No suitable production remote storage found");
|
||||
}
|
||||
|
||||
const configPath = `${remoteStorage.url}${remoteStorage.relative_path}/config.yaml`;
|
||||
const config = await fetch(configPath)
|
||||
.then((response) => response.text())
|
||||
.then((text) => parse(text) as LocalizationConfig);
|
||||
@@ -245,11 +237,6 @@ export class ServerAPI extends AbstractAPI {
|
||||
|
||||
Object.assign(strings, namespaceStrings);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
`Failed to fetch config from ${configPath}. Returning empty strings. This will throw an error in production. Error:`,
|
||||
error,
|
||||
);
|
||||
}
|
||||
|
||||
return strings;
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useLocale } from "./useLocale";
|
||||
export function useGameStrings(group: string) {
|
||||
const locale = useLocale();
|
||||
const strings = useAwait(
|
||||
() => api._groupedGameStrings(locale, group, true),
|
||||
() => api.groupedGameStrings(locale, group, true),
|
||||
`game-strings-${locale}-${group}`,
|
||||
);
|
||||
return strings;
|
||||
|
||||
Reference in new issue
Block a user