-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Customising quick pairing buttons #19631
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
yafred
wants to merge
27
commits into
lichess-org:master
Choose a base branch
from
yafred:custom-pairing-buttons
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
c9291d3
customise pool buttons
yafred cd75b98
fixes
yafred c865715
add game type icon to customised buttons
yafred 067577d
override lobby setup when clicking on a customised button
yafred 8da1459
submit with presets
yafred 3d6725b
use transp in custom buttons
yafred ef2ac55
don't show the modal dialog when clicking on a customised button
yafred d7e0bbf
show quick pairing button if we are forced into a pool
yafred faca208
fix irresponsive lobby button after custom submit
yafred bb3bae2
don't let icons eat pointer events
yafred 64d2eda
relocate test to prevent modal dialog when needed
yafred 5a03407
refactor customised button rendering
yafred 853799e
choose gameType in modal is undefined
yafred aa252f6
add icon to restore action
yafred 353d8f3
for Fen valid if no gameType
yafred 816bdb7
rated has no meaning for ai games
yafred 599ee7e
load props before redrawing
yafred 206e2b8
nice pencil when customisable
yafred da6d91d
cleanup
yafred fa61742
add ai level to customised button
yafred 24df3c4
Merge branch 'master' into custom-pairing-buttons
yafred df0dd51
port Simek modifs
yafred 6a7dacd
prettier
yafred 5788c3c
fix lint
yafred 9455501
give icons their own div to allow styling and positioning
yafred fcc307b
position icons (minimum impact on the current look)
yafred f3186d0
prettier
yafred File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| import { storage } from 'lib/storage'; | ||
| import { variants } from './options'; | ||
| import type { Customisation, GameType } from './interfaces'; | ||
| import * as licon from 'lib/licon'; | ||
| import type LobbyController from './ctrl'; | ||
| import { hl, type VNode } from 'lib/view'; | ||
|
|
||
| const custoStoreKey = (username?: string) => `lobby.customisation.${username || 'anon'}`; | ||
| const lobbySetupStoreKey = (username: string | undefined, gameType: GameType) => | ||
| `lobby.setup.${username || 'anon'}.${gameType}`; | ||
|
|
||
| export const getAll = (username?: string): Record<string, Customisation> => { | ||
| const raw = storage.make(custoStoreKey(username)).get(); | ||
| if (!raw) return {}; | ||
| try { | ||
| return JSON.parse(raw); | ||
| } catch { | ||
| return {}; | ||
| } | ||
| }; | ||
|
|
||
| export const get = (username: string | undefined, id: string): Customisation | undefined => | ||
| getAll(username)[id]; | ||
|
|
||
| export const set = (username: string | undefined, id: string, pool: Customisation) => { | ||
| const all = getAll(username); | ||
| all[id] = pool; | ||
| storage.make(custoStoreKey(username)).set(JSON.stringify(all)); | ||
| }; | ||
|
|
||
| export const remove = (username: string | undefined, id: string) => { | ||
| const all = getAll(username); | ||
| delete all[id]; | ||
| storage.make(custoStoreKey(username)).set(JSON.stringify(all)); | ||
| }; | ||
|
|
||
| export const overrideStoredLobbySetup = ( | ||
| poolId: string, | ||
| username: string | undefined, | ||
| ): Customisation | undefined => { | ||
| const customisation = get(username, poolId); | ||
| if (!customisation) return undefined; | ||
|
|
||
| storage | ||
| .make(lobbySetupStoreKey(username, customisation.gameType)) | ||
| .set(JSON.stringify(customisation.settings)); | ||
|
|
||
| return customisation; | ||
| }; | ||
|
|
||
| export const renderCustomisedButton = ( | ||
| poolId: string, | ||
| customisation: Customisation | undefined, | ||
| selected: boolean, | ||
| transp: boolean, | ||
| customisable: boolean, | ||
| ): VNode | undefined => { | ||
| if (!customisation) return undefined; | ||
|
|
||
| const variantDef = variants.find(v => v.key === customisation.settings.variant); | ||
| const variantIcon = | ||
| customisation.settings.variant !== 'standard' || customisation ? variantDef?.icon : undefined; | ||
| const typeIconAttrs = | ||
| customisation.gameType === 'hook' | ||
| ? { 'data-icon': licon.Group } | ||
| : customisation.gameType === 'friend' | ||
| ? { 'data-icon': licon.User } | ||
| : customisation.gameType === 'ai' | ||
| ? { 'data-icon': licon.Cpu } | ||
| : undefined; | ||
| const timeLabel = | ||
| customisation.settings.timeMode === 'realTime' | ||
| ? `${customisation.settings.time}+${customisation.settings.increment}` | ||
| : customisation.settings.timeMode === 'correspondence' | ||
| ? `${customisation.settings.days}d` | ||
| : '∞'; | ||
| const subLabel = | ||
| customisation.gameType !== 'ai' | ||
| ? customisation.settings.gameMode === 'rated' | ||
| ? i18n.site.rated | ||
| : i18n.site.casual | ||
| : 'Level ' + customisation.settings.aiLevel; | ||
|
|
||
| return hl( | ||
| 'div.lpool', | ||
| { | ||
| class: { selected, custom: true, transp, customisable }, | ||
| attrs: { role: 'button', 'data-id': poolId, tabindex: '0' }, | ||
| }, | ||
| [ | ||
| hl('div.icons', [ | ||
| hl('span', { attrs: typeIconAttrs }), | ||
| variantIcon ? hl('span', { attrs: { 'data-icon': variantIcon } }) : null, | ||
| ]), | ||
| hl('div.clock', timeLabel), | ||
| hl('div.perf', subLabel), | ||
| ], | ||
| ); | ||
| }; | ||
|
|
||
| export function renderCustomiserModalContent(ctrl: LobbyController): VNode[] | null { | ||
| if (!ctrl.isEditingPoolButtons() || !ctrl.selectedPoolButton) return null; | ||
| const customisation = get(ctrl.me?.username, ctrl.selectedPoolButton); | ||
| return [ | ||
| hl('div.setup-content', [ | ||
| hl('div.lobby__table', [ | ||
| hl('div.lobby__start', [ | ||
| makeRestoreButton(ctrl, customisation), | ||
| ...lobbyButtons.map(b => makeCustomiserButton(ctrl, customisation, b)), | ||
| ]), | ||
| ]), | ||
| ]), | ||
| ]; | ||
| } | ||
|
|
||
| type ButtonInfo = { gameType: GameType; label: string; title?: string }; | ||
| const lobbyButtons: ButtonInfo[] = [ | ||
| { | ||
| gameType: 'hook', | ||
| label: i18n.site.createLobbyGame, | ||
| }, | ||
| { | ||
| gameType: 'friend', | ||
| label: i18n.site.challengeAFriend, | ||
| }, | ||
| { | ||
| gameType: 'ai', | ||
| label: i18n.site.playAgainstComputer, | ||
| }, | ||
| ]; | ||
|
|
||
| function makeRestoreButton(ctrl: LobbyController, customisation: Customisation | undefined) { | ||
| if (!customisation) return null; | ||
|
|
||
| return hl( | ||
| 'button.button.button-metal.lobby__start__button.lobby__start__button--restore', | ||
| { | ||
| on: { | ||
| click: () => { | ||
| remove(ctrl.me?.username, ctrl.selectedPoolButton!); | ||
| ctrl.redraw(); | ||
| }, | ||
| }, | ||
| }, | ||
| 'Restore quick pairing', | ||
| ); | ||
| } | ||
|
|
||
| function makeCustomiserButton( | ||
| ctrl: LobbyController, | ||
| customisation: Customisation | undefined, | ||
| buttonInfo: ButtonInfo, | ||
| ) { | ||
| return hl( | ||
| `button.button.button-metal.lobby__start__button.lobby__start__button--${buttonInfo.gameType}`, | ||
| { | ||
| on: { | ||
| click: () => { | ||
| if (customisation) overrideStoredLobbySetup(customisation.gameType, ctrl.me?.username); | ||
| ctrl.setupCtrl.gameType = buttonInfo.gameType; | ||
| ctrl.setupCtrl.loadPropsFromStore(); | ||
| ctrl.redraw(); | ||
| }, | ||
| }, | ||
| }, | ||
| buttonInfo.label + (customisation && customisation.gameType === buttonInfo.gameType ? ' *' : ''), | ||
| ); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to skip group icon to match default tiles, which are hooks. Also icons feels a bit too big.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I'm happy you think we are at this stage of polishing 😄 )
The default tiles are not really hooks, there are pools:
My initial idea was to create a second layer of tiles and let the exisiting one in peace (but the reception was ... not great)
If this proposal goes through, we are going to spend a lot of attention on visual details (this is the home page)