@oddsmith/ui 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eleventy.cjs +14 -0
- package/LICENSE +28 -0
- package/README.md +118 -0
- package/custom-elements.json +1539 -0
- package/docs/_README/index.html +4 -0
- package/docs/api/index.html +2100 -0
- package/docs/components.bundle.js +1669 -0
- package/docs/components.bundle.js.map +1 -0
- package/docs/docs.css +162 -0
- package/docs/examples/index.html +56 -0
- package/docs/index.html +53 -0
- package/docs/install/index.html +45 -0
- package/docs/prism-okaidia.css +123 -0
- package/docs-src/.nojekyll +0 -0
- package/docs-src/_README.md +7 -0
- package/docs-src/_data/api.11tydata.js +8 -0
- package/docs-src/_includes/example.11ty.js +35 -0
- package/docs-src/_includes/footer.11ty.js +6 -0
- package/docs-src/_includes/header.11ty.js +7 -0
- package/docs-src/_includes/nav.11ty.js +11 -0
- package/docs-src/_includes/page.11ty.js +32 -0
- package/docs-src/_includes/relative-path.cjs +9 -0
- package/docs-src/api.11ty.js +85 -0
- package/docs-src/bundle.ts +9 -0
- package/docs-src/docs.css +162 -0
- package/docs-src/examples/index.md +15 -0
- package/docs-src/index.md +39 -0
- package/docs-src/install.md +28 -0
- package/docs-src/package.json +3 -0
- package/index.html +19 -0
- package/karma.conf.cjs +24 -0
- package/main.css +210 -0
- package/main.ts +124 -0
- package/package.json +86 -0
- package/previews/casino.ts +12 -0
- package/previews/catalog.ts +94 -0
- package/previews/leaderboard-v1.ts +12 -0
- package/previews/leaderboard-v2.ts +17 -0
- package/previews/sample-data.ts +101 -0
- package/previews/sf-leaderboard.ts +100 -0
- package/previews/sf-live-feed.ts +15 -0
- package/previews/streaks.ts +40 -0
- package/previews/types.ts +18 -0
- package/src/components/README.md +16 -0
- package/src/components/casino-leaderboard/casino-leaderboard.html +80 -0
- package/src/components/casino-leaderboard/casino-leaderboard.scss +585 -0
- package/src/components/casino-leaderboard/casino-leaderboard.ts +136 -0
- package/src/components/casino-leaderboard/data.ts +111 -0
- package/src/components/casino-leaderboard/index.ts +5 -0
- package/src/components/casino-leaderboard/todo.txt +2 -0
- package/src/components/casino-leaderboard/types.ts +19 -0
- package/src/components/leaderboard/components/leaderboard.ts +373 -0
- package/src/components/leaderboard/components/player-card.ts +342 -0
- package/src/components/leaderboard/components/ui.ts +452 -0
- package/src/components/leaderboard/data.ts +152 -0
- package/src/components/leaderboard/index.ts +2 -0
- package/src/components/leaderboard/main.ts +42 -0
- package/src/components/leaderboard/styles.ts +67 -0
- package/src/components/leaderboard/types.ts +28 -0
- package/src/components/leaderboard-v2/components/sf-leaderboard-player.ts +451 -0
- package/src/components/leaderboard-v2/components/sf-leaderboard-ui.ts +512 -0
- package/src/components/leaderboard-v2/components/sf-leaderboard.ts +205 -0
- package/src/components/leaderboard-v2/constants.ts +16 -0
- package/src/components/leaderboard-v2/demo/sample-data.ts +152 -0
- package/src/components/leaderboard-v2/events.ts +13 -0
- package/src/components/leaderboard-v2/icons.ts +22 -0
- package/src/components/leaderboard-v2/index.ts +23 -0
- package/src/components/leaderboard-v2/sf-leaderboard.html +1 -0
- package/src/components/leaderboard-v2/sf-leaderboard.scss +382 -0
- package/src/components/leaderboard-v2/tokens.ts +35 -0
- package/src/components/leaderboard-v2/types.ts +30 -0
- package/src/components/sf-leaderboard/index.ts +77 -0
- package/src/components/sf-leaderboard/sections/footer-section/footer-section.host.ts +3 -0
- package/src/components/sf-leaderboard/sections/footer-section/footer-section.html +3 -0
- package/src/components/sf-leaderboard/sections/footer-section/footer-section.scss +18 -0
- package/src/components/sf-leaderboard/sections/footer-section/footer-section.ts +22 -0
- package/src/components/sf-leaderboard/sections/header-section/header-section.host.ts +14 -0
- package/src/components/sf-leaderboard/sections/header-section/header-section.html +27 -0
- package/src/components/sf-leaderboard/sections/header-section/header-section.scss +189 -0
- package/src/components/sf-leaderboard/sections/header-section/header-section.ts +70 -0
- package/src/components/sf-leaderboard/sections/ranking-section/ranking-section.host.ts +22 -0
- package/src/components/sf-leaderboard/sections/ranking-section/ranking-section.html +38 -0
- package/src/components/sf-leaderboard/sections/ranking-section/ranking-section.scss +99 -0
- package/src/components/sf-leaderboard/sections/ranking-section/ranking-section.ts +121 -0
- package/src/components/sf-leaderboard/sections/stats-section/stats-section.host.ts +8 -0
- package/src/components/sf-leaderboard/sections/stats-section/stats-section.html +6 -0
- package/src/components/sf-leaderboard/sections/stats-section/stats-section.scss +44 -0
- package/src/components/sf-leaderboard/sections/stats-section/stats-section.ts +41 -0
- package/src/components/sf-leaderboard/sections/table-section/table-section.host.ts +17 -0
- package/src/components/sf-leaderboard/sections/table-section/table-section.html +19 -0
- package/src/components/sf-leaderboard/sections/table-section/table-section.scss +37 -0
- package/src/components/sf-leaderboard/sections/table-section/table-section.ts +108 -0
- package/src/components/sf-leaderboard/services/index.ts +22 -0
- package/src/components/sf-leaderboard/services/sf-leaderboard-data.service.ts +54 -0
- package/src/components/sf-leaderboard/services/sf-leaderboard.state.ts +160 -0
- package/src/components/sf-leaderboard/shared/components/activity-feed/activity-feed.host.ts +7 -0
- package/src/components/sf-leaderboard/shared/components/activity-feed/activity-feed.html +10 -0
- package/src/components/sf-leaderboard/shared/components/activity-feed/activity-feed.scss +180 -0
- package/src/components/sf-leaderboard/shared/components/activity-feed/activity-feed.ts +88 -0
- package/src/components/sf-leaderboard/shared/components/filters/filters.host.ts +12 -0
- package/src/components/sf-leaderboard/shared/components/filters/filters.html +22 -0
- package/src/components/sf-leaderboard/shared/components/filters/filters.scss +122 -0
- package/src/components/sf-leaderboard/shared/components/filters/filters.ts +75 -0
- package/src/components/sf-leaderboard/shared/components/player-avatar/player-avatar.host.ts +9 -0
- package/src/components/sf-leaderboard/shared/components/player-avatar/player-avatar.html +5 -0
- package/src/components/sf-leaderboard/shared/components/player-avatar/player-avatar.scss +81 -0
- package/src/components/sf-leaderboard/shared/components/player-avatar/player-avatar.ts +34 -0
- package/src/components/sf-leaderboard/shared/components/podium/map-players.ts +24 -0
- package/src/components/sf-leaderboard/shared/components/podium/podium.host.ts +10 -0
- package/src/components/sf-leaderboard/shared/components/podium/podium.html +53 -0
- package/src/components/sf-leaderboard/shared/components/podium/podium.scss +580 -0
- package/src/components/sf-leaderboard/shared/components/podium/podium.ts +49 -0
- package/src/components/sf-leaderboard/shared/components/podium/podium.types.ts +9 -0
- package/src/components/sf-leaderboard/shared/components/rank-badge/rank-badge.host.ts +11 -0
- package/src/components/sf-leaderboard/shared/components/rank-badge/rank-badge.html +9 -0
- package/src/components/sf-leaderboard/shared/components/rank-badge/rank-badge.scss +98 -0
- package/src/components/sf-leaderboard/shared/components/rank-badge/rank-badge.ts +63 -0
- package/src/components/sf-leaderboard/shared/components/stat-card/stat-card.host.ts +9 -0
- package/src/components/sf-leaderboard/shared/components/stat-card/stat-card.html +15 -0
- package/src/components/sf-leaderboard/shared/components/stat-card/stat-card.scss +210 -0
- package/src/components/sf-leaderboard/shared/components/stat-card/stat-card.ts +36 -0
- package/src/components/sf-leaderboard/shared/components/table/table.host.ts +5 -0
- package/src/components/sf-leaderboard/shared/components/table/table.html +11 -0
- package/src/components/sf-leaderboard/shared/components/table/table.scss +212 -0
- package/src/components/sf-leaderboard/shared/components/table/table.ts +111 -0
- package/src/components/sf-leaderboard/shared/constants/defaults.ts +7 -0
- package/src/components/sf-leaderboard/shared/constants/filters.ts +16 -0
- package/src/components/sf-leaderboard/shared/constants/index.ts +5 -0
- package/src/components/sf-leaderboard/shared/constants/player-stats.ts +3 -0
- package/src/components/sf-leaderboard/shared/constants/stats-overview.ts +38 -0
- package/src/components/sf-leaderboard/shared/constants/tags.ts +16 -0
- package/src/components/sf-leaderboard/shared/styles/_section.scss +35 -0
- package/src/components/sf-leaderboard/shared/types/data.ts +29 -0
- package/src/components/sf-leaderboard/shared/types/events.ts +30 -0
- package/src/components/sf-leaderboard/shared/types/player-stats.ts +3 -0
- package/src/components/sf-leaderboard/shared/types/sections.ts +100 -0
- package/src/components/sf-leaderboard/shared/utils/utils.ts +17 -0
- package/src/components/sf-leaderboard/theme/THEMING.md +54 -0
- package/src/components/sf-leaderboard/theme/context.ts +16 -0
- package/src/components/sf-leaderboard/theme/default-theme.ts +4 -0
- package/src/components/sf-leaderboard/theme/hex-to-rgb.ts +25 -0
- package/src/components/sf-leaderboard/theme/index.ts +18 -0
- package/src/components/sf-leaderboard/theme/inject-theme.ts +39 -0
- package/src/components/sf-leaderboard/theme/load-theme.ts +26 -0
- package/src/components/sf-leaderboard/theme/merge-theme.ts +59 -0
- package/src/components/sf-leaderboard/theme/scss/_colors.scss +101 -0
- package/src/components/sf-leaderboard/theme/scss/shared.scss +123 -0
- package/src/components/sf-leaderboard/theme/styles.ts +6 -0
- package/src/components/sf-leaderboard/theme/theme-to-css-vars.ts +99 -0
- package/src/components/sf-leaderboard/theme/themes/fallback.json +62 -0
- package/src/components/sf-leaderboard/theme/themes/red.json +62 -0
- package/src/components/sf-leaderboard/theme/types.ts +71 -0
- package/src/components/sf-live-feed/components/avatar/avatar.host.ts +5 -0
- package/src/components/sf-live-feed/components/avatar/avatar.html +3 -0
- package/src/components/sf-live-feed/components/avatar/avatar.scss +24 -0
- package/src/components/sf-live-feed/components/avatar/avatar.ts +27 -0
- package/src/components/sf-live-feed/components/sf-live-feed/sf-live-feed.host.ts +8 -0
- package/src/components/sf-live-feed/components/sf-live-feed/sf-live-feed.html +10 -0
- package/src/components/sf-live-feed/components/sf-live-feed/sf-live-feed.scss +177 -0
- package/src/components/sf-live-feed/components/sf-live-feed/sf-live-feed.ts +65 -0
- package/src/components/sf-live-feed/constants.ts +4 -0
- package/src/components/sf-live-feed/demo/sample-data.ts +34 -0
- package/src/components/sf-live-feed/index.ts +19 -0
- package/src/components/sf-live-feed/styles/theme.scss +19 -0
- package/src/components/sf-live-feed/styles/theme.ts +5 -0
- package/src/components/sf-live-feed/types.ts +19 -0
- package/src/components/sf-live-feed/utils.ts +17 -0
- package/src/components/streaks/constants.ts +17 -0
- package/src/components/streaks/demo/sample-steps.ts +10 -0
- package/src/components/streaks/events.ts +8 -0
- package/src/components/streaks/index.ts +16 -0
- package/src/components/streaks/sf-streaks.html +26 -0
- package/src/components/streaks/sf-streaks.scss +351 -0
- package/src/components/streaks/sf-streaks.ts +235 -0
- package/src/components/streaks/types.ts +7 -0
- package/src/lib/lit/component.ts +10 -0
- package/src/lib/lit/safe-custom-element.ts +12 -0
- package/src/lib/lit/scss.ts +6 -0
- package/src/vite-env.d.ts +18 -0
- package/styles/global.css +125 -0
- package/todo.txt +54 -0
- package/tsconfig.json +31 -0
- package/vite.config.ts +56 -0
- package/vite.docs.config.ts +33 -0
- package/vite.lit-html-plugin.ts +43 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sf Leaderboard — public API.
|
|
3
|
+
* Import: `import '@skinforge/sf-leaderboard'`
|
|
4
|
+
*/
|
|
5
|
+
export type {
|
|
6
|
+
Player,
|
|
7
|
+
Activity,
|
|
8
|
+
TimeFrame,
|
|
9
|
+
Category,
|
|
10
|
+
} from './shared/types/data.js';
|
|
11
|
+
export type {
|
|
12
|
+
SfLeaderboardLayout,
|
|
13
|
+
SfLeaderboardHeaderSection,
|
|
14
|
+
SfLeaderboardStatsSection,
|
|
15
|
+
SfLeaderboardStatItem,
|
|
16
|
+
SfLeaderboardRankingSection,
|
|
17
|
+
SfLeaderboardPodiumSection,
|
|
18
|
+
SfLeaderboardPlayerStatsSection,
|
|
19
|
+
SfLeaderboardTableSection,
|
|
20
|
+
SfLeaderboardTableFiltersSection,
|
|
21
|
+
} from './shared/types/sections.js';
|
|
22
|
+
/** @deprecated Use `SfLeaderboardStatItem` */
|
|
23
|
+
export type { SfLeaderboardOverviewStat } from './shared/constants/stats-overview.js';
|
|
24
|
+
export type {
|
|
25
|
+
SfLeaderboardState,
|
|
26
|
+
SfLeaderboardConfig,
|
|
27
|
+
SfLeaderboardLabels,
|
|
28
|
+
SfLeaderboardSectionData,
|
|
29
|
+
SfLeaderboardSectionId,
|
|
30
|
+
SfLeaderboardSectionEntry,
|
|
31
|
+
SfLeaderboardSectionPayloadMap,
|
|
32
|
+
SfLeaderboardSectionPatch,
|
|
33
|
+
/** @deprecated Use `SfLeaderboardState` */
|
|
34
|
+
SfLeaderboardData,
|
|
35
|
+
} from './services/index.js';
|
|
36
|
+
export {
|
|
37
|
+
EMPTY_SF_LEADERBOARD_STATE,
|
|
38
|
+
applySectionPatch,
|
|
39
|
+
getSectionData,
|
|
40
|
+
hasSection,
|
|
41
|
+
patchSectionData,
|
|
42
|
+
sectionEntry,
|
|
43
|
+
updateSections,
|
|
44
|
+
} from './services/index.js';
|
|
45
|
+
export * from './shared/constants/index.js';
|
|
46
|
+
export * from './shared/types/events.js';
|
|
47
|
+
export { sfLeaderboardDataService } from './services/index.js';
|
|
48
|
+
export { Component, type ComponentOptions } from '../../lib/lit/component.js';
|
|
49
|
+
export { SfLeaderboard } from './sf-leaderboard.js';
|
|
50
|
+
export { SfLeaderboardHeaderBlock } from './sections/header-section/header-section.js';
|
|
51
|
+
export { SfLeaderboardStatsBlock } from './sections/stats-section/stats-section.js';
|
|
52
|
+
export { SfLeaderboardRankingBlock } from './sections/ranking-section/ranking-section.js';
|
|
53
|
+
export { SfLeaderboardTableBlock } from './sections/table-section/table-section.js';
|
|
54
|
+
export { SfLeaderboardFooterBlock } from './sections/footer-section/footer-section.js';
|
|
55
|
+
export { SfLeaderboardPlayerStatsCard } from './shared/components/player-stats-card/player-stats-card.js';
|
|
56
|
+
export { SfLeaderboardStatCard } from './shared/components/stat-card/stat-card.js';
|
|
57
|
+
export { SfLeaderboardPodium } from './shared/components/podium/podium.js';
|
|
58
|
+
|
|
59
|
+
export type {
|
|
60
|
+
SfLeaderboardTheme,
|
|
61
|
+
SfLeaderboardPlacementTheme,
|
|
62
|
+
SfLeaderboardTableColumnTheme,
|
|
63
|
+
TableColumnId,
|
|
64
|
+
} from './theme/index.js';
|
|
65
|
+
export {
|
|
66
|
+
sfLeaderboardTheme,
|
|
67
|
+
loadThemeFromJson,
|
|
68
|
+
parseThemeJson,
|
|
69
|
+
injectTheme,
|
|
70
|
+
clearTheme,
|
|
71
|
+
getThemeLabel,
|
|
72
|
+
mergeSfLeaderboardTheme,
|
|
73
|
+
themeToCssVars,
|
|
74
|
+
DEFAULT_SF_LEADERBOARD_THEME,
|
|
75
|
+
} from './theme/index.js';
|
|
76
|
+
|
|
77
|
+
import './sf-leaderboard.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: block;
|
|
3
|
+
width: 100%;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.page-footer {
|
|
7
|
+
border-top: 1px solid var(--border);
|
|
8
|
+
margin-top: clamp(1.5rem, 4vw, 3rem);
|
|
9
|
+
padding-top: 1rem;
|
|
10
|
+
width: 100%;
|
|
11
|
+
|
|
12
|
+
p {
|
|
13
|
+
margin: 0;
|
|
14
|
+
text-align: center;
|
|
15
|
+
font-size: 0.875rem;
|
|
16
|
+
color: var(--muted-foreground);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { LitElement, nothing } from 'lit';
|
|
2
|
+
import { property } from 'lit/decorators.js';
|
|
3
|
+
import { Component } from '../../../../../lib/lit/component.js';
|
|
4
|
+
import { scss } from '../../../../../lib/lit/scss.js';
|
|
5
|
+
import { SF_LEADERBOARD_FOOTER_SECTION } from '../../shared/constants/tags.js';
|
|
6
|
+
import { sfLeaderboardTheme } from '../../theme/styles.js';
|
|
7
|
+
import type { FooterSectionHost } from './footer-section.host.js';
|
|
8
|
+
import renderTemplate from './footer-section.html?lit-html';
|
|
9
|
+
import styles from './footer-section.scss?inline';
|
|
10
|
+
|
|
11
|
+
@Component({ selector: SF_LEADERBOARD_FOOTER_SECTION })
|
|
12
|
+
export class SfLeaderboardFooterBlock extends LitElement implements FooterSectionHost {
|
|
13
|
+
static styles = [sfLeaderboardTheme, scss(styles)];
|
|
14
|
+
|
|
15
|
+
@property({ type: String })
|
|
16
|
+
text = '';
|
|
17
|
+
|
|
18
|
+
render() {
|
|
19
|
+
if (!this.text) return nothing;
|
|
20
|
+
return renderTemplate(this);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SfLeaderboardRefreshDetail } from '../../shared/types/events.js';
|
|
2
|
+
import type { SfLeaderboardHeaderSection } from '../../shared/types/sections.js';
|
|
3
|
+
|
|
4
|
+
export interface HeaderSectionHost {
|
|
5
|
+
section: SfLeaderboardHeaderSection;
|
|
6
|
+
refreshContext?: SfLeaderboardRefreshDetail;
|
|
7
|
+
showIcon: boolean;
|
|
8
|
+
showSubtitle: boolean;
|
|
9
|
+
showLive: boolean;
|
|
10
|
+
showBack: boolean;
|
|
11
|
+
backLabel: string;
|
|
12
|
+
isRefreshing: boolean;
|
|
13
|
+
onBackClick(): void;
|
|
14
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<header class="header">
|
|
2
|
+
<div class="header-content">
|
|
3
|
+
<div class="logo-section">
|
|
4
|
+
<div class="logo-icon" ?hidden="${!host.showIcon}">${host.section.icon}</div>
|
|
5
|
+
<div class="logo-text">
|
|
6
|
+
<h1>${host.section.title}</h1>
|
|
7
|
+
<p ?hidden="${!host.showSubtitle}">${host.section.subtitle}</p>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<div class="header-actions">
|
|
12
|
+
<div class="live-badge" ?hidden="${!host.showLive}">
|
|
13
|
+
<span class="live-dot"></span>
|
|
14
|
+
Live
|
|
15
|
+
</div>
|
|
16
|
+
<button
|
|
17
|
+
type="button"
|
|
18
|
+
class="back-btn ${host.isRefreshing ? 'refreshing' : ''}"
|
|
19
|
+
?hidden="${!host.showBack}"
|
|
20
|
+
@click="${host.onBackClick}"
|
|
21
|
+
>
|
|
22
|
+
<span class="icon" aria-hidden="true">←</span>
|
|
23
|
+
${host.backLabel}
|
|
24
|
+
</button>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</header>
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: block;
|
|
3
|
+
width: 100%;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.header {
|
|
7
|
+
position: sticky;
|
|
8
|
+
top: 0;
|
|
9
|
+
z-index: 50;
|
|
10
|
+
backdrop-filter: blur(16px);
|
|
11
|
+
background: color-mix(in srgb, var(--background) 82%, transparent);
|
|
12
|
+
padding: 12px 0;
|
|
13
|
+
border-bottom: 1px solid var(--border);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.header-content {
|
|
17
|
+
width: 100%;
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: space-between;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.logo-section {
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
gap: 0.75rem;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.logo-icon {
|
|
30
|
+
width: 40px;
|
|
31
|
+
height: 40px;
|
|
32
|
+
border-radius: var(--radius);
|
|
33
|
+
background: var(--accent-soft);
|
|
34
|
+
border: 1px solid var(--surface-border-color);
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
justify-content: center;
|
|
38
|
+
font-size: 1.25rem;
|
|
39
|
+
box-shadow: var(--surface-shadow-hover);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.logo-text h1 {
|
|
43
|
+
font-size: 1.25rem;
|
|
44
|
+
font-weight: 700;
|
|
45
|
+
margin: 0;
|
|
46
|
+
text-shadow: var(--accent-text-glow);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.logo-text p {
|
|
50
|
+
font-size: 0.75rem;
|
|
51
|
+
color: var(--muted-foreground);
|
|
52
|
+
margin: 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.header-actions {
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
gap: 0.75rem;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.live-badge {
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
gap: 0.5rem;
|
|
65
|
+
padding: 0.375rem 0.75rem;
|
|
66
|
+
border-radius: 9999px;
|
|
67
|
+
border: 1px solid rgba(var(--success-rgb), 0.35);
|
|
68
|
+
background: rgba(var(--success-rgb), 0.08);
|
|
69
|
+
font-size: 0.75rem;
|
|
70
|
+
font-weight: 500;
|
|
71
|
+
color: var(--success);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.live-dot {
|
|
75
|
+
position: relative;
|
|
76
|
+
width: 8px;
|
|
77
|
+
height: 8px;
|
|
78
|
+
background: var(--success);
|
|
79
|
+
border-radius: 50%;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.live-dot::before {
|
|
83
|
+
content: '';
|
|
84
|
+
position: absolute;
|
|
85
|
+
inset: 0;
|
|
86
|
+
border-radius: 50%;
|
|
87
|
+
background: var(--success);
|
|
88
|
+
animation: ping 1.5s ease-out infinite;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@keyframes ping {
|
|
92
|
+
0% {
|
|
93
|
+
transform: scale(1);
|
|
94
|
+
opacity: 1;
|
|
95
|
+
}
|
|
96
|
+
100% {
|
|
97
|
+
transform: scale(2.5);
|
|
98
|
+
opacity: 0;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.back-btn {
|
|
103
|
+
display: flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
gap: 0.5rem;
|
|
106
|
+
padding: 0.5rem 1rem;
|
|
107
|
+
border-radius: var(--radius-sm);
|
|
108
|
+
border: 1px solid var(--surface-border-color);
|
|
109
|
+
background: var(--surface-gradient);
|
|
110
|
+
color: var(--foreground);
|
|
111
|
+
font-size: 0.875rem;
|
|
112
|
+
font-family: inherit;
|
|
113
|
+
cursor: pointer;
|
|
114
|
+
box-shadow: var(--surface-shadow);
|
|
115
|
+
transition: border-color var(--transition-fast),
|
|
116
|
+
box-shadow var(--transition-fast);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.back-btn:hover {
|
|
120
|
+
border-color: var(--surface-border-hover);
|
|
121
|
+
box-shadow: var(--surface-shadow-hover);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.back-btn .icon {
|
|
125
|
+
transition: transform 0.3s ease;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.back-btn.refreshing .icon {
|
|
129
|
+
animation: spin 1s linear infinite;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@keyframes spin {
|
|
133
|
+
from {
|
|
134
|
+
transform: rotate(0deg);
|
|
135
|
+
}
|
|
136
|
+
to {
|
|
137
|
+
transform: rotate(360deg);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@media (max-width: 639px) {
|
|
142
|
+
.header-content {
|
|
143
|
+
flex-wrap: wrap;
|
|
144
|
+
gap: 0.75rem;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.logo-section {
|
|
148
|
+
flex: 1 1 100%;
|
|
149
|
+
justify-content: center;
|
|
150
|
+
align-items: center;
|
|
151
|
+
gap: 0.5rem;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.logo-icon {
|
|
155
|
+
width: clamp(32px, 9vw, 40px);
|
|
156
|
+
height: clamp(32px, 9vw, 40px);
|
|
157
|
+
font-size: clamp(1rem, 4vw, 1.25rem);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.logo-text {
|
|
161
|
+
text-align: center;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.logo-text h1 {
|
|
165
|
+
text-align: center;
|
|
166
|
+
font-size: clamp(1rem, 4.5vw, 1.25rem);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.logo-text p {
|
|
170
|
+
display: none;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.header-actions {
|
|
174
|
+
width: 100%;
|
|
175
|
+
justify-content: space-between;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.back-btn {
|
|
179
|
+
padding: 0.5rem 0.75rem;
|
|
180
|
+
font-size: 0.8125rem;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@media (max-width: 380px) {
|
|
185
|
+
.live-badge {
|
|
186
|
+
font-size: 0.6875rem;
|
|
187
|
+
padding: 0.3rem 0.6rem;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { LitElement, nothing } from 'lit';
|
|
2
|
+
import { property } from 'lit/decorators.js';
|
|
3
|
+
import { Component } from '../../../../../lib/lit/component.js';
|
|
4
|
+
import { scss } from '../../../../../lib/lit/scss.js';
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_CATEGORY,
|
|
7
|
+
DEFAULT_TIMEFRAME,
|
|
8
|
+
SF_LEADERBOARD_HEADER_SECTION,
|
|
9
|
+
} from '../../shared/constants/index.js';
|
|
10
|
+
import { sfLeaderboardTheme } from '../../theme/styles.js';
|
|
11
|
+
import { SF_LEADERBOARD_REFRESH } from '../../shared/types/events.js';
|
|
12
|
+
import type { SfLeaderboardRefreshDetail } from '../../shared/types/events.js';
|
|
13
|
+
import type { SfLeaderboardHeaderSection as HeaderSectionData } from '../../shared/types/sections.js';
|
|
14
|
+
import type { HeaderSectionHost } from './header-section.host.js';
|
|
15
|
+
import renderTemplate from './header-section.html?lit-html';
|
|
16
|
+
import styles from './header-section.scss?inline';
|
|
17
|
+
|
|
18
|
+
@Component({ selector: SF_LEADERBOARD_HEADER_SECTION })
|
|
19
|
+
export class SfLeaderboardHeaderBlock extends LitElement implements HeaderSectionHost {
|
|
20
|
+
static styles = [sfLeaderboardTheme, scss(styles)];
|
|
21
|
+
|
|
22
|
+
@property({ attribute: false })
|
|
23
|
+
section!: HeaderSectionData;
|
|
24
|
+
|
|
25
|
+
@property({ attribute: false })
|
|
26
|
+
refreshContext?: SfLeaderboardRefreshDetail;
|
|
27
|
+
|
|
28
|
+
get showIcon(): boolean {
|
|
29
|
+
return Boolean(this.section?.icon);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get showSubtitle(): boolean {
|
|
33
|
+
return Boolean(this.section?.subtitle);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get showLive(): boolean {
|
|
37
|
+
return Boolean(this.section?.showLive);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get showBack(): boolean {
|
|
41
|
+
return this.section?.backButton != null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get backLabel(): string {
|
|
45
|
+
return this.section?.backButton?.label ?? 'Back';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get isRefreshing(): boolean {
|
|
49
|
+
return this.section?.isRefreshing ?? false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
onBackClick() {
|
|
53
|
+
const ctx = this.refreshContext;
|
|
54
|
+
this.dispatchEvent(
|
|
55
|
+
new CustomEvent(SF_LEADERBOARD_REFRESH, {
|
|
56
|
+
detail: {
|
|
57
|
+
timeframe: ctx?.timeframe ?? DEFAULT_TIMEFRAME,
|
|
58
|
+
category: ctx?.category ?? DEFAULT_CATEGORY,
|
|
59
|
+
},
|
|
60
|
+
bubbles: true,
|
|
61
|
+
composed: true,
|
|
62
|
+
}),
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
render() {
|
|
67
|
+
if (!this.section) return nothing;
|
|
68
|
+
return renderTemplate(this);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Player } from '../../shared/types/data.js';
|
|
2
|
+
import type { SfLeaderboardRankingSection } from '../../shared/types/sections.js';
|
|
3
|
+
|
|
4
|
+
export interface RankingSectionHost {
|
|
5
|
+
ranking: SfLeaderboardRankingSection;
|
|
6
|
+
hasPair: boolean;
|
|
7
|
+
hasPodium: boolean;
|
|
8
|
+
hasPlayerStats: boolean;
|
|
9
|
+
podiumTitle: string;
|
|
10
|
+
podiumBadge: string;
|
|
11
|
+
showPodiumBadge: boolean;
|
|
12
|
+
podiumPlayers: Player[];
|
|
13
|
+
playerStatsTitle: string;
|
|
14
|
+
playerStatsRank: number;
|
|
15
|
+
playerStatsPercentile: number;
|
|
16
|
+
playerStatsUsername: string;
|
|
17
|
+
playerStatsEarnings: string;
|
|
18
|
+
playerStatsWinRate: number;
|
|
19
|
+
playerStatsGamesPlayed: number;
|
|
20
|
+
playerStatsWinStreak: number;
|
|
21
|
+
playerStatsLevel: number;
|
|
22
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<section class="section ranking-section">
|
|
2
|
+
<div class="ranking-grid ${host.hasPair ? 'has-pair' : 'single'}">
|
|
3
|
+
<div
|
|
4
|
+
class="ranking-column ranking-column--podium"
|
|
5
|
+
?hidden="${!host.hasPodium}"
|
|
6
|
+
>
|
|
7
|
+
<div class="section-header">
|
|
8
|
+
<h2 class="section-title">${host.podiumTitle}</h2>
|
|
9
|
+
<span class="elite-badge" ?hidden="${!host.showPodiumBadge}"
|
|
10
|
+
>${host.podiumBadge}</span
|
|
11
|
+
>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="podium-slot">
|
|
14
|
+
<sf-leaderboard-podium
|
|
15
|
+
.players="${host.podiumPlayers}"
|
|
16
|
+
></sf-leaderboard-podium>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
<div
|
|
20
|
+
class="ranking-column ranking-column--player-stats"
|
|
21
|
+
?hidden="${!host.hasPlayerStats}"
|
|
22
|
+
>
|
|
23
|
+
<div class="section-header">
|
|
24
|
+
<h2 class="section-title">${host.playerStatsTitle}</h2>
|
|
25
|
+
</div>
|
|
26
|
+
<sf-leaderboard-player-stats-card
|
|
27
|
+
rank="${host.playerStatsRank}"
|
|
28
|
+
percentile="${host.playerStatsPercentile}"
|
|
29
|
+
username="${host.playerStatsUsername}"
|
|
30
|
+
earnings="${host.playerStatsEarnings}"
|
|
31
|
+
winRate="${host.playerStatsWinRate}"
|
|
32
|
+
gamesPlayed="${host.playerStatsGamesPlayed}"
|
|
33
|
+
winStreak="${host.playerStatsWinStreak}"
|
|
34
|
+
level="${host.playerStatsLevel}"
|
|
35
|
+
></sf-leaderboard-player-stats-card>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</section>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
@use '../../shared/styles/section';
|
|
2
|
+
|
|
3
|
+
:host {
|
|
4
|
+
display: block;
|
|
5
|
+
width: 100%;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.ranking-section {
|
|
9
|
+
--ranking-podium-min-h: clamp(300px, min(36vh, 36dvh), 420px);
|
|
10
|
+
--ranking-player-stats-min-h: clamp(300px, min(36vh, 36dvh), 420px);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.ranking-grid {
|
|
14
|
+
display: grid;
|
|
15
|
+
grid-template-columns: 1fr;
|
|
16
|
+
gap: clamp(0.75rem, 2vw, 1rem);
|
|
17
|
+
width: 100%;
|
|
18
|
+
align-items: stretch;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.ranking-grid.has-pair {
|
|
22
|
+
@media (min-width: 1080px) {
|
|
23
|
+
grid-template-columns: minmax(0, 1.38fr) minmax(0, 0.82fr);
|
|
24
|
+
min-height: var(--ranking-podium-min-h);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.ranking-column {
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
min-width: 0;
|
|
32
|
+
min-height: 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.ranking-column--player-stats {
|
|
36
|
+
min-height: var(--ranking-player-stats-min-h);
|
|
37
|
+
|
|
38
|
+
sf-leaderboard-player-stats-card {
|
|
39
|
+
flex: 1 1 auto;
|
|
40
|
+
width: 100%;
|
|
41
|
+
min-height: 0;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.podium-slot {
|
|
46
|
+
display: flex;
|
|
47
|
+
flex: 1 1 auto;
|
|
48
|
+
min-width: 0;
|
|
49
|
+
min-height: var(--ranking-podium-min-h);
|
|
50
|
+
overflow: hidden;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.podium-slot > sf-leaderboard-podium {
|
|
54
|
+
flex: 1 1 auto;
|
|
55
|
+
width: 100%;
|
|
56
|
+
height: 100%;
|
|
57
|
+
min-height: 100%;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@media (max-width: 1079px) {
|
|
61
|
+
.ranking-section {
|
|
62
|
+
--ranking-podium-min-h: clamp(280px, min(38vh, 38dvh), 400px);
|
|
63
|
+
--ranking-player-stats-min-h: clamp(280px, min(34vh, 34dvh), 360px);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@media (min-width: 677px) and (max-width: 1079px) {
|
|
68
|
+
.ranking-section {
|
|
69
|
+
--ranking-player-stats-min-h: clamp(360px, min(42vh, 42dvh), 440px);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@media (max-width: 676px) {
|
|
74
|
+
.ranking-column--player-stats {
|
|
75
|
+
min-height: 0;
|
|
76
|
+
height: auto;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@media (min-width: 1280px) {
|
|
81
|
+
.ranking-section {
|
|
82
|
+
--ranking-podium-min-h: clamp(340px, min(38vh, 38dvh), 460px);
|
|
83
|
+
--ranking-player-stats-min-h: clamp(340px, min(38vh, 38dvh), 460px);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@media (max-width: 639px) {
|
|
88
|
+
.ranking-section {
|
|
89
|
+
--ranking-podium-min-h: clamp(280px, min(44dvh, 46vh), 360px);
|
|
90
|
+
--ranking-player-stats-min-h: clamp(240px, min(34dvh, 36vh), 288px);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@media (max-width: 380px) {
|
|
95
|
+
.ranking-section {
|
|
96
|
+
--ranking-podium-min-h: clamp(268px, 48dvh, 340px);
|
|
97
|
+
--ranking-player-stats-min-h: clamp(248px, 44dvh, 300px);
|
|
98
|
+
}
|
|
99
|
+
}
|