Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
dd60e13
Build scenario analytics dashboard
Emissaryx Jul 29, 2026
dbdc4d8
Improve scenario rankings and match details
Emissaryx Jul 29, 2026
e37963e
Support direct Cloudflare page links
Emissaryx Jul 29, 2026
84f99a3
Simplify scenario filters and expand leaderboard controls
Emissaryx Jul 29, 2026
0d800a3
Unify scenario filters and add time ranges
Emissaryx Jul 29, 2026
c20be00
Stop time filters from refetching continuously
Emissaryx Jul 30, 2026
9e38719
Load useful batches for scenario time ranges
Emissaryx Jul 30, 2026
d32f30d
Calculate leaderboards from complete time windows
Emissaryx Jul 30, 2026
1f253de
Respect scenario API page-size limit
Emissaryx Jul 30, 2026
384a969
Show realm win rates above balance bar
Emissaryx Jul 30, 2026
8b0f954
Place win rates at realm balance split
Emissaryx Jul 30, 2026
ba64082
Remove win-rate label backgrounds
Emissaryx Jul 30, 2026
f6b0770
Restore complete stylesheet
Emissaryx Jul 30, 2026
0ac2b30
Improve scenario filter performance and clarity
Emissaryx Jul 30, 2026
ee49e66
Use the last hour as the default scenario window
Emissaryx Jul 30, 2026
61b8cb5
Add scenario activity breakdown
Emissaryx Jul 30, 2026
6577dfd
Fit standout tables without desktop scrolling
Emissaryx Jul 30, 2026
2e041e1
Add sortable scenario balance analysis
Emissaryx Jul 30, 2026
bbbab1f
Keep profile scenario history outside dashboard default
Emissaryx Jul 30, 2026
0f4f8d9
Add totals average and median standout views
Emissaryx Jul 30, 2026
b277440
Add character scenario relationships
Emissaryx Jul 30, 2026
982874b
Clarify selected and active scenario dates
Emissaryx Jul 30, 2026
109c56a
Scenario page: fix share-link drift, align column order, sort by real…
Emissaryx Aug 1, 2026
2a98495
Scenario page styling: balance/score colors, Bulma select widths
Emissaryx Aug 1, 2026
0335191
Standouts: default Average/Median to a 10+ scenario minimum
Emissaryx Aug 1, 2026
68b5acb
Fix misaligned dropdown arrow on compact Bulma selects
Emissaryx Aug 1, 2026
0826f6f
Scenario scoreboard: group by role, show % of team per stat
Emissaryx Aug 1, 2026
7f4c37c
Add scoreboard team/role section styles
Emissaryx Aug 1, 2026
f677c2b
Remove useless default prop value (lint fix)
Emissaryx Aug 1, 2026
e1da98f
Remove useless default prop value (lint fix)
Emissaryx Aug 1, 2026
ca2eb20
Remove useless default prop value (lint fix)
Emissaryx Aug 1, 2026
e60aba8
Remove dead commented-out GameObject search row
Emissaryx Aug 1, 2026
a572d9d
Cache scenario window results to avoid redownloading on revisit
Emissaryx Aug 2, 2026
9196265
Bucket the relative time window to 5 minutes so cache-first actually …
Emissaryx Aug 2, 2026
07a802c
Add navigation links for items, quests, creatures, instances, and sto…
Emissaryx Aug 2, 2026
d7a7a74
Reorder main nav links alphabetically
Emissaryx Aug 2, 2026
c20f975
Wrap select elements in divs for styling
Emissaryx Aug 2, 2026
e37c175
Refactor career selection to use a div wrapper
Emissaryx Aug 2, 2026
448615c
Refactor select elements for item filters
Emissaryx Aug 2, 2026
454e4d2
Add MainNav component for navigation links
Emissaryx Aug 2, 2026
874de3c
Add MainNav component to App routing
Emissaryx Aug 2, 2026
b24d13b
Clean up Home component by removing imports and links
Emissaryx Aug 2, 2026
7aa4aa9
Add generic filter-grid and filter-summary-bar styles
Emissaryx Aug 2, 2026
490c83e
Fix Instances breadcrumb and switch filters to filter-grid
Emissaryx Aug 2, 2026
74000be
Switch Creatures filter to filter-grid
Emissaryx Aug 2, 2026
ca0fe15
Refactor search box layout in Quests component
Emissaryx Aug 2, 2026
e778912
Refactor Items page layout and search filters
Emissaryx Aug 2, 2026
b8468ac
Refactor SkirmishFilters layout to use filter-grid
Emissaryx Aug 2, 2026
013f470
Refactor career filter layout and improve accessibility
Emissaryx Aug 2, 2026
b89988b
Change container class for Home component
Emissaryx Aug 2, 2026
921fd18
Update MainNav container class for responsiveness
Emissaryx Aug 2, 2026
2920069
Change container class to is-max-widescreen
Emissaryx Aug 2, 2026
bde20fb
Update container class to is-max-widescreen
Emissaryx Aug 2, 2026
9225ada
Change container class to is-max-widescreen
Emissaryx Aug 2, 2026
9099c74
Update container class for SearchGuild component
Emissaryx Aug 2, 2026
a7494ff
Add creatureTitleIcon/creatureTitleLabel helpers
Emissaryx Aug 2, 2026
2d81f9d
Refactor creature table to include title and spawns
Emissaryx Aug 2, 2026
3b4f914
Add realm, role, and location to creatures JSON
Emissaryx Aug 2, 2026
66d72a3
Add ID column to Creatures table
Emissaryx Aug 2, 2026
037375b
Refactor VendorItems to load all items at once
Emissaryx Aug 2, 2026
68584b4
Add 'id' field to creatures section in pages.json
Emissaryx Aug 2, 2026
807b640
Add filterItems translation key to itemVendors
Emissaryx Aug 2, 2026
68c5a90
Implement scrollable vendor items card
Emissaryx Aug 2, 2026
3535278
Handle data issues when loading vendor items
Emissaryx Aug 2, 2026
894462e
Recover partial data from malformed vendor item rows
Emissaryx Aug 2, 2026
de514b6
Live-filter all search boxes; fix wrong-page navigation and silent da…
Emissaryx Aug 2, 2026
5da8a65
Fix search box regressions from the live-filter change
Emissaryx Aug 2, 2026
36ad18f
Fix focus loss during live search on all list pages
Emissaryx Aug 2, 2026
eacdae6
Fix clearing the guild search box landing on player search with 'guil…
Emissaryx Aug 3, 2026
c359873
Keep focus in the search box across the Home-to-search-results naviga…
Emissaryx Aug 3, 2026
7db3caa
Add instance hub page: Runs/Characters/Leaderboards tabs per dungeon
Emissaryx Aug 3, 2026
5691eb5
Fix instance hub GraphQL type mismatch on instanceId filter
Emissaryx Aug 3, 2026
f506bb9
Fix blank Average Duration on the instance hub Runs tab
Emissaryx Aug 3, 2026
02b4869
Redesign Instances list as card grid; fix missing title i18n key
Emissaryx Aug 3, 2026
03a7175
Add sortable columns to the instance hub Characters table
Emissaryx Aug 3, 2026
8814798
Fix misplaced sort arrow on Characters table (add is-relative to thead)
Emissaryx Aug 3, 2026
56173da
Add date-range windowed loading to instance hub (24h/7d/30d/90d/YTD/c…
Emissaryx Aug 3, 2026
428f076
Add parseIsoDuration utility for API Duration scalar values
Aug 4, 2026
709a2bd
Fix blank Average Duration and add sortable columns to Instance Runs
Aug 4, 2026
c559143
Fix broken /instance-statistics page
Aug 4, 2026
57672d9
Guard Average Duration against implausible API values
Aug 4, 2026
3c6a6d0
Compute Average Duration from a sampled, outlier-excluded set of runs
Aug 4, 2026
67b2ad3
Cap the duration sample at 50 rows, the API's real page-size ceiling
Aug 4, 2026
833caaa
Remove item-rating filters/columns from Instance pages; unify filter …
Aug 4, 2026
6efe55f
Remove item rating + skull icon from Instance Run detail page
Aug 4, 2026
4ca032b
Add curated instance grouping config
Aug 4, 2026
2c03dfd
Use instance groups in the Instance Runs filter dropdown
Aug 4, 2026
6c4e0b8
Make Instance Hub group-aware; fix Completed/Wiped label
Aug 4, 2026
b9fb253
Make Instance Statistics group-aware
Aug 4, 2026
a314646
Redesign /instances as one page of grouped dungeon cards
Aug 4, 2026
b90c671
Nest named-boss encounters and wiped attempts instead of flat lists
Aug 4, 2026
928239d
Nest wiped boss attempts on the Instance Run detail page
Aug 4, 2026
8ce06e8
Fix remaining deaths-skull icon, breadcrumbs, and sort instances by e…
Aug 4, 2026
ffaae68
Add a Runs column to the Instance Hub Leaderboards tab
Aug 4, 2026
d0b9da8
Remove redundant Home breadcrumb from instance detail pages
Aug 4, 2026
95817d2
Instance Hub: remove Home breadcrumb, add Runs as a Leaderboards metric
Aug 4, 2026
5289fb4
Instance Statistics: hide sub-minute encounter rows
Aug 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/deploy-cloudflare-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Deploy Cloudflare Pages

on:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Install dependencies
run: npm ci

- name: Build site
run: npm run build

- name: Deploy to Cloudflare Pages
run: npx wrangler@4 pages deploy build --project-name=ror-killboard-preview
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"vite": "^8.0.14"
},
"scripts": {
"dev": "vite",
"start": "vite",
"build": "vite build",
"test": "tsc -p . && vite build && oxlint --type-aware src",
Expand Down
1 change: 1 addition & 0 deletions public/_redirects
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* /index.html 200
223 changes: 126 additions & 97 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import './i18n/config';
import React from 'react';
import { Character } from '@/pages/Character';
import { Home } from '@/pages/Home';
import { MainNav } from '@/components/global/MainNav';
import { Kill } from '@/pages/Kill';
import { Guild } from '@/pages/Guild';
import { Search } from '@/pages/Search';
Expand Down Expand Up @@ -31,6 +32,7 @@ import { Storyline } from '@/pages/Storyline';
import { StorylineEntry } from '@/pages/StorylineEntry';
import { StorylineActivity } from '@/pages/StorylineActivity';
import { InstanceStatistics } from '@/pages/InstanceStatistics';
import { InstanceHub } from '@/pages/InstanceHub';

// Extend the Window interface to include gtag
declare global {
Expand All @@ -54,103 +56,130 @@ const App = () => {
usePageViews();

return (
<Routes>
<Route path="/" element={<Home tab="players" />} />
<Route path="/guilds" element={<Home tab="guilds" />} />
<Route path="/scenarios" element={<Home tab="scenarios" />} />
<Route path="/kill/:id" element={<Kill />} />
<Route path="/kills" element={<Kills />} />
<Route path="/character/:id" element={<Character tab="kills" />} />
<Route
path="/character/:id/scenarios"
element={<Character tab="scenarios" />}
/>
<Route
path="/character/:id/skirmishes"
element={<Character tab="skirmishes" />}
/>
<Route
path="/character/:id/armory"
element={<Character tab="armory" />}
/>
<Route
path="/character/:playerId1/feud/:playerId2"
element={<PlayerFeudPage />}
/>

<Route path="/creatures" element={<Creatures />} />
<Route path="/creature/:id" element={<Creature />} />
<Route path="/creature/:id/quests" element={<Creature tab="quests" />} />
<Route
path="/creature/:id/vendorItems"
element={<Creature tab="vendorItems" />}
/>
<Route path="/creature/:id/zone/:zoneId" element={<Creature />} />

<Route path="/gameobject/:id" element={<GameObject />} />
<Route path="/creature/:id/quests" element={<GameObject />} />
<Route path="/creature/:id/zone/:zoneId" element={<GameObject />} />

<Route path="/guild/:id" element={<Guild tab="kills" />} />
<Route path="/guild/:id/members" element={<Guild tab="members" />} />
<Route path="/guild/:id/scenarios" element={<Guild tab="scenarios" />} />
<Route
path="/guild/:id/skirmishes"
element={<Guild tab="skirmishes" />}
/>
<Route
path="/guild/:guildId1/feud/:guildId2"
element={<GuildFeudPage />}
/>

<Route path="/quests" element={<Quests />} />
<Route path="/quest/:id" element={<Quest />} />

<Route path="/search/:query" element={<Search />} />
<Route path="/search/guild/:query" element={<SearchGuild />} />

<Route path="/scenario/:id" element={<Scenario tab="scoreboard" />} />
<Route path="/scenario/:id/kills" element={<Scenario tab="kills" />} />
<Route
path="/scenario/:id/skirmishes"
element={<Scenario tab="skirmishes" />}
/>
<Route path="/scenario/:id/map" element={<Scenario tab="map" />} />
<Route path="/skirmishes" element={<Home tab="skirmishes" />} />
<Route path="/skirmish/:id" element={<Skirmish tab="scoreboard" />} />
<Route path="/skirmish/:id/kills" element={<Skirmish tab="kills" />} />
<Route
path="/skirmish/:id/damage/:characterId"
element={<Skirmish tab="characterDamage" />}
/>
<Route path="/skirmish/:id/damage" element={<Skirmish tab="damage" />} />
<Route path="/zone_heatmap/:id" element={<ZoneMap />} />

<Route path="/items" element={<Items />} />
<Route path="/item/:id" element={<Item tab="vendors" />} />
<Route path="/item/:id/purchase" element={<Item tab="purchase" />} />
<Route path="/item/:id/quests" element={<Item tab="quests" />} />

<Route path="/instance-runs" element={<InstanceRuns />} />
<Route path="/instance-run/:id" element={<InstanceRun />} />
<Route
path="/instance-run/:instanceRunId/:id"
element={<InstanceEncounterRun />}
/>

<Route path="/instances" element={<Instances />} />
<Route path="/instance-statistics/:id" element={<InstanceStatistics />} />

<Route path="/storylines" element={<Storylines />} />
<Route path="/storylines/:id" element={<Storyline />} />
<Route path="/storylines/:storylineId/:id" element={<StorylineEntry />} />
<Route
path="/storylines/:storylineId/:storylineEntryId/:id"
element={<StorylineActivity />}
/>

<Route path="/ranked-leaderboard" element={<RankedLeaderboard />} />
</Routes>
<>
<MainNav />
<Routes>
<Route path="/" element={<Home tab="players" />} />
<Route path="/guilds" element={<Home tab="guilds" />} />
<Route path="/scenarios" element={<Home tab="scenarios" />} />
<Route path="/kill/:id" element={<Kill />} />
<Route path="/kills" element={<Kills />} />
<Route path="/character/:id" element={<Character tab="kills" />} />
<Route
path="/character/:id/scenarios"
element={<Character tab="scenarios" />}
/>
<Route
path="/character/:id/skirmishes"
element={<Character tab="skirmishes" />}
/>
<Route
path="/character/:id/armory"
element={<Character tab="armory" />}
/>
<Route
path="/character/:playerId1/feud/:playerId2"
element={<PlayerFeudPage />}
/>

<Route path="/creatures" element={<Creatures />} />
<Route path="/creature/:id" element={<Creature />} />
<Route
path="/creature/:id/quests"
element={<Creature tab="quests" />}
/>
<Route
path="/creature/:id/vendorItems"
element={<Creature tab="vendorItems" />}
/>
<Route path="/creature/:id/zone/:zoneId" element={<Creature />} />

<Route path="/gameobject/:id" element={<GameObject />} />
<Route path="/creature/:id/quests" element={<GameObject />} />
<Route path="/creature/:id/zone/:zoneId" element={<GameObject />} />

<Route path="/guild/:id" element={<Guild tab="kills" />} />
<Route path="/guild/:id/members" element={<Guild tab="members" />} />
<Route
path="/guild/:id/scenarios"
element={<Guild tab="scenarios" />}
/>
<Route
path="/guild/:id/skirmishes"
element={<Guild tab="skirmishes" />}
/>
<Route
path="/guild/:guildId1/feud/:guildId2"
element={<GuildFeudPage />}
/>

<Route path="/quests" element={<Quests />} />
<Route path="/quest/:id" element={<Quest />} />

<Route path="/search/:query" element={<Search />} />
<Route path="/search/guild/:query" element={<SearchGuild />} />

<Route path="/scenario/:id" element={<Scenario tab="scoreboard" />} />
<Route path="/scenario/:id/kills" element={<Scenario tab="kills" />} />
<Route
path="/scenario/:id/skirmishes"
element={<Scenario tab="skirmishes" />}
/>
<Route path="/scenario/:id/map" element={<Scenario tab="map" />} />
<Route path="/skirmishes" element={<Home tab="skirmishes" />} />
<Route path="/skirmish/:id" element={<Skirmish tab="scoreboard" />} />
<Route path="/skirmish/:id/kills" element={<Skirmish tab="kills" />} />
<Route
path="/skirmish/:id/damage/:characterId"
element={<Skirmish tab="characterDamage" />}
/>
<Route
path="/skirmish/:id/damage"
element={<Skirmish tab="damage" />}
/>
<Route path="/zone_heatmap/:id" element={<ZoneMap />} />

<Route path="/items" element={<Items />} />
<Route path="/item/:id" element={<Item tab="vendors" />} />
<Route path="/item/:id/purchase" element={<Item tab="purchase" />} />
<Route path="/item/:id/quests" element={<Item tab="quests" />} />

<Route path="/instance-runs" element={<InstanceRuns />} />
<Route path="/instance-run/:id" element={<InstanceRun />} />
<Route
path="/instance-run/:instanceRunId/:id"
element={<InstanceEncounterRun />}
/>

<Route path="/instances" element={<Instances />} />
<Route path="/instance/:id" element={<InstanceHub tab="runs" />} />
<Route
path="/instance/:id/characters"
element={<InstanceHub tab="characters" />}
/>
<Route
path="/instance/:id/leaderboards"
element={<InstanceHub tab="leaderboards" />}
/>
<Route
path="/instance-statistics/:id"
element={<InstanceStatistics />}
/>

<Route path="/storylines" element={<Storylines />} />
<Route path="/storylines/:id" element={<Storyline />} />
<Route
path="/storylines/:storylineId/:id"
element={<StorylineEntry />}
/>
<Route
path="/storylines/:storylineId/:storylineEntryId/:id"
element={<StorylineActivity />}
/>

<Route path="/ranked-leaderboard" element={<RankedLeaderboard />} />
</Routes>
</>
);
};

Expand Down
13 changes: 7 additions & 6 deletions src/components/WarIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ReactElement } from 'react';
import { assetUrl } from '@/utils';

export const WarIcon = ({
icon,
Expand All @@ -19,18 +20,18 @@ export const WarIcon = ({
switch (frameType) {
case 'circle': {
return selected
? '/images/icons/round_frame_press.png'
: '/images/icons/round_frame.png';
? assetUrl('/images/icons/round_frame_press.png')
: assetUrl('/images/icons/round_frame.png');
}
case 'hex': {
return selected
? '/images/icons/hex_frame_press.png'
: '/images/icons/hex_frame.png';
? assetUrl('/images/icons/hex_frame_press.png')
: assetUrl('/images/icons/hex_frame.png');
}
default: {
return selected
? '/images/icons/square_frame_press.png'
: '/images/icons/square_frame.png';
? assetUrl('/images/icons/square_frame_press.png')
: assetUrl('/images/icons/square_frame.png');
}
}
})();
Expand Down
2 changes: 1 addition & 1 deletion src/components/ZoneHeatmap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const ZoneHeatmap = ({
zoneId,
max,
data,
size = 640,
size,
}: {
zoneId: string;
max: number;
Expand Down
Loading