Use radio buttons for server list
This commit is contained in:
parent
72772881b6
commit
e1c56c201e
@ -18,9 +18,9 @@
|
||||
<CollapsibleSection v-if="servers.size > 1" name="servers">
|
||||
<template v-slot:heading>{{ heading }}</template>
|
||||
<template v-slot:default>
|
||||
<ul class="section__content menu" role="listbox" aria-labelledby="servers-heading">
|
||||
<RadioList class="section__content" aria-labelledby="servers-heading">
|
||||
<ServerListItem :server="server" v-for="[name, server] in servers" :key="name"></ServerListItem>
|
||||
</ul>
|
||||
</RadioList>
|
||||
</template>
|
||||
</CollapsibleSection>
|
||||
</template>
|
||||
@ -30,10 +30,12 @@ import ServerListItem from './ServerListItem.vue';
|
||||
import {defineComponent} from 'vue';
|
||||
import {useStore} from "@/store";
|
||||
import CollapsibleSection from "@/components/sidebar/CollapsibleSection.vue";
|
||||
import RadioList from "@/components/util/RadioList.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ServerList',
|
||||
components: {
|
||||
RadioList,
|
||||
CollapsibleSection,
|
||||
ServerListItem
|
||||
},
|
||||
|
@ -15,12 +15,9 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<li :class="{'server': true, 'server--selected': selected}" role="none">
|
||||
<button type="button" :class="{'active': selected}"
|
||||
role="radio" :aria-checked="selected" :title="server.label || server.id"
|
||||
@click="setCurrentServer(server.id)">{{ server.label || server.id }}
|
||||
</button>
|
||||
</li>
|
||||
<input :id="`server-${server.id}`" type="radio" name="server" :value="server.id" v-model="currentServer"
|
||||
@click="setCurrentServer(server.id)">
|
||||
<label :for="`server-${server.id}`">{{ server.label || server.id }}</label>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@ -39,11 +36,8 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
computed: {
|
||||
currentServer(): LiveAtlasServerDefinition | undefined {
|
||||
return useStore().state.currentServer;
|
||||
},
|
||||
selected(): boolean {
|
||||
return !!this.currentServer && this.server.id === this.currentServer.id;
|
||||
currentServer(): string | undefined {
|
||||
return useStore().state.currentServer ? useStore().state.currentServer.id : undefined;
|
||||
}
|
||||
},
|
||||
|
||||
|
71
src/components/util/RadioList.vue
Normal file
71
src/components/util/RadioList.vue
Normal file
@ -0,0 +1,71 @@
|
||||
<!--
|
||||
- Copyright 2020 James Lyne
|
||||
-
|
||||
- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
- you may not use this file except in compliance with the License.
|
||||
- You may obtain a copy of the License at
|
||||
-
|
||||
- http://www.apache.org/licenses/LICENSE-2.0
|
||||
-
|
||||
- Unless required by applicable law or agreed to in writing, software
|
||||
- distributed under the License is distributed on an "AS IS" BASIS,
|
||||
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
- See the License for the specific language governing permissions and
|
||||
- limitations under the License.
|
||||
-->
|
||||
<template>
|
||||
<fieldset class="menu" role="radiogroup" @keydown="onKeydown">
|
||||
<slot></slot>
|
||||
</fieldset>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {defineComponent} from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'RadioList',
|
||||
|
||||
setup() {
|
||||
},
|
||||
|
||||
methods: {
|
||||
onKeydown(e: KeyboardEvent) {
|
||||
if(e.key === 'ArrowUp' || e.key === 'ArrowDown' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
|
||||
const fieldset = e.currentTarget as HTMLFieldSetElement,
|
||||
position = Array.from(fieldset.elements).indexOf(e.target as HTMLElement);
|
||||
|
||||
if(position < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let newPosition = (e.key === 'ArrowUp' || e.key === 'ArrowLeft') ? position - 1 : position + 1;
|
||||
|
||||
if(newPosition < 0) {
|
||||
newPosition = fieldset.elements.length - 1;
|
||||
} else if (newPosition >= fieldset.elements.length) {
|
||||
newPosition = 0;
|
||||
}
|
||||
|
||||
(fieldset.elements[newPosition] as HTMLElement).focus();
|
||||
e.preventDefault();
|
||||
} else if(e.key === 'Enter') {
|
||||
if(e.target instanceof HTMLInputElement && e.target.type === 'radio') {
|
||||
e.target.click();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../scss/mixins';
|
||||
|
||||
fieldset {
|
||||
appearance: none;
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
@ -26,6 +26,7 @@
|
||||
font-size: 1.6rem;
|
||||
font-family: Raleway, sans-serif;
|
||||
box-sizing: border-box;
|
||||
text-shadow: none;
|
||||
|
||||
.svg-icon {
|
||||
display: inline-block;
|
||||
|
@ -172,19 +172,46 @@ input {
|
||||
display: flex;
|
||||
padding: 0.8rem 0.8rem 0.7rem;
|
||||
position: relative;
|
||||
border-bottom: 0.1rem solid transparent;
|
||||
|
||||
> button {
|
||||
margin: -0.8rem -0.8rem -0.7rem;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
> input[type=radio] {
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
height: 1px;
|
||||
width: 1px;
|
||||
position: absolute;
|
||||
|
||||
& + label {
|
||||
@include button;
|
||||
}
|
||||
|
||||
&:hover + label, &:checked + label {
|
||||
@include button-hovered;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&:focus + label {
|
||||
@include button-focused;
|
||||
}
|
||||
|
||||
&:active + label {
|
||||
@include button-active;
|
||||
}
|
||||
}
|
||||
|
||||
& > li > button, & > input[type=radio] + label {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
margin: -0.8rem -0.8rem -0.7rem;
|
||||
padding: 0.8rem 0.8rem 0.7rem;
|
||||
text-align: left;
|
||||
flex-grow: 1;
|
||||
min-height: 3.2rem;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
border-bottom: 0.1rem solid transparent;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user