@polisplatform/theme-bootstrap 0.0.0-stage → 0.3.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/README.md CHANGED
@@ -1,3 +1,128 @@
1
- # Temporary Holding Version
1
+ # @polisplatform/theme-bootstrap
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Video Game Rankings theme for Polis-family apps. Provides the SCSS design
4
+ tokens (variables, fonts, base element styles, responsive helpers) and the
5
+ Mantine theme overrides extracted from the VGR web app.
6
+
7
+ ## What's in here
8
+
9
+ ```
10
+ src/
11
+ theme.ts Mantine theme override (createTheme(...))
12
+ styles/
13
+ main.scss Imports bootstrap + the partials below
14
+ variables.scss CSS custom properties (colors, typography, layout)
15
+ fonts.scss Font-face declarations (currently empty placeholder)
16
+ elements.scss Base element styles (h3/h4/h6, .button, .alert, ...)
17
+ responsive.scss Breakpoint helpers (.hide-in-mobile, .desktop-only, ...)
18
+ ```
19
+
20
+ The contents are extracted verbatim from
21
+ `Video-Game-Rankings/apps/web/src/theme/` and the inline `mantimeTheme`
22
+ object that lived in `apps/web/src/App.tsx`.
23
+
24
+ ## Consuming
25
+
26
+ This package follows the same distribution pattern as `polis-laravel` and
27
+ `polis-react`: it lives in a public GitHub repo and is pulled in via a
28
+ `github:` dependency pinned to a tag.
29
+
30
+ Add to the consuming app's `package.json`:
31
+
32
+ ```json
33
+ {
34
+ "dependencies": {
35
+ "@polisplatform/theme-bootstrap": "github:PomeloProductions/polis-theme-bootstrap#v0.1.0"
36
+ }
37
+ }
38
+ ```
39
+
40
+ Then `npm install`.
41
+
42
+ ## Importing
43
+
44
+ ### Polis theme (recommended)
45
+
46
+ `@polisplatform/theme-bootstrap` exports a `theme: PolisTheme` object that
47
+ satisfies the canonical interface in `@polisplatform/react/theme/PolisTheme`.
48
+ Pass it to `<PolisProvider>` from `@polisplatform/react`:
49
+
50
+ ```tsx
51
+ import { PolisProvider } from '@polisplatform/react';
52
+ import { theme } from '@polisplatform/theme-bootstrap';
53
+
54
+ export function App() {
55
+ return <PolisProvider theme={theme}>{/* ... */}</PolisProvider>;
56
+ }
57
+ ```
58
+
59
+ `PolisProvider` injects every token as a `--polis-*` CSS custom
60
+ property and wraps children in `<MantineProvider>` using the theme's
61
+ embedded `mantineTheme` override. Swap themes by changing only the
62
+ import on the second line — components in `@polisplatform/react` that read
63
+ `var(--polis-*)` will pick up the new palette automatically.
64
+
65
+ ### Dark mode
66
+
67
+ This theme ships a full dark colour set (in `theme.dark`) whose surfaces track
68
+ Bootstrap 5.3's dark theme (`--bs-body-bg` #212529 body, `--bs-tertiary-bg`
69
+ #2b3035 elevated). `<PolisProvider>` (from `@polisplatform/react` ≥ the dark-mode
70
+ release) resolves the active scheme (`'light' | 'dark' | 'system'`), injects the
71
+ matching token set, and sets `data-bs-theme="dark"` on `<html>` so Bootstrap's
72
+ own dark mode engages in lockstep:
73
+
74
+ ```tsx
75
+ <PolisProvider theme={theme} defaultAppliedColorScheme="system">
76
+ {/* ... */}
77
+ </PolisProvider>
78
+ ```
79
+
80
+ SCSS-only consumers (no `<PolisProvider>`) get dark by setting
81
+ `data-bs-theme="dark"` or `data-polis-color-scheme="dark"` on the root element —
82
+ `styles/variables.scss` overrides the `--polis-color-*` tokens under those
83
+ selectors.
84
+
85
+ ### Mantine theme (standalone)
86
+
87
+ If you only need the Mantine theme overrides (no token interface, no
88
+ PolisProvider), the `mantineTheme` export is the same object that's
89
+ embedded in `theme.mantineTheme`:
90
+
91
+ ```ts
92
+ import { MantineProvider } from '@mantine/core';
93
+ import { mantineTheme } from '@polisplatform/theme-bootstrap';
94
+
95
+ export function App() {
96
+ return (
97
+ <MantineProvider theme={mantineTheme}>
98
+ {/* ... */}
99
+ </MantineProvider>
100
+ );
101
+ }
102
+ ```
103
+
104
+ ### SCSS
105
+
106
+ Import the bundle entry point:
107
+
108
+ ```scss
109
+ @import '@polisplatform/theme-bootstrap/styles/main.scss';
110
+ ```
111
+
112
+ Or pull in individual partials:
113
+
114
+ ```scss
115
+ @import '@polisplatform/theme-bootstrap/styles/variables';
116
+ @import '@polisplatform/theme-bootstrap/styles/elements';
117
+ @import '@polisplatform/theme-bootstrap/styles/responsive';
118
+ ```
119
+
120
+ `main.scss` currently imports `~bootstrap/scss/bootstrap`, so the consuming
121
+ app must have `bootstrap` available to its SCSS resolver (most bundlers
122
+ honour the `~` tilde-prefix to mean "resolve from `node_modules`").
123
+
124
+ ## Versioning
125
+
126
+ Tagged releases follow SemVer. Breaking changes bump the major; new
127
+ features the minor; bug fixes the patch. Pin consumers to a tag
128
+ (`#v0.1.0`) so theme updates roll out deliberately.
package/package.json CHANGED
@@ -1,6 +1,91 @@
1
1
  {
2
2
  "name": "@polisplatform/theme-bootstrap",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.3.0",
4
+ "description": "Video Game Rankings theme for Polis-family apps (SCSS variables, fonts, base elements, responsive helpers, Mantine theme overrides)",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Bryce Meyer <bryce13950@gmail.com> (Pomelo Productions)",
8
+ "homepage": "https://github.com/PomeloProductions/polis-theme-bootstrap",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/PomeloProductions/polis-theme-bootstrap.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/PomeloProductions/polis-theme-bootstrap/issues"
15
+ },
16
+ "keywords": [
17
+ "polis",
18
+ "pomelo",
19
+ "theme",
20
+ "bootstrap",
21
+ "ui"
22
+ ],
23
+ "publishConfig": {
24
+ "access": "public",
25
+ "registry": "https://registry.npmjs.org"
26
+ },
27
+ "main": "./src/index.ts",
28
+ "types": "./src/index.ts",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./src/index.ts",
32
+ "import": "./src/index.ts",
33
+ "default": "./src/index.ts"
34
+ },
35
+ "./theme": "./src/theme.ts",
36
+ "./styles/*": "./src/styles/*",
37
+ "./styles/main.scss": "./src/styles/main.scss",
38
+ "./styles/variables.scss": "./src/styles/variables.scss",
39
+ "./styles/fonts.scss": "./src/styles/fonts.scss",
40
+ "./styles/elements.scss": "./src/styles/elements.scss",
41
+ "./styles/responsive.scss": "./src/styles/responsive.scss",
42
+ "./package.json": "./package.json"
43
+ },
44
+ "files": [
45
+ "src",
46
+ "tsconfig.json",
47
+ "README.md"
48
+ ],
49
+ "peerDependencies": {
50
+ "@mantine/core": "^9.0.0",
51
+ "@polisplatform/react": "github:PomeloProductions/polis-react",
52
+ "bootstrap": ">=5",
53
+ "react": ">=19.2.0"
54
+ },
55
+ "peerDependenciesMeta": {
56
+ "@mantine/core": {
57
+ "optional": true
58
+ },
59
+ "@polisplatform/react": {
60
+ "optional": true
61
+ },
62
+ "bootstrap": {
63
+ "optional": true
64
+ },
65
+ "react": {
66
+ "optional": true
67
+ }
68
+ },
69
+ "scripts": {
70
+ "lint": "eslint . && prettier --check .",
71
+ "lint:fix": "eslint . --fix && prettier --write ."
72
+ },
73
+ "devDependencies": {
74
+ "@eslint/js": "^10.0.0",
75
+ "@mantine/core": "^9.6.0",
76
+ "@mantine/dates": "^9.6.0",
77
+ "@mantine/hooks": "^9.6.0",
78
+ "@mantine/notifications": "^9.6.0",
79
+ "@mantine/tiptap": "^9.6.0",
80
+ "@polisplatform/react": "github:PomeloProductions/polis-react",
81
+ "eslint": "^10.0.0",
82
+ "eslint-config-prettier": "^10.0.0",
83
+ "eslint-plugin-import": "^2.31.0",
84
+ "eslint-plugin-react": "^7.37.4",
85
+ "eslint-plugin-react-hooks": "^7.0.0",
86
+ "globals": "^17.0.0",
87
+ "prettier": "^3.4.2",
88
+ "typescript": "^6.0.3",
89
+ "typescript-eslint": "^8.69.0"
90
+ }
91
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { theme, mantineTheme } from './theme';
2
+ export { default } from './theme';
@@ -0,0 +1,149 @@
1
+ :root {
2
+ --primary-color: var(--polis-color-primary);
3
+ --primary-shade: #3171e0;
4
+ --primary-tint: #4c8dff;
5
+ --medium-color: #92949c;
6
+ --medium-tint: #a2a4ab;
7
+ --medium-shade: #808289;
8
+ --light-color: #f4f5f8;
9
+ --light-shade: #d7d8da;
10
+ --danger-color: #eb445a;
11
+ }
12
+
13
+ h3 {
14
+ color: var(--primary-shade);
15
+ text-align: center;
16
+ font-weight: bold;
17
+ }
18
+ h4 {
19
+ font-weight: bold;
20
+ margin: 0;
21
+ color: black;
22
+ }
23
+ h6 {
24
+ font-size: 5vw;
25
+ @media screen and (min-width: 400px) {
26
+ font-size: 20px;
27
+ }
28
+ }
29
+ .content {
30
+ --background: var(--color-light);
31
+ --padding-top: 20px;
32
+ --padding-bottom: 20px;
33
+ --padding-start: 20px;
34
+ --padding-end: 20px;
35
+ }
36
+ .button {
37
+ --background: var(--polis-color-primary);
38
+ --background-hover: var(--color-primary-shade);
39
+ --background-activated: var(--color-primary-shade);
40
+ --background-focused: var(--color-primary-shade);
41
+ --color: var(--color-primary-contrast);
42
+ --border-radius: 4px;
43
+ --box-shadow: none;
44
+ --padding-top: 10px;
45
+ --padding-bottom: 10px;
46
+ --padding-start: 20px;
47
+ --padding-end: 20px;
48
+ font-weight: 500;
49
+ text-transform: none;
50
+ }
51
+ .button.outlined {
52
+ --background: transparent;
53
+ --background-hover: rgba(var(--color-primary-rgb), 0.1);
54
+ --background-activated: rgba(var(--color-primary-rgb), 0.2);
55
+ --background-focused: rgba(var(--color-primary-rgb), 0.1);
56
+ --color: var(--polis-color-primary);
57
+ --border-color: var(--polis-color-primary);
58
+ --border-width: 1px;
59
+ --border-style: solid;
60
+ }
61
+ .error {
62
+ color: var(--danger-color);
63
+ }
64
+ .select {
65
+ --background: transparent;
66
+ --color: var(--color-dark);
67
+ --placeholder-color: var(--color-medium);
68
+ --padding-start: 0;
69
+ --padding-end: 0;
70
+ }
71
+ .item {
72
+ --background: transparent;
73
+ --color: var(--color-dark);
74
+ --padding-start: 0;
75
+ --padding-end: 0;
76
+ --inner-padding-end: 0;
77
+ --min-height: 40px;
78
+ }
79
+ .item,
80
+ .list {
81
+ --background: transparent;
82
+ }
83
+ .alert {
84
+ --background: var(--color-light);
85
+ --backdrop-opacity: 0.4;
86
+ --max-width: 90%;
87
+ --width: 90%;
88
+ --border-radius: 8px;
89
+ --box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
90
+ --header-color: var(--color-dark);
91
+ --message-color: var(--color-medium);
92
+ --button-color: var(--polis-color-primary);
93
+ --button-background: transparent;
94
+ --button-background-hover: rgba(var(--color-primary-rgb), 0.1);
95
+ --button-background-activated: rgba(var(--color-primary-rgb), 0.2);
96
+ --button-background-focused: rgba(var(--color-primary-rgb), 0.1);
97
+ }
98
+ .toolbar .back-button {
99
+ --color: var(--color-dark);
100
+ --padding-start: 0;
101
+ --padding-end: 0;
102
+ margin: 0;
103
+ }
104
+ .app {
105
+ --background: var(--color-light);
106
+ }
107
+ a {
108
+ color: var(--primary-shade);
109
+ text-decoration: none;
110
+
111
+ &:hover {
112
+ text-decoration: underline;
113
+ }
114
+ }
115
+ .plt-android {
116
+ .back-button {
117
+ display: none;
118
+ }
119
+ }
120
+
121
+ input,
122
+ textarea {
123
+ border: 1px solid var(--light-shade);
124
+ padding: 8px;
125
+ border-radius: 4px;
126
+
127
+ &:focus {
128
+ outline: none;
129
+ border-color: var(--primary-color);
130
+ }
131
+ }
132
+
133
+ .back-button {
134
+ display: inline-flex;
135
+ align-items: center;
136
+ color: var(--medium-color);
137
+ text-decoration: none;
138
+ padding: 8px;
139
+
140
+ &:hover {
141
+ color: var(--medium-shade);
142
+ }
143
+ }
144
+
145
+ .app-container {
146
+ min-height: 100vh;
147
+ display: flex;
148
+ flex-direction: column;
149
+ }
File without changes
@@ -0,0 +1,11 @@
1
+ @import '~bootstrap/scss/bootstrap';
2
+
3
+ @import 'fonts';
4
+ @import 'variables';
5
+ @import 'elements';
6
+ @import 'responsive';
7
+
8
+ // Remove red weekend styling from Mantine DatePicker
9
+ [data-weekend] {
10
+ color: inherit !important;
11
+ }
@@ -0,0 +1,35 @@
1
+ .plt-mobileweb,
2
+ .plt-desktop {
3
+ input::-webkit-outer-spin-button,
4
+ input::-webkit-inner-spin-button {
5
+ -webkit-appearance: none;
6
+ margin: 0;
7
+ }
8
+ input[type='number'] {
9
+ -moz-appearance: textfield;
10
+ }
11
+ }
12
+
13
+ // These are the organization breakpoints
14
+ @media screen and (max-width: 800px) {
15
+ .desktop-only {
16
+ display: none !important;
17
+ }
18
+ }
19
+ @media screen and (min-width: 801px) {
20
+ .mobile-only {
21
+ display: none !important;
22
+ }
23
+ }
24
+
25
+ // Public breakpoints
26
+ .hide-in-desktop {
27
+ @media screen and (min-width: 992px) {
28
+ display: none !important;
29
+ }
30
+ }
31
+ .hide-in-mobile {
32
+ @media screen and (max-width: 991px) {
33
+ display: none !important;
34
+ }
35
+ }
@@ -0,0 +1,277 @@
1
+ /*
2
+ * Theme Variables
3
+ * ----------------------------------------------------------------------------
4
+ * Custom variables for the application theme
5
+ *
6
+ * The `--polis-*` block mirrors the token values exported from `theme.ts`
7
+ * (`@polisplatform/theme-bootstrap`) as CSS custom-property defaults. Consumers
8
+ * that import just the SCSS — without going through `<PolisProvider>`
9
+ * from `@polisplatform/react` — still get a styled surface. When `<PolisProvider>`
10
+ * is mounted it will overwrite these on `document.documentElement`, so
11
+ * runtime theme swaps still take precedence.
12
+ */
13
+
14
+ :root {
15
+ /* ── Polis canonical tokens (mirrors src/theme.ts) ── */
16
+ --polis-color-primary: #228be6;
17
+ --polis-color-primary-hover: #1c7ed6;
18
+ --polis-color-primary-active: #1971c2;
19
+ --polis-color-surface: #ffffff;
20
+ --polis-color-surface-alt: #f8f9fa;
21
+ --polis-color-text-primary: #212529;
22
+ --polis-color-text-muted: #6c757d;
23
+ --polis-color-border: #dee2e6;
24
+ --polis-color-success: #52ab58;
25
+ --polis-color-warning: #ffc409;
26
+ --polis-color-danger: #eb445a;
27
+ --polis-color-info: #3298b3;
28
+
29
+ --polis-font-body: Inter, sans-serif;
30
+ --polis-font-heading: Inter, sans-serif;
31
+ --polis-font-mono:
32
+ 'SFMono-Regular', Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
33
+
34
+ --polis-radius-sm: 2px;
35
+ --polis-radius-md: 4px;
36
+ --polis-radius-lg: 8px;
37
+ --polis-radius-full: 9999px;
38
+
39
+ --polis-spacing-xs: 4px;
40
+ --polis-spacing-sm: 8px;
41
+ --polis-spacing-md: 16px;
42
+ --polis-spacing-lg: 24px;
43
+ --polis-spacing-xl: 32px;
44
+
45
+ /* ── Legacy VGR / Bootstrap-styled palette (kept for backward-compat) ── */
46
+ /* Primary Colors */
47
+ --color-primary-rgb: 56, 128, 255;
48
+ --color-primary-contrast: #ffffff;
49
+ --color-primary-contrast-rgb: 255, 255, 255;
50
+ --color-primary-shade: #e87819;
51
+ --color-primary-tint: #f58d34;
52
+ --color-primary-light: #ffeed4;
53
+
54
+ /* Secondary Colors */
55
+ --color-secondary: #3298b3;
56
+ --color-secondary-rgb: 61, 194, 255;
57
+ --color-secondary-contrast: #ffffff;
58
+ --color-secondary-contrast-rgb: 255, 255, 255;
59
+ --color-secondary-shade: #3eacc9;
60
+ --color-secondary-tint: #3298b3;
61
+
62
+ /* Tertiary Colors */
63
+ --color-tertiary: #5260ff;
64
+ --color-tertiary-rgb: 82, 96, 255;
65
+ --color-tertiary-contrast: #ffffff;
66
+ --color-tertiary-contrast-rgb: 255, 255, 255;
67
+ --color-tertiary-shade: #4854e0;
68
+ --color-tertiary-tint: #6370ff;
69
+
70
+ /* Quaternary Colors */
71
+ --color-quaternary: #481514;
72
+
73
+ /* Success Colors */
74
+ --color-success: #52ab58;
75
+ --color-success-rgb: 45, 211, 111;
76
+ --color-success-contrast: #ffffff;
77
+ --color-success-contrast-rgb: 255, 255, 255;
78
+ --color-success-shade: rgba(0, 128, 55, 0.95);
79
+ --color-success-tint: #3fa46a;
80
+
81
+ /* Warning Colors */
82
+ --color-warning: #ffc409;
83
+ --color-warning-rgb: 255, 196, 9;
84
+ --color-warning-contrast: #000000;
85
+ --color-warning-contrast-rgb: 0, 0, 0;
86
+ --color-warning-shade: #e0ac08;
87
+ --color-warning-tint: #ffca22;
88
+
89
+ /* Danger Colors */
90
+ --color-danger: #eb445a;
91
+ --color-danger-rgb: 235, 68, 90;
92
+ --color-danger-contrast: #ffffff;
93
+ --color-danger-contrast-rgb: 255, 255, 255;
94
+ --color-danger-shade: #cf3c4f;
95
+ --color-danger-tint: #ed576b;
96
+
97
+ /* Dark Colors */
98
+ --color-dark: #222428;
99
+ --color-dark-rgb: 34, 36, 40;
100
+ --color-dark-contrast: #ffffff;
101
+ --color-dark-contrast-rgb: 255, 255, 255;
102
+ --color-dark-shade: #1e2023;
103
+ --color-dark-tint: #383a3e;
104
+
105
+ /* Medium Colors */
106
+ --color-medium: #545454;
107
+ --color-medium-rgb: 146, 148, 156;
108
+ --color-medium-contrast: #ffffff;
109
+ --color-medium-contrast-rgb: 255, 255, 255;
110
+ --color-medium-shade: #888b8e;
111
+ --color-medium-tint: #9d9fa6;
112
+
113
+ /* Light Colors */
114
+ --color-light: #f5f7f4;
115
+ --color-light-rgb: 244, 245, 248;
116
+ --color-light-contrast: var(--polis-color-primary);
117
+ --color-light-contrast-rgb: 0, 0, 0;
118
+ --color-light-shade: #d7d8da;
119
+ --color-light-tint: #f5f6f9;
120
+
121
+ /* Social Colors */
122
+ --color-favorite: #69bb7b;
123
+ --color-favorite-rgb: 105, 187, 123;
124
+ --color-favorite-contrast: #ffffff;
125
+ --color-favorite-contrast-rgb: 255, 255, 255;
126
+ --color-favorite-shade: #5ca56c;
127
+ --color-favorite-tint: #78c288;
128
+
129
+ --color-twitter: #1da1f4;
130
+ --color-twitter-rgb: 29, 161, 244;
131
+ --color-twitter-contrast: #ffffff;
132
+ --color-twitter-contrast-rgb: 255, 255, 255;
133
+ --color-twitter-shade: #1a8ed7;
134
+ --color-twitter-tint: #34aaf5;
135
+
136
+ --color-instagram: #5956d8;
137
+ --color-instagram-rgb: 89, 86, 216;
138
+ --color-instagram-contrast: #ffffff;
139
+ --color-instagram-contrast-rgb: 255, 255, 255;
140
+ --color-instagram-shade: #4e4cbe;
141
+ --color-instagram-tint: #6a67dc;
142
+
143
+ --color-vimeo: #23b6ea;
144
+ --color-vimeo-rgb: 35, 182, 234;
145
+ --color-vimeo-contrast: #ffffff;
146
+ --color-vimeo-contrast-rgb: 255, 255, 255;
147
+ --color-vimeo-shade: #1fa0ce;
148
+ --color-vimeo-tint: #39bdec;
149
+
150
+ --color-facebook: #3b5998;
151
+ --color-facebook-rgb: 59, 89, 152;
152
+ --color-facebook-contrast: #ffffff;
153
+ --color-facebook-contrast-rgb: 255, 255, 255;
154
+ --color-facebook-shade: #344e86;
155
+ --color-facebook-tint: #4f6aa2;
156
+
157
+ --color-github: #211f1f;
158
+ --color-github-rgb: 33, 31, 31;
159
+ --color-github-contrast: #ffffff;
160
+ --color-github-contrast-rgb: 255, 255, 255;
161
+ --color-github-shade: #1d1b1b;
162
+ --color-github-tint: #373535;
163
+
164
+ /* Other Colors */
165
+ --welcome-background: #f6ead7;
166
+ --color-violet: #5e17eb;
167
+
168
+ /* Typography */
169
+ --font-family: 'Omnes', 'Helvetica Neue', 'Arial', sans-serif;
170
+ --headings-font-weight: 300;
171
+
172
+ /* Layout */
173
+ --toolbar-background: white;
174
+ --tab-bar-background: white;
175
+ --color-angular: #ac282b;
176
+ --color-communication: #8e8d93;
177
+ --color-tooling: #fe4c52;
178
+ --color-services: #fd8b2d;
179
+ --color-design: #fed035;
180
+ --color-workshop: #69bb7b;
181
+ --color-food: #3bc7c4;
182
+ --color-documentation: #b16be3;
183
+ --color-navigation: #6600cc;
184
+ }
185
+
186
+ /*
187
+ * ── Polis dark tokens ──
188
+ * SCSS-only consumers (no <PolisProvider>) get dark mode by setting
189
+ * `data-bs-theme="dark"` (Bootstrap 5.3 native) or `data-polis-color-scheme="dark"`
190
+ * on the root element. When <PolisProvider> is mounted it overwrites these
191
+ * inline on document.documentElement, so this block is the standalone default.
192
+ * Mirrors the `dark` set in src/theme.ts.
193
+ */
194
+ :root[data-bs-theme='dark'],
195
+ :root[data-polis-color-scheme='dark'] {
196
+ --polis-color-primary: #4dabf7;
197
+ --polis-color-primary-hover: #74c0fc;
198
+ --polis-color-primary-active: #a5d8ff;
199
+ --polis-color-primary-tint: #1b3a5b;
200
+ --polis-color-primary-subtle: #132840;
201
+ --polis-color-primary-contrast: #0b0d10;
202
+ --polis-color-surface: #212529;
203
+ --polis-color-surface-alt: #2b3035;
204
+ --polis-color-text-primary: #dee2e6;
205
+ --polis-color-text-muted: #adb5bd;
206
+ --polis-color-border: #495057;
207
+ --polis-color-success: #69db7c;
208
+ --polis-color-warning: #ffd43b;
209
+ --polis-color-danger: #ff8787;
210
+ --polis-color-info: #66d9e8;
211
+ }
212
+
213
+ /* Dark Theme */
214
+ body.dark {
215
+ --color-primary: #428cff;
216
+ --color-primary-rgb: 66, 140, 255;
217
+ --color-primary-contrast: #ffffff;
218
+ --color-primary-contrast-rgb: 255, 255, 255;
219
+ --color-primary-shade: #3a7be0;
220
+ --color-primary-tint: #5598ff;
221
+
222
+ --color-secondary: #50c8ff;
223
+ --color-secondary-rgb: 80, 200, 255;
224
+ --color-secondary-contrast: #ffffff;
225
+ --color-secondary-contrast-rgb: 255, 255, 255;
226
+ --color-secondary-shade: #46b0e0;
227
+ --color-secondary-tint: #62ceff;
228
+
229
+ --color-tertiary: #6a64ff;
230
+ --color-tertiary-rgb: 106, 100, 255;
231
+ --color-tertiary-contrast: #ffffff;
232
+ --color-tertiary-contrast-rgb: 255, 255, 255;
233
+ --color-tertiary-shade: #5d58e0;
234
+ --color-tertiary-tint: #7974ff;
235
+
236
+ --color-success: #2fdf75;
237
+ --color-success-rgb: 47, 223, 117;
238
+ --color-success-contrast: #000000;
239
+ --color-success-contrast-rgb: 0, 0, 0;
240
+ --color-success-shade: #29c467;
241
+ --color-success-tint: #44e283;
242
+
243
+ --color-warning: #ffd534;
244
+ --color-warning-rgb: 255, 213, 52;
245
+ --color-warning-contrast: #000000;
246
+ --color-warning-contrast-rgb: 0, 0, 0;
247
+ --color-warning-shade: #e0bb2e;
248
+ --color-warning-tint: #ffd948;
249
+
250
+ --color-danger: #ff4961;
251
+ --color-danger-rgb: 255, 73, 97;
252
+ --color-danger-contrast: #ffffff;
253
+ --color-danger-contrast-rgb: 255, 255, 255;
254
+ --color-danger-shade: #e04055;
255
+ --color-danger-tint: #ff5b71;
256
+
257
+ --color-dark: #f4f5f8;
258
+ --color-dark-rgb: 244, 245, 248;
259
+ --color-dark-contrast: #000000;
260
+ --color-dark-contrast-rgb: 0, 0, 0;
261
+ --color-dark-shade: #d7d8da;
262
+ --color-dark-tint: #f5f6f9;
263
+
264
+ --color-medium: #989aa2;
265
+ --color-medium-rgb: 152, 154, 162;
266
+ --color-medium-contrast: #000000;
267
+ --color-medium-contrast-rgb: 0, 0, 0;
268
+ --color-medium-shade: #86888f;
269
+ --color-medium-tint: #a2a4ab;
270
+
271
+ --color-light: #222428;
272
+ --color-light-rgb: 34, 36, 40;
273
+ --color-light-contrast: #ffffff;
274
+ --color-light-contrast-rgb: 255, 255, 255;
275
+ --color-light-shade: #1e2023;
276
+ --color-light-tint: #383a3e;
277
+ }
package/src/theme.ts ADDED
@@ -0,0 +1,127 @@
1
+ import { createTheme } from '@mantine/core';
2
+ import type { PolisTheme } from '@polisplatform/react/theme/PolisTheme';
3
+
4
+ /**
5
+ * Mantine theme overrides for the Video Game Rankings application.
6
+ *
7
+ * Extracted verbatim from `apps/web/src/App.tsx` of the VGR repo. This is
8
+ * the same `mantineTheme` object that was passed to `<MantineProvider>`.
9
+ *
10
+ * Exported standalone for callers that consume the Mantine theme directly,
11
+ * and re-exported below at `theme.mantineTheme` so `<PolisProvider>` can
12
+ * forward it into Mantine.
13
+ */
14
+ export const mantineTheme = createTheme({
15
+ primaryColor: 'blue',
16
+ fontFamily: 'Inter, sans-serif',
17
+ other: {
18
+ primaryShade: { light: 6, dark: 8 },
19
+ },
20
+ components: {
21
+ Table: {
22
+ styles: {
23
+ th: {
24
+ backgroundColor: 'var(--polis-color-surface-alt, #f8f9fa)',
25
+ borderBottom: '2px solid var(--polis-color-border, #dee2e6)',
26
+ padding: '1rem',
27
+ },
28
+ td: {
29
+ padding: '1rem',
30
+ },
31
+ tr: {
32
+ '&:hover': {
33
+ backgroundColor: 'var(--polis-color-surface-alt, #f8f9fa)',
34
+ },
35
+ },
36
+ },
37
+ },
38
+ },
39
+ });
40
+
41
+ /**
42
+ * `@polisplatform/theme-bootstrap` — the Polis token bundle that drives the
43
+ * VGR-flavored visual identity (Bootstrap-rooted SCSS palette + Mantine
44
+ * theme override).
45
+ *
46
+ * Pass this to `<PolisProvider theme={theme}>` from `@polisplatform/react`.
47
+ *
48
+ * The primary palette tracks the Mantine theme's `primaryColor: 'blue'`,
49
+ * which is what the actual Mantine surface renders in the VGR app. The
50
+ * other colour tokens align with Bootstrap 5 defaults.
51
+ */
52
+ export const theme: PolisTheme = {
53
+ name: 'bootstrap',
54
+
55
+ colors: {
56
+ primary: '#228be6',
57
+ primaryHover: '#1c7ed6',
58
+ primaryActive: '#1971c2',
59
+ // Mantine blue[1] / blue[2] — light tints of the primary, used for
60
+ // hover/selected backgrounds on neutral surfaces.
61
+ primaryTint: '#d0ebff',
62
+ primarySubtle: '#a5d8ff',
63
+ // White reads cleanly on the blue[6] primary used by buttons / badges.
64
+ primaryContrast: '#ffffff',
65
+ surface: '#ffffff',
66
+ surfaceAlt: '#f8f9fa',
67
+ textPrimary: '#212529',
68
+ textMuted: '#6c757d',
69
+ border: '#dee2e6',
70
+ success: '#52ab58',
71
+ warning: '#ffc409',
72
+ danger: '#eb445a',
73
+ info: '#3298b3',
74
+ },
75
+
76
+ /**
77
+ * Dark colour tokens. Surfaces track Bootstrap 5.3's dark theme
78
+ * (`--bs-body-bg` #212529 body, `--bs-tertiary-bg` #2b3035 elevated) so the
79
+ * SCSS surface stays in step with `data-bs-theme="dark"`. The primary
80
+ * lightens to Mantine blue[4] (#4dabf7) to hold contrast against the dark
81
+ * body; `primaryContrast` stays dark ink for filled buttons.
82
+ */
83
+ dark: {
84
+ primary: '#4dabf7',
85
+ primaryHover: '#74c0fc',
86
+ primaryActive: '#a5d8ff',
87
+ // Deep blue backgrounds for subtle/selected states on dark surfaces.
88
+ primaryTint: '#1b3a5b',
89
+ primarySubtle: '#132840',
90
+ // Dark ink reads on the light-blue primary used for filled buttons.
91
+ primaryContrast: '#0b0d10',
92
+ surface: '#212529',
93
+ surfaceAlt: '#2b3035',
94
+ textPrimary: '#dee2e6',
95
+ textMuted: '#adb5bd',
96
+ border: '#495057',
97
+ success: '#69db7c',
98
+ warning: '#ffd43b',
99
+ danger: '#ff8787',
100
+ info: '#66d9e8',
101
+ },
102
+
103
+ fonts: {
104
+ body: 'Inter, sans-serif',
105
+ heading: 'Inter, sans-serif',
106
+ mono: '"SFMono-Regular", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
107
+ },
108
+
109
+ radius: {
110
+ sm: '2px',
111
+ md: '4px',
112
+ lg: '8px',
113
+ full: '9999px',
114
+ },
115
+
116
+ spacing: {
117
+ xs: '4px',
118
+ sm: '8px',
119
+ md: '16px',
120
+ lg: '24px',
121
+ xl: '32px',
122
+ },
123
+
124
+ mantineTheme,
125
+ };
126
+
127
+ export default theme;
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
7
+ "jsx": "react-jsx",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "declaration": true,
15
+ "declarationMap": true,
16
+ "noEmit": true
17
+ },
18
+ "include": ["src/**/*.ts", "src/**/*.tsx"],
19
+ "exclude": ["node_modules", "dist"]
20
+ }