mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf04fe21b3 | ||
|
|
84eb3c2da3 | ||
|
|
22bf2dc1d8 | ||
|
|
b9c339daa7 | ||
|
|
ef3006cac1 | ||
|
|
e482fd40c1 | ||
|
|
cc4569966e | ||
|
|
3708a3ced7 | ||
|
|
0ae59c2fd7 | ||
|
|
7027f63236 | ||
|
|
6725e79021 | ||
|
|
5ca3cee9da | ||
|
|
602a5a1e99 | ||
|
|
bfbf3bdc39 | ||
|
|
644686582e | ||
|
|
1c00bc81f8 | ||
|
|
ac3b69bec5 | ||
|
|
3e14c943b6 | ||
|
|
d33633be2c | ||
|
|
4bf70d02d0 | ||
|
|
377bcf0e38 | ||
|
|
884b6d4318 |
No files matched your search
@@ -39,6 +39,17 @@ env:
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||
PUBLIC_ASSET_BRANCH: ${{ github.event.inputs.cdn_branch || secrets.PUBLIC_ASSET_BRANCH }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: true
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
PUBLIC_PATREON_CLIENT_ID: ${{ secrets.PUBLIC_PATREON_CLIENT_ID }}
|
||||
PUBLIC_PATREON_REDIRECT_URI: ${{ secrets.PUBLIC_PATREON_REDIRECT_URI }}
|
||||
PATREON_CLIENT_SECRET: ${{ secrets.PATREON_CLIENT_SECRET }}
|
||||
PUBLIC_NITROPAY_ID: ${{ secrets.PUBLIC_NITROPAY_ID }}
|
||||
PUBLIC_DEBUG_MISSING_I18N: false
|
||||
|
||||
jobs:
|
||||
download_client:
|
||||
@@ -106,6 +117,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
@@ -127,7 +141,7 @@ jobs:
|
||||
|
||||
- name: Start server and build assets
|
||||
run: |
|
||||
bun dev:website &
|
||||
bun dev:website --verbosepa &
|
||||
SERVER_PID=$!
|
||||
|
||||
bun run build:assets --all-targets --depot --production
|
||||
|
||||
@@ -2,7 +2,6 @@ name: Website
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: main
|
||||
workflow_dispatch:
|
||||
|
||||
schedule:
|
||||
@@ -27,6 +26,8 @@ env:
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -53,6 +54,7 @@ jobs:
|
||||
path: dist/website
|
||||
|
||||
deploy-github-pages:
|
||||
if: ${{ github.ref == 'refs/heads/main' }}
|
||||
name: Deploy to GitHub Pages
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
files:
|
||||
- source: /packages/core/lang/en.json
|
||||
- source: /packages/i18n/strings/en.json
|
||||
translation: /%original_path%/%locale%.json
|
||||
@@ -0,0 +1,7 @@
|
||||
# BlitzKit 1.27.1
|
||||
|
||||
## Fixes
|
||||
|
||||
- Fixed a crash that occurs if tanks are deleted in Blitz and were once available in BlitzKit
|
||||
- All tank icons are now back
|
||||
- The tank search once again returns results
|
||||
+3
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "blitzkit",
|
||||
"private": true,
|
||||
"version": "1.27.0",
|
||||
"version": "1.27.1",
|
||||
"description": "🎉 Tools for everything World of Tanks Blitz",
|
||||
"type": "module",
|
||||
"types": "./types.d.ts",
|
||||
@@ -35,7 +35,8 @@
|
||||
"build:protos": "bun packages/scripts/src/protos.ts",
|
||||
"preview:website": "cd packages/website && bun run preview",
|
||||
"build:reviews": "cd packages/scripts && bun build:reviews",
|
||||
"build:ids": "cd packages/scripts && bun build:ids"
|
||||
"build:ids": "cd packages/scripts && bun build:ids",
|
||||
"prunestrings": "cd packages/scripts && bun prunestrings"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { SEARCH_KEYS } from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { Locale } from 'discord.js';
|
||||
import { go } from 'fuzzysort';
|
||||
@@ -19,10 +20,7 @@ export async function resolveTankId(
|
||||
const searchResult = go(
|
||||
`${tank}`,
|
||||
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
||||
{
|
||||
keys: ['searchableName', 'searchableNameDeburr', 'camouflages'],
|
||||
limit: 1,
|
||||
},
|
||||
{ keys: SEARCH_KEYS, limit: 1 },
|
||||
);
|
||||
|
||||
if (searchResult.length === 0) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { fetchTankNames, TankType } from '@blitzkit/core';
|
||||
import { SUPPORTED_LOCALES } from '@blitzkit/i18n';
|
||||
import { fetchTankNames, SEARCH_KEYS, TankType } from '@blitzkit/core';
|
||||
import {
|
||||
ApplicationCommandOptionChoiceData,
|
||||
AutocompleteInteraction,
|
||||
@@ -32,16 +31,7 @@ export async function autocompleteTanks(
|
||||
go(
|
||||
focusedOption.value,
|
||||
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
||||
{
|
||||
keys: [
|
||||
...SUPPORTED_LOCALES.map((locale) => [
|
||||
`searchableName.{locale}`,
|
||||
`searchableNameDeburr.{locale}`,
|
||||
]).flat(),
|
||||
'camouflages',
|
||||
],
|
||||
limit: 10,
|
||||
},
|
||||
{ keys: SEARCH_KEYS, limit: 10 },
|
||||
).map(async (item) => {
|
||||
let name = unwrap(item.obj.searchableName);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { deburr } from 'lodash-es';
|
||||
import { SUPPORTED_LOCALES } from '../../../i18n/src/strings';
|
||||
import { I18nString } from '../protos';
|
||||
import { fetchCamouflageDefinitions } from './camouflageDefinitions';
|
||||
import { fetchTankDefinitions } from './tankDefinitions';
|
||||
@@ -33,3 +34,11 @@ export async function fetchTankNames() {
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export const SEARCH_KEYS = [
|
||||
...SUPPORTED_LOCALES.map((locale) => [
|
||||
`searchableName.locales.${locale}`,
|
||||
`searchableNameDeburr.locales.${locale}`,
|
||||
]).flat(),
|
||||
'camouflages',
|
||||
];
|
||||
+1592
-221
File diff suppressed because it is too large.
Load diff
+535
-516
File diff suppressed because it is too large.
Load diff
+535
-516
File diff suppressed because it is too large.
Load diff
+563
-486
File diff suppressed because it is too large.
Load diff
+739
-468
File diff suppressed because it is too large.
Load diff
+2135
-448
File diff suppressed because it is too large.
Load diff
+535
-516
File diff suppressed because it is too large.
Load diff
+745
-456
File diff suppressed because it is too large.
Load diff
@@ -10,7 +10,8 @@
|
||||
"build:reviews": "bun src/reviews.ts",
|
||||
"build:ids": "bun src/discoverIds.ts",
|
||||
"build:bot": "bun src/buildBot.ts",
|
||||
"build:ratingleaderboard": "bun src/buildRatingLeaderboard.ts"
|
||||
"build:ratingleaderboard": "bun src/buildRatingLeaderboard.ts",
|
||||
"prunestrings": "bun src/pruneStrings.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzkit/core": "workspace:*",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { assertSecret } from '@blitzkit/core';
|
||||
import { existsSync } from 'fs';
|
||||
import { mkdir, writeFile } from 'fs/promises';
|
||||
import { parse as parsePath } from 'path';
|
||||
import ProgressBar from 'progress';
|
||||
@@ -45,19 +46,24 @@ while (true) {
|
||||
files.length,
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
files.map(async ({ path, data }) => {
|
||||
const { dir } = parsePath(path);
|
||||
for (const { path, data } of files) {
|
||||
console.log(`Patching "${path}"...`);
|
||||
|
||||
const { dir } = parsePath(path);
|
||||
|
||||
try {
|
||||
await mkdir(`${DATA}/${dir}`, { recursive: true });
|
||||
await writeFile(
|
||||
`${DATA}/${path}`,
|
||||
new Uint8Array(writeDVPL(Buffer.from(data))),
|
||||
);
|
||||
} catch (error) {
|
||||
console.warn(`Failed to make directory "${dir}"`);
|
||||
}
|
||||
|
||||
bar.tick();
|
||||
}),
|
||||
);
|
||||
await writeFile(
|
||||
`${DATA}/${path}`,
|
||||
new Uint8Array(writeDVPL(Buffer.from(data))),
|
||||
);
|
||||
|
||||
bar.tick();
|
||||
}
|
||||
|
||||
if ('dynamicContentLocalizationsDir' in data) {
|
||||
console.log('Found dynamic content localizations; patching...');
|
||||
|
||||
@@ -3,7 +3,7 @@ import { DATA_COMPRESSED } from '../../buildAssets/constants';
|
||||
import { readDVPL } from './readDVPL';
|
||||
|
||||
export async function readDVPLFile(file: string) {
|
||||
if (DATA_COMPRESSED) {
|
||||
if (DATA_COMPRESSED && !file.endsWith('.dvpl')) {
|
||||
return readDVPL(await readFile(`${file}.dvpl`));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
DEFAULT_LOCALE,
|
||||
SUPPORTED_LOCALES,
|
||||
TranslationTree,
|
||||
} from '@blitzkit/i18n';
|
||||
import { writeFile } from 'fs/promises';
|
||||
|
||||
const ROOT = '@blitzkit/i18n/strings';
|
||||
const WORKING_ROOT = '../../packages/i18n/strings';
|
||||
|
||||
const defaultStrings = await import(`${ROOT}/${DEFAULT_LOCALE}.json`);
|
||||
const nonDefaultLocales = SUPPORTED_LOCALES.filter(
|
||||
(locale) => locale !== DEFAULT_LOCALE,
|
||||
);
|
||||
|
||||
function prune(defaultStrings: TranslationTree, strings: TranslationTree) {
|
||||
for (const key in strings) {
|
||||
if (key in defaultStrings) {
|
||||
if (typeof defaultStrings[key] === typeof strings[key]) {
|
||||
if (typeof strings[key] === 'string') {
|
||||
if (
|
||||
(defaultStrings[key] as string).replaceAll(/%s\d/g, '%s') ===
|
||||
(strings[key] as string).replaceAll(/%s\d/g, '%s') ||
|
||||
strings[key] === ''
|
||||
) {
|
||||
delete strings[key];
|
||||
}
|
||||
} else {
|
||||
prune(defaultStrings[key] as TranslationTree, strings[key]);
|
||||
}
|
||||
} else {
|
||||
delete strings[key];
|
||||
}
|
||||
} else {
|
||||
delete strings[key];
|
||||
}
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
for (const locale of nonDefaultLocales) {
|
||||
console.log(`Pruning ${locale}...`);
|
||||
|
||||
const strings = await import(`${ROOT}/${locale}.json`);
|
||||
const pruned = prune(defaultStrings, strings);
|
||||
|
||||
writeFile(`${WORKING_ROOT}/${locale}.json`, JSON.stringify(pruned, null, 2));
|
||||
}
|
||||
@@ -1,4 +1,9 @@
|
||||
import { asset, TankType, type TankDefinition } from '@blitzkit/core';
|
||||
import {
|
||||
asset,
|
||||
fetchTankDefinitions,
|
||||
TankType,
|
||||
type TankDefinition,
|
||||
} from '@blitzkit/core';
|
||||
import { Flex, Text, type TextProps } from '@radix-ui/themes';
|
||||
import { uniq } from 'lodash-es';
|
||||
import { forwardRef, type ReactNode } from 'react';
|
||||
@@ -16,6 +21,8 @@ type TankCardProps = TextProps & {
|
||||
noLink?: boolean;
|
||||
};
|
||||
|
||||
const tankDefinitions = await fetchTankDefinitions();
|
||||
|
||||
export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>(
|
||||
(
|
||||
{
|
||||
@@ -49,10 +56,9 @@ export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>(
|
||||
onClick={() => {
|
||||
onSelect?.(tank);
|
||||
mutateTankopediaPersistent((draft) => {
|
||||
draft.recentlyViewed = uniq([
|
||||
tank.id,
|
||||
...draft.recentlyViewed,
|
||||
]).slice(0, MAX_RECENTLY_VIEWED);
|
||||
draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed])
|
||||
.filter((id) => id in tankDefinitions.tanks)
|
||||
.slice(0, MAX_RECENTLY_VIEWED);
|
||||
});
|
||||
}}
|
||||
className="tank-search-card"
|
||||
|
||||
@@ -12,7 +12,7 @@ export function NoResults({ type = 'filters' }: NoResultsProps) {
|
||||
return (
|
||||
<Flex flexGrow="1" align="center" justify="center">
|
||||
<Text color="gray">
|
||||
{strings.website.common.tank_search.no_tanks_found.body}.{' '}
|
||||
{strings.website.common.tank_search.no_tanks_found.body}{' '}
|
||||
<Link
|
||||
href="#"
|
||||
underline="always"
|
||||
@@ -25,7 +25,6 @@ export function NoResults({ type = 'filters' }: NoResultsProps) {
|
||||
? strings.website.common.tank_search.no_tanks_found.clear_filters
|
||||
: strings.website.common.tank_search.no_tanks_found.search_again}
|
||||
</Link>
|
||||
.
|
||||
</Text>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
@@ -16,7 +16,9 @@ export function RecentlyViewed() {
|
||||
const tankopediaPersistentStore = TankopediaPersistent.useStore();
|
||||
const filters = useStore($tankFilters);
|
||||
// non-reactive because it is a little weird that it updates instantly even before the page loads
|
||||
const recentlyViewed = tankopediaPersistentStore.getState().recentlyViewed;
|
||||
const recentlyViewed = tankopediaPersistentStore
|
||||
.getState()
|
||||
.recentlyViewed.filter((id) => id in tankDefinitions.tanks);
|
||||
const sort = useStore($tankopediaSort);
|
||||
const hasFilters = useMemo(
|
||||
() =>
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
metaSortTank,
|
||||
normalizeBoundingBox,
|
||||
resolveDpm,
|
||||
SEARCH_KEYS,
|
||||
unionBoundingBox,
|
||||
type TankDefinition,
|
||||
} from '@blitzkit/core';
|
||||
@@ -410,7 +411,7 @@ export const TankSearch = memo<TankSearchProps>(
|
||||
: sorted.reverse();
|
||||
} else {
|
||||
const searchedRaw = fuzzysort.go(tankFilters.search, tankNames, {
|
||||
keys: ['searchableName', 'searchableNameDeburr', 'camouflages'],
|
||||
keys: SEARCH_KEYS,
|
||||
});
|
||||
const searchedTanks = searchedRaw.map(
|
||||
(result) => tankDefinitions.tanks[result.obj.id],
|
||||
@@ -456,7 +457,9 @@ export const TankSearch = memo<TankSearchProps>(
|
||||
draft.recentlyViewed = uniq([
|
||||
...tanksFiltered.map(({ id }) => id),
|
||||
...draft.recentlyViewed,
|
||||
]).slice(0, MAX_RECENTLY_VIEWED);
|
||||
])
|
||||
.filter((id) => id in tankDefinitions.tanks)
|
||||
.slice(0, MAX_RECENTLY_VIEWED);
|
||||
});
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { assertSecret } from '@blitzkit/core';
|
||||
import { assertSecret, fetchTankDefinitions } from '@blitzkit/core';
|
||||
import { MinusCircledIcon } from '@radix-ui/react-icons';
|
||||
import { Callout, Flex } from '@radix-ui/themes';
|
||||
import { uniq } from 'lodash-es';
|
||||
@@ -9,6 +9,8 @@ import { AesonPlug } from '../AesonPlug';
|
||||
import { ExperimentIcon } from '../ExperimentIcon';
|
||||
import { MAX_RECENTLY_VIEWED } from '../TankSearch/constants';
|
||||
|
||||
const tankDefinitions = await fetchTankDefinitions();
|
||||
|
||||
export function CalloutsSection() {
|
||||
const tank = Duel.use((state) => state.protagonist.tank);
|
||||
const mutateTankopediaPersistent = TankopediaPersistent.useMutation();
|
||||
@@ -17,10 +19,9 @@ export function CalloutsSection() {
|
||||
|
||||
useEffect(() => {
|
||||
mutateTankopediaPersistent((draft) => {
|
||||
draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed]).slice(
|
||||
0,
|
||||
MAX_RECENTLY_VIEWED,
|
||||
);
|
||||
draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed])
|
||||
.filter((id) => id in tankDefinitions.tanks)
|
||||
.slice(0, MAX_RECENTLY_VIEWED);
|
||||
});
|
||||
}, [tank]);
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ const locale = Astro.params.locale ?? DEFAULT_LOCALE;
|
||||
import { SUPPORTED_LOCALES } from '@blitzkit/i18n';
|
||||
import { getBestLocale } from '../core/i18n/getBestLocale';
|
||||
|
||||
const isAPI = window.location.pathname.startsWith('/api');
|
||||
const isI18nPath = SUPPORTED_LOCALES.some((locale) =>
|
||||
window.location.pathname.startsWith(`/${locale}`),
|
||||
);
|
||||
@@ -38,7 +39,7 @@ const locale = Astro.params.locale ?? DEFAULT_LOCALE;
|
||||
window.location.pathname.startsWith(`/${locale}`),
|
||||
);
|
||||
|
||||
if (bestLocale !== currentPathLocale) {
|
||||
if (!isAPI && bestLocale !== currentPathLocale) {
|
||||
window.location.pathname = isI18nPath
|
||||
? window.location.pathname.replace(
|
||||
`/${currentPathLocale}`,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { TankSandbox } from '../../../../../components/Tankopedia/HeroSection/co
|
||||
import { awaitableModelDefinitions } from '../../../../../core/awaitables/modelDefinitions';
|
||||
import { awaitableProvisionDefinitions } from '../../../../../core/awaitables/provisionDefinitions';
|
||||
import { awaitableTankDefinitions } from '../../../../../core/awaitables/tankDefinitions';
|
||||
import { LocaleProvider } from '../../../../../hooks/useLocale';
|
||||
import { App } from '../../../../../stores/app';
|
||||
import { Duel } from '../../../../../stores/duel';
|
||||
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral';
|
||||
@@ -23,15 +24,17 @@ export function Page({ id }: PageProps) {
|
||||
const model = modelDefinitions.models[id];
|
||||
|
||||
return (
|
||||
<App.Provider>
|
||||
<TankopediaPersistent.Provider>
|
||||
<Duel.Provider data={{ provisionDefinitions, tank }}>
|
||||
<TankopediaEphemeral.Provider data={model}>
|
||||
<Content />
|
||||
</TankopediaEphemeral.Provider>
|
||||
</Duel.Provider>
|
||||
</TankopediaPersistent.Provider>
|
||||
</App.Provider>
|
||||
<LocaleProvider locale="en">
|
||||
<App.Provider>
|
||||
<TankopediaPersistent.Provider>
|
||||
<Duel.Provider data={{ provisionDefinitions, tank }}>
|
||||
<TankopediaEphemeral.Provider data={model}>
|
||||
<Content />
|
||||
</TankopediaEphemeral.Provider>
|
||||
</Duel.Provider>
|
||||
</TankopediaPersistent.Provider>
|
||||
</App.Provider>
|
||||
</LocaleProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user