openguessr-ui 0.0.0-stage → 0.1.1
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 +463 -2
- package/base.css +256 -0
- package/classes.css +151 -0
- package/components/Chip.svelte +89 -0
- package/components/Collapsible.svelte +76 -0
- package/components/ConfirmPopup.svelte +28 -0
- package/components/ErrorPopup.svelte +52 -0
- package/components/InfoBanner.svelte +68 -0
- package/components/LoadingSpinner.svelte +33 -0
- package/components/Notification.svelte +132 -0
- package/components/Popup.svelte +141 -0
- package/components/RoomCodeInput.svelte +130 -0
- package/components/Tabs.svelte +88 -0
- package/components/Ticker.svelte +84 -0
- package/components/TitleSeparator.svelte +36 -0
- package/confirmPopup.svelte.js +16 -0
- package/errorPopup.svelte.js +22 -0
- package/fonts/barlow-condensed-medium.woff2 +0 -0
- package/index.js +16 -0
- package/notifications.svelte.js +55 -0
- package/package.json +49 -5
- package/sound-effects/basic_button.ogg +0 -0
- package/sound-effects/change_value.ogg +0 -0
- package/sound-effects/item_locked.ogg +0 -0
- package/sound-effects/item_select.ogg +0 -0
- package/sound-effects/juicy_button.ogg +0 -0
- package/sound-effects/start_button.ogg +0 -0
- package/sound-effects/toggle_button.ogg +0 -0
- package/tooltip.svelte.js +180 -0
- package/variables.css +39 -0
- package/vector-graphics/compass_spinner.svg +6 -0
package/README.md
CHANGED
|
@@ -1,3 +1,464 @@
|
|
|
1
|
-
#
|
|
1
|
+
# OpenGuessr UI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The user interface design system for OpenGuessr. Install via `npm install openguessr-ui`.
|
|
4
|
+
|
|
5
|
+
Made to be used with [Svelte](https://svelte.dev).
|
|
6
|
+
|
|
7
|
+
> [!IMPORTANT]
|
|
8
|
+
> While this library is publicly available, commercial use is not permitted.
|
|
9
|
+
|
|
10
|
+
## Structure
|
|
11
|
+
|
|
12
|
+
These core concepts define how UI should be structured.
|
|
13
|
+
|
|
14
|
+
### Core concepts
|
|
15
|
+
|
|
16
|
+
- **Boxes:** Boxes house controls, text, images, or other boxes.
|
|
17
|
+
|
|
18
|
+
- **Panels:** Panels are used for floating UI. They typically include controls rather than loads of text or images, perfect for HUDs.
|
|
19
|
+
|
|
20
|
+
- **Containers:** Containers contain boxes. The popup acts as a layout/container hybird that also contains boxes.
|
|
21
|
+
|
|
22
|
+
- **Layouts:** Layouts are typically full pages that containers or panels sit in.
|
|
23
|
+
|
|
24
|
+
### Hierarchy
|
|
25
|
+
|
|
26
|
+
1. Every element starts in layout space (level 1), where `--layout-margin` defines the spacing between grouped elements, the padding, and the border radii of children. For separating unrelated elements, `--layout-spacer` is used.
|
|
27
|
+
|
|
28
|
+
2. The second level is containers, where the spacing and padding is `--box-margin`, and the border radii of children are as well.
|
|
29
|
+
|
|
30
|
+
3. The third level is boxes, where the spacing and padding is still `--box-margin`, but the border radii of children are `--content-margin`.
|
|
31
|
+
|
|
32
|
+
4. On the fourth level there is either content or smaller boxes. Smaller boxes still use `--box-margin` for padding and spacing, but `--content-margin` for border radii.
|
|
33
|
+
|
|
34
|
+
The content level (inside buttons, chips, tabs, or other controls) uses spacing of `--content-margin`. Placing content directly into layouts or containers is not allowed, it needs to sit inside a box or panel.
|
|
35
|
+
|
|
36
|
+
Popups take some properties from layouts and some from containers. They use `--layout-margin` for spacing, but content inside them is boxes (level 3) with `--box-margin` for border radii. Panels typically live in layout space (level 1), but have unique spacing rules (as outlined above).
|
|
37
|
+
|
|
38
|
+
## Styling
|
|
39
|
+
|
|
40
|
+
This defines how UI should be styled.
|
|
41
|
+
|
|
42
|
+
### Variables
|
|
43
|
+
|
|
44
|
+
These variables are used for margins, paddings, and gaps:
|
|
45
|
+
|
|
46
|
+
| Variable | Value |
|
|
47
|
+
| -------- | ----- |
|
|
48
|
+
| --content-margin | 5px |
|
|
49
|
+
| --panel-margin | 8px |
|
|
50
|
+
| --box-margin | 10px |
|
|
51
|
+
| --layout-margin | 15px |
|
|
52
|
+
| --layout-spacer | 50px |
|
|
53
|
+
|
|
54
|
+
These variables are used for colors:
|
|
55
|
+
|
|
56
|
+
| Variable | Explanation |
|
|
57
|
+
| -------- | ------- |
|
|
58
|
+
| --brand-color | Primary red |
|
|
59
|
+
| --panel-color | Blue-ish, for panels |
|
|
60
|
+
| --box-color | Bright transparent for boxes |
|
|
61
|
+
| --line-color | For strokes and separators |
|
|
62
|
+
| --box-color-dark | Accentuated boxes |
|
|
63
|
+
| --box-color-dark-soft | Slightly accentuated boxes |
|
|
64
|
+
| --overlay-color | Dark overlays |
|
|
65
|
+
| --overlay-color-dark | Full-screen menu overlays |
|
|
66
|
+
| --bright-green-color | Experience, perks |
|
|
67
|
+
| --bright-green-color-soft| Indicators |
|
|
68
|
+
| --bright-green-color-dark | Experience, perk backgrounds |
|
|
69
|
+
| --background-color | Opaque background |
|
|
70
|
+
| --dark-shadow-color | Text or drop shadows |
|
|
71
|
+
|
|
72
|
+
> [!TIP]
|
|
73
|
+
> There should be at most one `--brand-color` element visible at a time (the primary action). Green colors should not be used for success, use bright styling instead (e.g. `rgba(255, 255, 255, 0.2)`).
|
|
74
|
+
|
|
75
|
+
These variabels are used for box shadows:
|
|
76
|
+
|
|
77
|
+
| Variable | Used for |
|
|
78
|
+
| -------- | ------- |
|
|
79
|
+
| --button-shadow | Buttons |
|
|
80
|
+
| --button-shadow-dark | Dark buttons |
|
|
81
|
+
| --box-shadow-top | Boxes that fade out towards the bottom |
|
|
82
|
+
| --box-shadow-bottom | Boxes that fade out towards the top |
|
|
83
|
+
| --box-shadow | Boxes |
|
|
84
|
+
| --bulb-shadow | Pills, chips, badges |
|
|
85
|
+
| --panel-shadow | Floating elements (containers, panels..) |
|
|
86
|
+
|
|
87
|
+
These variables are used for blur:
|
|
88
|
+
|
|
89
|
+
| Variable | Value |
|
|
90
|
+
| -------- | ------- |
|
|
91
|
+
| --weak-blur | 5px |
|
|
92
|
+
| --normal-blur | 10px |
|
|
93
|
+
| --elevated-blur | 15px |
|
|
94
|
+
| --strong-blur | 50px |
|
|
95
|
+
|
|
96
|
+
### Boxes
|
|
97
|
+
|
|
98
|
+
Boxes typically use this base styling:
|
|
99
|
+
|
|
100
|
+
```css
|
|
101
|
+
.box {
|
|
102
|
+
background-color: var(--box-color);
|
|
103
|
+
border-radius: var(--box-margin); /* --content-margin when inside another box */
|
|
104
|
+
padding: var(--box-margin);
|
|
105
|
+
gap: var(--box-margin); /* When applicable */
|
|
106
|
+
box-shadow: var(--box-shadow);
|
|
107
|
+
max-width: fit-content;
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Their width shouldn't grow to fit the container or Popup they are in.
|
|
112
|
+
|
|
113
|
+
#### Text inside boxes
|
|
114
|
+
|
|
115
|
+
Since boxes have rather tight padding and text naturally adds top and bottom spacing through the line-height, applying `padding-inline: var(--content-margin)` to text is recommended. If the entire box just contains text, raising the boxes' inline padding to `--layout-margin` has the same effect.
|
|
116
|
+
|
|
117
|
+
### Panels
|
|
118
|
+
|
|
119
|
+
Panels typically use this base styling:
|
|
120
|
+
|
|
121
|
+
```css
|
|
122
|
+
.panel {
|
|
123
|
+
background-color: var(--panel-color);
|
|
124
|
+
border-radius: var(--box-margin); /* Or --layout-margin if they contain large buttons */
|
|
125
|
+
padding: var(--panel-margin);
|
|
126
|
+
gap: var(--panel-margin); /* When applicable */
|
|
127
|
+
backdrop-filter: blur(var(--normal-blur)); /* Only if the layout doesn't apply elevated or strong blur already */
|
|
128
|
+
box-shadow: var(--panel-shadow);
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Panels that house large buttons which are rounder than usual buttons should have a border radius of `--layout-margin` to avoid uneven corners. Don't mix them, panels should stick to only large or only small buttons.
|
|
133
|
+
|
|
134
|
+
When panels sit inside layouts with a strong background color (e.g. `--overlay-color-dark`), their backgorund color should be `--box-color` instead of `--panel-color` to avoid layering two blue-ish tones (which will produce a color that looks too vibrant).
|
|
135
|
+
|
|
136
|
+
The gap or margin between related panels should be `--box-margin` if they use `--box-margin` for the border radii, otherwise `--layout-margin`.
|
|
137
|
+
|
|
138
|
+
### Containers
|
|
139
|
+
|
|
140
|
+
Containers typically use this base styling:
|
|
141
|
+
|
|
142
|
+
```css
|
|
143
|
+
.container {
|
|
144
|
+
background-color: var(--panel-color);
|
|
145
|
+
border-radius: var(--layout-margin);
|
|
146
|
+
padding: var(--box-margin);
|
|
147
|
+
gap: var(--box-margin); /* When applicable */
|
|
148
|
+
backdrop-filter: blur(var(--normal-blur)); /* Only if the layout doesn't apply elevated or strong blur already */
|
|
149
|
+
box-shadow: var(--panel-shadow);
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Like panels, containers inside layouts with a strong background color should use `--box-color` instead of `--panel-color`.
|
|
154
|
+
|
|
155
|
+
### Layouts
|
|
156
|
+
|
|
157
|
+
Layouts typically use this base styling:
|
|
158
|
+
|
|
159
|
+
```css
|
|
160
|
+
.layout {
|
|
161
|
+
background-color: var(--overlay-color-dark);
|
|
162
|
+
padding: var(--layout-margin);
|
|
163
|
+
padding-block: var(--layout-spacer); /* For full pages to leave some slack at the top and bottom */
|
|
164
|
+
gap: var(--layout-margin); /* When applicable */
|
|
165
|
+
backdrop-filter: blur(var(--elevated-blur));
|
|
166
|
+
max-width: 1100px;
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Buttons
|
|
171
|
+
|
|
172
|
+
Buttons should always be placed in a box or panel, not just on a blank page. Large buttons shouldn't be put into a box.
|
|
173
|
+
|
|
174
|
+
To create a button, apply the `standard-button` class. This will create a red primary button. To make it secondary, add `bright`.
|
|
175
|
+
|
|
176
|
+
There is a tertiary button, and it's created by applying `dark`, but it's not used in combination with other button variants. Instead, it's strictly for repetitive actions to reduce mental load since it is less eye-catching. For example, a sidebar with dozens of items, where each one has a small "X" button to delete it.
|
|
177
|
+
|
|
178
|
+
Large buttons with short text inside often look unnaturally slim when placed as the only button inside a panel, bumping the padding by adding `wide` resolves this.
|
|
179
|
+
|
|
180
|
+
### Icons in buttons
|
|
181
|
+
|
|
182
|
+
Regular buttons typically have the icon placed on the left side.
|
|
183
|
+
|
|
184
|
+
Large buttons with text place the icon towards the right and use `space-between` to ensure that when multiple buttons are present in a stack, icons and text are perfectly horizontally aligned, making it easier to scan through them at a glance.
|
|
185
|
+
|
|
186
|
+
### Icons
|
|
187
|
+
|
|
188
|
+
Lucide (`@lucide/svelte`) should be used for icons.
|
|
189
|
+
|
|
190
|
+
At the default icon size (which inherits from the font size), using `2.25` as the stroke width is suggested. Icons placed inside of buttons right next to text commonly look best at size `20`.
|
|
191
|
+
|
|
192
|
+
Since Lucide icons don't follow a strict universal strokeWidth and size, some might look better at different values, in which case it is okay to deviate from these defaults. For example, the `X` looks a bit thinner than most other icons.
|
|
193
|
+
|
|
194
|
+
Icons should typically have the color white. They inherit color, but if they aren't placed inside an element that sets one (such as a paragraph), it needs to be set explicitly.
|
|
195
|
+
|
|
196
|
+
The spacing between text and an icon inside content should be `--content-margin`.
|
|
197
|
+
|
|
198
|
+
### Scrollable areas
|
|
199
|
+
|
|
200
|
+
Overfade (`overfade`) is a library used for scrollable areas. It applies a dynamic mask-image on the overflowing element's parent.
|
|
201
|
+
|
|
202
|
+
For example, when an element, that contains overflowing text content and uses `of-top` and `of-bottom`, is scrolled all the way to the top, the top of the text is not faded out, only the bottom is.
|
|
203
|
+
|
|
204
|
+
To use it, add its classes:
|
|
205
|
+
|
|
206
|
+
- `of-top`: Fade out towards the top (for overflow-y)
|
|
207
|
+
- `of-bottom`: Fade out towards the bottom (for overflow-y)
|
|
208
|
+
- `of-left`: Fade out towards the left (for overflow-x)
|
|
209
|
+
- `of-right`: Fade out towards the right (for overflow-x)
|
|
210
|
+
- `of-length-x`: Multiply the length of the fade, defaults to 1 (optional, x = factor)
|
|
211
|
+
|
|
212
|
+
These classes should not be applied directly on boxes or containers, since that would fade their background color. Instead, the scrollable content should go in a separate child div with overfade classes applied.
|
|
213
|
+
|
|
214
|
+
Scrollable content should be intentionally, visibly cut off when scrolling is allowed to communicate the fact that scrolling is possible.
|
|
215
|
+
|
|
216
|
+
### Opacity values
|
|
217
|
+
|
|
218
|
+
Opacity values used are typically `0.25`, `0.5`, `0.75` and `1`. Supportive text, such as the explanation for a feature, can be `0.75` or even `0.5`. Labels, e.g. for controls, should be full opacity.
|
|
219
|
+
|
|
220
|
+
### Images
|
|
221
|
+
|
|
222
|
+
Apply `pointer-events: none` and `user-select: none` unless images need to be explicitly interactive.
|
|
223
|
+
|
|
224
|
+
### Animation and transition durations
|
|
225
|
+
|
|
226
|
+
Use `100ms`, `150ms`, `250ms`, `500ms` or `1000ms`.
|
|
227
|
+
|
|
228
|
+
### Hover effects
|
|
229
|
+
|
|
230
|
+
Elements with hover styling should get darker when hovered, never brighter. For mobile, many `:hover` effects should also be applied when `:active`.
|
|
231
|
+
|
|
232
|
+
## Components
|
|
233
|
+
|
|
234
|
+
These built-in components are useful for building common UI flows.
|
|
235
|
+
|
|
236
|
+
### Popup
|
|
237
|
+
|
|
238
|
+
The popup component is used for dialogs. It takes the following props:
|
|
239
|
+
|
|
240
|
+
- `open`: Whether the popup is open
|
|
241
|
+
- `slim`: Reduces the max width
|
|
242
|
+
- `verySlim`: Reduces the max width further
|
|
243
|
+
- `frameless`: Reduces the padding, e.g. for iFrames
|
|
244
|
+
- `onuserclose`: Called when the user closes the popup
|
|
245
|
+
|
|
246
|
+
A common design pattern is to include a heading at the top of a popup. For this, the built-in `popup-title` class can be used:
|
|
247
|
+
|
|
248
|
+
```html
|
|
249
|
+
<div class="popup-title">
|
|
250
|
+
<h1>Settings</h1>
|
|
251
|
+
</div>
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Many popups include a central action button which gets the `large popup-bottom-button` treatment. Never combine this with the `wide` class.
|
|
255
|
+
|
|
256
|
+
### Chip
|
|
257
|
+
|
|
258
|
+
The chip component is used for small pieces of information, such as a "New" or "Free" indicator. It takes the following props:
|
|
259
|
+
|
|
260
|
+
- `text`: The chip's text
|
|
261
|
+
- `children`: Content to render instead of text
|
|
262
|
+
- `red`: Color variant
|
|
263
|
+
- `italic`: Makes the text italic, typically combined with red
|
|
264
|
+
- `mutedOpacity`: Makes the text muted, red variant typically disables this
|
|
265
|
+
- `onclick`: Makes the chip clickable
|
|
266
|
+
- `class`, `style`: Class and style passthrough
|
|
267
|
+
|
|
268
|
+
### Collapsible
|
|
269
|
+
|
|
270
|
+
The collapsible component is used to contain information that should be tucked away, e.g. information only valuable for a portion of players. It takes the following props:
|
|
271
|
+
|
|
272
|
+
- `title`: The title text
|
|
273
|
+
- `isOpen`: Whether the collapsible is expanded
|
|
274
|
+
- `children`: The content inside
|
|
275
|
+
- `inPage`: Set to false when used in popups, containers etc.
|
|
276
|
+
- `ontoggle`: Called whenever the open state changes
|
|
277
|
+
- `class`: Class passthrough
|
|
278
|
+
|
|
279
|
+
### ConfirmPopup
|
|
280
|
+
|
|
281
|
+
The confirm popup component is used to request user confirmation or to display information. It needs to be mounted. It takes the following props:
|
|
282
|
+
|
|
283
|
+
- `onconfirm`: Called when the user confirms
|
|
284
|
+
|
|
285
|
+
Confirm popups are shown via `showConfirmPopup(title, text, executeFunction, confirmText)`:
|
|
286
|
+
|
|
287
|
+
- `title`: The popup title
|
|
288
|
+
- `text`: The description
|
|
289
|
+
- `executeFunction`: Called on confirm, also shows the confirm button
|
|
290
|
+
- `confirmText`: Text of the confirm button, defaults to "Confirm"
|
|
291
|
+
|
|
292
|
+
Usage example:
|
|
293
|
+
|
|
294
|
+
```js
|
|
295
|
+
showConfirmPopup("Remove item?", "The item will be removed from your favorites.", () => removeItem(), "Remove");
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### ErrorPopup
|
|
299
|
+
|
|
300
|
+
The error popup component is used to inform the user about errors. It needs to be mounted.
|
|
301
|
+
|
|
302
|
+
Error popups are shown via `errorPopup(title, description, errorCode, reload, hideDontShowAgainOption)`:
|
|
303
|
+
|
|
304
|
+
- `title`: The popup title
|
|
305
|
+
- `description`: The description
|
|
306
|
+
- `errorCode`: The error code (usually passed by the server)
|
|
307
|
+
- `reload`: Reloads the page when the popup is closed, also shows the popup even if the user chose to hide errors
|
|
308
|
+
- `hideDontShowAgainOption`: Hides the "Never show again" option
|
|
309
|
+
|
|
310
|
+
Usage example:
|
|
311
|
+
|
|
312
|
+
```js
|
|
313
|
+
errorPopup("Failed to load map", "An error occured loading this map.", "Code 404: Map not found");
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### InfoBanner
|
|
317
|
+
|
|
318
|
+
The info banner component is used for short pieces of information. It takes the following props:
|
|
319
|
+
|
|
320
|
+
- `text`: The banner text
|
|
321
|
+
- `children`: Content to render instead of text
|
|
322
|
+
- `inPage`: Set to true when used in layouts
|
|
323
|
+
- `nowrap`: Keeps the text on one line
|
|
324
|
+
- `center`: Centers the content
|
|
325
|
+
- `transition`: Toggles the slide transition
|
|
326
|
+
- `class`, `style`: Class and style passthrough
|
|
327
|
+
|
|
328
|
+
### LoadingSpinner
|
|
329
|
+
|
|
330
|
+
The loading spinner component can be displayed while large content loads, such as panoramas or full pages. It takes the following props:
|
|
331
|
+
|
|
332
|
+
- `class`, `style`: Class and style passthrough
|
|
333
|
+
|
|
334
|
+
### Notification
|
|
335
|
+
|
|
336
|
+
The notification component is used for short messages at the top of the screen, optionally with an action. It needs to be mounted. It takes the following props:
|
|
337
|
+
|
|
338
|
+
- `top`: Distance from the top of the viewport, defaults to `--layout-margin`
|
|
339
|
+
- `onaccept`: Called when the accept button is used
|
|
340
|
+
- `ondismiss`: Called when the dismiss button is used
|
|
341
|
+
|
|
342
|
+
Notifications are shown via `showNotification(text, acceptAction, dismissAction, viewOnly, clickableText, textClickFunction)`:
|
|
343
|
+
|
|
344
|
+
- `text`: The notification text, `%s` marks where the clickable text goes
|
|
345
|
+
- `acceptAction`: Called on accept, also shows the accept button
|
|
346
|
+
- `dismissAction`: Called on dismiss
|
|
347
|
+
- `viewOnly`: Displays a view icon in the accept button
|
|
348
|
+
- `clickableText`: Clickable text inserted at `%s`, e.g. a player name
|
|
349
|
+
- `textClickFunction`: Called when the clickable text is clicked
|
|
350
|
+
|
|
351
|
+
Usage example:
|
|
352
|
+
|
|
353
|
+
```js
|
|
354
|
+
showNotification("Copied!");
|
|
355
|
+
showNotification("Accept event invite?", () => joinEvent());
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### RoomCodeInput
|
|
359
|
+
|
|
360
|
+
The room code input component is used for entering 6-character room codes. It takes the following props:
|
|
361
|
+
|
|
362
|
+
- `segments`: The entered characters
|
|
363
|
+
- `inPage`: Set to false when used in panels, boxes etc.
|
|
364
|
+
- `onsubmit`: Called with the code when the enter or the submit button is pressed
|
|
365
|
+
|
|
366
|
+
### Tabs
|
|
367
|
+
|
|
368
|
+
The tabs component is great for choosing settings or views, as well as for On/Off switches. It takes the following props:
|
|
369
|
+
|
|
370
|
+
- `tabs`: Text strings or icons
|
|
371
|
+
- `selected`: Selected tab's content
|
|
372
|
+
- `selectedIndex`: Selected tab's index
|
|
373
|
+
- `onchange`: Called with `(selected, selectedIndex)` when the selection changes
|
|
374
|
+
- `disabled`: Disables all tabs
|
|
375
|
+
- `children`: Children rendered inside tab
|
|
376
|
+
- `class`: Class passthrough
|
|
377
|
+
|
|
378
|
+
### Ticker
|
|
379
|
+
|
|
380
|
+
The ticker component is used for fine-grained numeric inputs. It takes the following props:
|
|
381
|
+
|
|
382
|
+
- `value`: Current value
|
|
383
|
+
- `initialValue`: Start value
|
|
384
|
+
- `step`: Step amount (how much the value changes per step)
|
|
385
|
+
- `minimum`: Maximum value
|
|
386
|
+
- `minimumText`, `maximumText`: Text displayed when the max/min is reached
|
|
387
|
+
- `minimumValue`, `maximumValue`: Custom value to show when max/min is reached
|
|
388
|
+
- `note`: Unit of the value
|
|
389
|
+
- `minValueWidth`: Minimum width of value field to prevent the width from jumping
|
|
390
|
+
- `onchange`: Called when the value changes
|
|
391
|
+
|
|
392
|
+
### TitleSeparator
|
|
393
|
+
|
|
394
|
+
The title separator component is used to separate content inside Popups or containers. It takes the following props:
|
|
395
|
+
|
|
396
|
+
- `text`: The title text
|
|
397
|
+
- `noMargin`: Removes the default top and bottom margin (`--layout-margin`)
|
|
398
|
+
- `class`: Class passthrough
|
|
399
|
+
|
|
400
|
+
## Attachments
|
|
401
|
+
|
|
402
|
+
Attachments utilize Svelte's `{@attach...}` syntax.
|
|
403
|
+
|
|
404
|
+
### Tooltip
|
|
405
|
+
|
|
406
|
+
Regular tooltips are used for icon buttons that have no text, and persistent tooltips for tutorials.
|
|
407
|
+
|
|
408
|
+
Usage example:
|
|
409
|
+
|
|
410
|
+
```html
|
|
411
|
+
<button {@attach tooltip({ text: "Settings" })}><GearsIcon /></button>
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Options:
|
|
415
|
+
|
|
416
|
+
- `text`: The tooltip text
|
|
417
|
+
- `imageSrc`: Image shown above the text
|
|
418
|
+
- `imageAspectRatio`: Aspect ratio of the image
|
|
419
|
+
- `maxWidth`: Max width in pixels
|
|
420
|
+
- `state`: A `$state({ visible: false })` object, makes the tooltip persistent and controllable
|
|
421
|
+
- `onclose`: Called when the close button is used
|
|
422
|
+
- `showDelay`: Delay in ms before showing
|
|
423
|
+
- `zIndex`: Tooltip z-index
|
|
424
|
+
- `mobile`: Set to false to hide the tooltip on mobile
|
|
425
|
+
|
|
426
|
+
## Sound effects
|
|
427
|
+
|
|
428
|
+
UI sound effects are available as `.ogg` files and can be played with any audio library:
|
|
429
|
+
|
|
430
|
+
```js
|
|
431
|
+
import basicButtonSound from "openguessr-ui/sound-effects/basic_button.ogg";
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
| Sound | Purpose |
|
|
435
|
+
| ----- | ------- |
|
|
436
|
+
| basic_button | Default sound for standard buttons and tabs |
|
|
437
|
+
| juicy_button | Selection-like choices (e.g. map selection) |
|
|
438
|
+
| start_button | Starting or joining a game |
|
|
439
|
+
| toggle_button | Anything that toggles (e.g. collapsibles) |
|
|
440
|
+
| change_value | Changing a value (e.g. through a ticker) |
|
|
441
|
+
| item_select | Selecting an item (e.g. a pin, badge, or flag) |
|
|
442
|
+
| item_locked | Trying to select a locked item |
|
|
443
|
+
|
|
444
|
+
The components don't play sounds themselves. Instead, they should be played via callbacks:
|
|
445
|
+
|
|
446
|
+
- Collapsible `ontoggle`: `toggle_button`
|
|
447
|
+
- Ticker `onchange`: `change_value`
|
|
448
|
+
- Notification `onaccept`, `ondismiss`: `basic_button`
|
|
449
|
+
|
|
450
|
+
## Scroll bars
|
|
451
|
+
|
|
452
|
+
Typically, scroll bars should be hidden via `scrollbar-width: none`. There can be exceptions, e.g. for text editors where a scroll bar brings utility.
|
|
453
|
+
|
|
454
|
+
## Text formatting guidelines
|
|
455
|
+
|
|
456
|
+
- Body text and headings should be written as plain sentences (sentence case) as opposed to title case (for example, “Game overview” rather than “Game Overview”). The only exception that OpenGuessr makes is for content that needs a clear title or branding such as modes (e.g. Country Guessr), maps (e.g. Capital Cities), competitions, and tournaments.
|
|
457
|
+
- Using a colon ":" in or for UI labels is not recommended.
|
|
458
|
+
- Headings should not end in a period.
|
|
459
|
+
|
|
460
|
+
## Flexibility
|
|
461
|
+
|
|
462
|
+
This design system is highly expandable. Instead of using fixed components for everything, most elements are built using the provided CSS variables.
|
|
463
|
+
|
|
464
|
+
Game UIs should feel handcrafted instead of generic, there are many scenarios where custom controls feel more intuitive than any preexisting component would. So, don't use generic buttons for a fancy map selection screen, or don't use a slider for a health bar – creativity is what makes games feel special.
|