Refactor sidebar sections
- Rename CollapsibleSection to SidebarSection with a collapsible prop - Move section__content element to SidebarSection - Move sidebar section styling to SidebarSection
This commit is contained in:
parent
df1d2ee73b
commit
450a5ee46c
@ -152,8 +152,6 @@ export default defineComponent({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '../scss/placeholders';
|
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 110;
|
z-index: 110;
|
||||||
@ -230,80 +228,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar__section {
|
|
||||||
@extend %panel;
|
|
||||||
margin-bottom: var(--ui-element-spacing);
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 25rem;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
|
|
||||||
.section__heading {
|
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
text-align: left;
|
|
||||||
align-items: center;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
button {
|
|
||||||
display: flex;
|
|
||||||
font-size: 2rem;
|
|
||||||
padding: 1.5rem 1.5rem 1rem;
|
|
||||||
margin: -1.5rem -1.5rem 0;
|
|
||||||
background-color: transparent;
|
|
||||||
font-weight: 400;
|
|
||||||
color: inherit;
|
|
||||||
width: calc(100% + 3rem);
|
|
||||||
align-items: center;
|
|
||||||
text-shadow: var(--text-shadow);
|
|
||||||
|
|
||||||
.svg-icon {
|
|
||||||
margin-left: auto;
|
|
||||||
width: 1.5rem;
|
|
||||||
height: 1.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover, &:focus-visible, &.focus-visible, &:active {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.section__content {
|
|
||||||
padding: 0 0.5rem;
|
|
||||||
margin: 0 -.5rem 1rem;
|
|
||||||
min-width: 0;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.section__skeleton {
|
|
||||||
font-style: italic;
|
|
||||||
color: var(--text-disabled);
|
|
||||||
text-align: center;
|
|
||||||
align-self: center;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.section--collapsed {
|
|
||||||
.section__heading button {
|
|
||||||
padding-bottom: 1.5rem;
|
|
||||||
margin-bottom: -1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section__content {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 320px) {
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
padding-right: 7rem;
|
padding-right: 7rem;
|
||||||
padding-top: 0.8rem;
|
padding-top: 0.8rem;
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
<!--
|
|
||||||
- Copyright 2021 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>
|
|
||||||
<section :class="{'sidebar__section': true, 'section--collapsible': true, 'section--collapsed': collapsed}">
|
|
||||||
<h2 class="section__heading">
|
|
||||||
<button :id="`${name}-heading`" type="button"
|
|
||||||
@click.prevent="toggle" :title="title"
|
|
||||||
:aria-expanded="!collapsed" :aria-controls="`${name}-content`">
|
|
||||||
<span>
|
|
||||||
<slot name="heading"></slot>
|
|
||||||
</span>
|
|
||||||
<SvgIcon name="arrow"></SvgIcon>
|
|
||||||
</button>
|
|
||||||
</h2>
|
|
||||||
<div :id="`${name}-content`" :aria-hidden="collapsed">
|
|
||||||
<slot></slot>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import {useStore} from "@/store";
|
|
||||||
import {LiveAtlasSidebarSection} from "@/index";
|
|
||||||
import {defineComponent} from "@vue/runtime-core";
|
|
||||||
import SvgIcon from "@/components/SvgIcon.vue";
|
|
||||||
import '@/assets/icons/arrow.svg';
|
|
||||||
import {MutationTypes} from "@/store/mutation-types";
|
|
||||||
import {computed} from "vue";
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: 'CollapsibleSection',
|
|
||||||
components: {SvgIcon},
|
|
||||||
props: {
|
|
||||||
name: {
|
|
||||||
type: String as () => LiveAtlasSidebarSection,
|
|
||||||
required: true,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setup(props) {
|
|
||||||
const store = useStore(),
|
|
||||||
title = computed(() => store.state.messages.toggleTitle),
|
|
||||||
collapsed = computed(() => store.state.ui.sidebar.collapsedSections.has(props.name));
|
|
||||||
|
|
||||||
const toggle = () => store.commit(MutationTypes.TOGGLE_SIDEBAR_SECTION_COLLAPSED_STATE, props.name);
|
|
||||||
|
|
||||||
return {
|
|
||||||
title,
|
|
||||||
collapsed,
|
|
||||||
toggle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.section--collapsible {
|
|
||||||
.section__heading .svg-icon {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.section--collapsed {
|
|
||||||
.section__heading .svg-icon {
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -15,35 +15,33 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CollapsibleSection name="players" class="players">
|
<SidebarSection name="players" class="players">
|
||||||
<template v-slot:heading>{{ messageHeading }}</template>
|
<template v-slot:heading>{{ messageHeading }}</template>
|
||||||
<template v-slot:default>
|
<template v-slot:default>
|
||||||
<div class="section__content">
|
<input v-if="players && searchEnabled" id="players__search" type="text" name="search"
|
||||||
<input v-if="players && searchEnabled" id="players__search" type="text" name="search"
|
v-model="searchQuery" :placeholder="messagePlayersSearchPlaceholder" @keydown="onKeydown">
|
||||||
v-model="searchQuery" :placeholder="messagePlayersSearchPlaceholder" @keydown="onKeydown">
|
<RadioList v-if="filteredPlayers.length" aria-labelledby="players-heading">
|
||||||
<RadioList v-if="filteredPlayers.length" aria-labelledby="players-heading">
|
<PlayerListItem v-for="player in filteredPlayers" :key="player.name"
|
||||||
<PlayerListItem v-for="player in filteredPlayers" :key="player.name"
|
:player="player"></PlayerListItem>
|
||||||
:player="player"></PlayerListItem>
|
</RadioList>
|
||||||
</RadioList>
|
<div v-else-if="searchQuery" class="section__skeleton">{{ messageSkeletonPlayersSearch }}</div>
|
||||||
<div v-else-if="searchQuery" class="section__skeleton">{{ messageSkeletonPlayersSearch }}</div>
|
<div v-else class="section__skeleton">{{ messageSkeletonPlayers }}</div>
|
||||||
<div v-else class="section__skeleton">{{ messageSkeletonPlayers }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</CollapsibleSection>
|
</SidebarSection>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import PlayerListItem from "./PlayerListItem.vue";
|
import PlayerListItem from "./PlayerListItem.vue";
|
||||||
import {computed, defineComponent} from "@vue/runtime-core";
|
import {computed, defineComponent} from "@vue/runtime-core";
|
||||||
import {useStore} from "@/store";
|
import {useStore} from "@/store";
|
||||||
import CollapsibleSection from "@/components/sidebar/CollapsibleSection.vue";
|
|
||||||
import RadioList from "@/components/util/RadioList.vue";
|
import RadioList from "@/components/util/RadioList.vue";
|
||||||
import {ref} from "vue";
|
import {ref} from "vue";
|
||||||
|
import SidebarSection from "@/components/sidebar/SidebarSection.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
SidebarSection,
|
||||||
RadioList,
|
RadioList,
|
||||||
CollapsibleSection,
|
|
||||||
PlayerListItem
|
PlayerListItem
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -15,28 +15,28 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CollapsibleSection v-if="servers.size > 1" name="servers">
|
<SidebarSection v-if="servers.size > 1" name="servers">
|
||||||
<template v-slot:heading>{{ heading }}</template>
|
<template v-slot:heading>{{ heading }}</template>
|
||||||
<template v-slot:default>
|
<template v-slot:default>
|
||||||
<RadioList class="section__content" aria-labelledby="servers-heading">
|
<RadioList aria-labelledby="servers-heading">
|
||||||
<ServerListItem :server="server" v-for="[name, server] in servers" :key="name"></ServerListItem>
|
<ServerListItem :server="server" v-for="[name, server] in servers" :key="name"></ServerListItem>
|
||||||
</RadioList>
|
</RadioList>
|
||||||
</template>
|
</template>
|
||||||
</CollapsibleSection>
|
</SidebarSection>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import ServerListItem from './ServerListItem.vue';
|
import ServerListItem from './ServerListItem.vue';
|
||||||
import {computed, defineComponent} from 'vue';
|
import {computed, defineComponent} from 'vue';
|
||||||
import {useStore} from "@/store";
|
import {useStore} from "@/store";
|
||||||
import CollapsibleSection from "@/components/sidebar/CollapsibleSection.vue";
|
import SidebarSection from "@/components/sidebar/SidebarSection.vue";
|
||||||
import RadioList from "@/components/util/RadioList.vue";
|
import RadioList from "@/components/util/RadioList.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ServerList',
|
name: 'ServerList',
|
||||||
components: {
|
components: {
|
||||||
RadioList,
|
RadioList,
|
||||||
CollapsibleSection,
|
SidebarSection,
|
||||||
ServerListItem
|
ServerListItem
|
||||||
},
|
},
|
||||||
|
|
||||||
|
191
src/components/sidebar/SidebarSection.vue
Normal file
191
src/components/sidebar/SidebarSection.vue
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
<!--
|
||||||
|
- Copyright 2021 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>
|
||||||
|
<section :class="{
|
||||||
|
'sidebar__section': true,
|
||||||
|
'section--collapsible': collapsible,
|
||||||
|
'section--collapsed': collapsed
|
||||||
|
}" :data-section="name">
|
||||||
|
<h2 class="section__heading">
|
||||||
|
<button :id="`${name}-heading`" type="button"
|
||||||
|
@click.prevent="toggle" :title="title"
|
||||||
|
:aria-expanded="!collapsed" :aria-controls="`${name}-content`">
|
||||||
|
<span>
|
||||||
|
<slot name="heading"></slot>
|
||||||
|
</span>
|
||||||
|
<SvgIcon name="arrow"></SvgIcon>
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div :id="`${name}-content`" class="section__content" :aria-hidden="collapsed">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import {useStore} from "@/store";
|
||||||
|
import {LiveAtlasSidebarSection} from "@/index";
|
||||||
|
import {defineComponent} from "@vue/runtime-core";
|
||||||
|
import SvgIcon from "@/components/SvgIcon.vue";
|
||||||
|
import '@/assets/icons/arrow.svg';
|
||||||
|
import {MutationTypes} from "@/store/mutation-types";
|
||||||
|
import {computed, ref} from "vue";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'SidebarSection',
|
||||||
|
components: {SvgIcon},
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String as () => LiveAtlasSidebarSection,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
collapsible: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setup(props) {
|
||||||
|
const store = useStore(),
|
||||||
|
title = computed(() => store.state.messages.toggleTitle),
|
||||||
|
collapsed = computed(() => store.state.ui.sidebar[props.name].collapsed),
|
||||||
|
customPosition = computed(() => store.state.ui.sidebar[props.name].customPosition),
|
||||||
|
customSize = computed(() => store.state.ui.sidebar[props.name].customSize),
|
||||||
|
smallScreen = computed(() => store.state.ui.smallScreen),
|
||||||
|
|
||||||
|
offsetX = ref(0),
|
||||||
|
offsetY = ref(0);
|
||||||
|
|
||||||
|
const toggle = () => {
|
||||||
|
if(!props.collapsible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
store.commit(MutationTypes.TOGGLE_SIDEBAR_SECTION_COLLAPSED_STATE, props.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
collapsed,
|
||||||
|
customPosition,
|
||||||
|
customSize,
|
||||||
|
smallScreen,
|
||||||
|
toggle,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../../scss/placeholders';
|
||||||
|
|
||||||
|
.sidebar__section {
|
||||||
|
@extend %panel;
|
||||||
|
margin-bottom: var(--ui-element-spacing);
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 25rem;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
|
||||||
|
.section__heading {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
text-align: left;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
button {
|
||||||
|
display: flex;
|
||||||
|
font-size: 2rem;
|
||||||
|
padding: 1.5rem 1.5rem 1rem;
|
||||||
|
margin: -1.5rem -1.5rem 0;
|
||||||
|
background-color: transparent;
|
||||||
|
font-weight: 400;
|
||||||
|
color: inherit;
|
||||||
|
width: calc(100% + 3rem);
|
||||||
|
align-items: center;
|
||||||
|
text-shadow: var(--text-shadow);
|
||||||
|
|
||||||
|
.svg-icon {
|
||||||
|
margin-left: auto;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover, &:focus-visible, &.focus-visible, &:active {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section__content {
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
margin: 0 -.5rem 1rem;
|
||||||
|
min-width: 0;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section__skeleton {
|
||||||
|
font-style: italic;
|
||||||
|
color: var(--text-disabled);
|
||||||
|
text-align: center;
|
||||||
|
align-self: center;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.section--collapsible {
|
||||||
|
.section__heading .svg-icon {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.section--collapsed {
|
||||||
|
.section__heading .svg-icon {
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section__heading button {
|
||||||
|
padding-bottom: 1.5rem;
|
||||||
|
margin-bottom: -1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section__content {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section__content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
flex-shrink: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 320px) {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -15,29 +15,29 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CollapsibleSection name="maps">
|
<SidebarSection name="maps">
|
||||||
<template v-slot:heading>{{ heading }}</template>
|
<template v-slot:heading>{{ heading }}</template>
|
||||||
<template v-slot:default>
|
<template v-slot:default>
|
||||||
<RadioList v-if="worlds.size" class="section__content" aria-labelledby="maps-heading">
|
<RadioList v-if="worlds.size" aria-labelledby="maps-heading">
|
||||||
<WorldListItem :world="world" v-for="[name, world] in worlds" :key="`${prefix}_${currentServer}_${name}`"></WorldListItem>
|
<WorldListItem :world="world" v-for="[name, world] in worlds" :key="`${prefix}_${currentServer}_${name}`"></WorldListItem>
|
||||||
</RadioList>
|
</RadioList>
|
||||||
<div v-else class="section__content section__skeleton">{{ skeleton }}</div>
|
<div v-else class="section__skeleton">{{ skeleton }}</div>
|
||||||
</template>
|
</template>
|
||||||
</CollapsibleSection>
|
</SidebarSection>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import WorldListItem from './WorldListItem.vue';
|
import WorldListItem from './WorldListItem.vue';
|
||||||
import {computed, defineComponent} from 'vue';
|
import {computed, defineComponent} from 'vue';
|
||||||
import {useStore} from "@/store";
|
import {useStore} from "@/store";
|
||||||
import CollapsibleSection from "@/components/sidebar/CollapsibleSection.vue";
|
|
||||||
import RadioList from "@/components/util/RadioList.vue";
|
import RadioList from "@/components/util/RadioList.vue";
|
||||||
|
import SidebarSection from "@/components/sidebar/SidebarSection.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'WorldList',
|
name: 'WorldList',
|
||||||
components: {
|
components: {
|
||||||
|
SidebarSection,
|
||||||
RadioList,
|
RadioList,
|
||||||
CollapsibleSection,
|
|
||||||
WorldListItem
|
WorldListItem
|
||||||
},
|
},
|
||||||
|
|
||||||
|
4
src/index.d.ts
vendored
4
src/index.d.ts
vendored
@ -160,6 +160,10 @@ export type LiveAtlasUIModal = 'login' | 'settings';
|
|||||||
export type LiveAtlasSidebarSection = 'servers' | 'players' | 'maps';
|
export type LiveAtlasSidebarSection = 'servers' | 'players' | 'maps';
|
||||||
export type LiveAtlasDimension = 'overworld' | 'nether' | 'end';
|
export type LiveAtlasDimension = 'overworld' | 'nether' | 'end';
|
||||||
|
|
||||||
|
export type LiveAtlasSidebarSectionState = {
|
||||||
|
collapsed?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
interface LiveAtlasPlayer {
|
interface LiveAtlasPlayer {
|
||||||
name: string;
|
name: string;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
|
@ -43,7 +43,9 @@ console.info(`LiveAtlas version ${store.state.version} - https://github.com/JLyn
|
|||||||
|
|
||||||
store.subscribe((mutation, state) => {
|
store.subscribe((mutation, state) => {
|
||||||
if(mutation.type === 'toggleSidebarSectionCollapsedState' || mutation.type === 'setSidebarSectionCollapsedState') {
|
if(mutation.type === 'toggleSidebarSectionCollapsedState' || mutation.type === 'setSidebarSectionCollapsedState') {
|
||||||
localStorage.setItem('collapsedSections', JSON.stringify(Array.from(state.ui.sidebar.collapsedSections)));
|
localStorage.setItem('uiSettings', JSON.stringify({
|
||||||
|
sidebar: state.ui.sidebar,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -39,7 +39,12 @@ import {
|
|||||||
LiveAtlasMarker,
|
LiveAtlasMarker,
|
||||||
LiveAtlasMarkerSet,
|
LiveAtlasMarkerSet,
|
||||||
LiveAtlasServerDefinition,
|
LiveAtlasServerDefinition,
|
||||||
LiveAtlasServerConfig, LiveAtlasChat, LiveAtlasPartialComponentConfig, LiveAtlasComponentConfig, LiveAtlasUIModal
|
LiveAtlasServerConfig,
|
||||||
|
LiveAtlasChat,
|
||||||
|
LiveAtlasPartialComponentConfig,
|
||||||
|
LiveAtlasComponentConfig,
|
||||||
|
LiveAtlasUIModal,
|
||||||
|
LiveAtlasSidebarSectionState
|
||||||
} from "@/index";
|
} from "@/index";
|
||||||
import DynmapMapProvider from "@/providers/DynmapMapProvider";
|
import DynmapMapProvider from "@/providers/DynmapMapProvider";
|
||||||
import Pl3xmapMapProvider from "@/providers/Pl3xmapMapProvider";
|
import Pl3xmapMapProvider from "@/providers/Pl3xmapMapProvider";
|
||||||
@ -97,12 +102,27 @@ export type Mutations<S = State> = {
|
|||||||
|
|
||||||
export const mutations: MutationTree<State> & Mutations = {
|
export const mutations: MutationTree<State> & Mutations = {
|
||||||
[MutationTypes.INIT](state: State, config: LiveAtlasGlobalConfig) {
|
[MutationTypes.INIT](state: State, config: LiveAtlasGlobalConfig) {
|
||||||
const collapsedSections = localStorage.getItem('collapsedSections'),
|
const messageConfig = config?.messages || {},
|
||||||
messageConfig = config?.messages || {},
|
|
||||||
uiConfig = config?.ui || {};
|
uiConfig = config?.ui || {};
|
||||||
|
|
||||||
if(collapsedSections) {
|
try {
|
||||||
state.ui.sidebar.collapsedSections = new Set(JSON.parse(collapsedSections));
|
const uiSettings = JSON.parse(localStorage.getItem('uiSettings') || '{}');
|
||||||
|
|
||||||
|
if(uiSettings && uiSettings.sidebar) {
|
||||||
|
for(const element in uiSettings.sidebar) {
|
||||||
|
const elementState: LiveAtlasSidebarSectionState = uiSettings.sidebar[element];
|
||||||
|
|
||||||
|
if(!elementState) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(typeof state.ui.sidebar[element as LiveAtlasSidebarSection] !== 'undefined') {
|
||||||
|
state.ui.sidebar[element as LiveAtlasSidebarSection].collapsed = !!elementState.collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
console.warn('Failed to load saved UI settings', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
const messages: LiveAtlasGlobalMessageConfig = {
|
const messages: LiveAtlasGlobalMessageConfig = {
|
||||||
@ -615,11 +635,7 @@ export const mutations: MutationTree<State> & Mutations = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
[MutationTypes.TOGGLE_SIDEBAR_SECTION_COLLAPSED_STATE](state: State, section: LiveAtlasSidebarSection): void {
|
[MutationTypes.TOGGLE_SIDEBAR_SECTION_COLLAPSED_STATE](state: State, section: LiveAtlasSidebarSection): void {
|
||||||
if(state.ui.sidebar.collapsedSections.has(section)) {
|
state.ui.sidebar[section].collapsed = !state.ui.sidebar[section].collapsed;
|
||||||
state.ui.sidebar.collapsedSections.delete(section);
|
|
||||||
} else {
|
|
||||||
state.ui.sidebar.collapsedSections.add(section);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
[MutationTypes.SET_LOGGED_IN](state: State, payload: boolean): void {
|
[MutationTypes.SET_LOGGED_IN](state: State, payload: boolean): void {
|
||||||
|
@ -32,7 +32,10 @@ import {
|
|||||||
LiveAtlasPlayer,
|
LiveAtlasPlayer,
|
||||||
LiveAtlasMarkerSet,
|
LiveAtlasMarkerSet,
|
||||||
LiveAtlasComponentConfig,
|
LiveAtlasComponentConfig,
|
||||||
LiveAtlasServerConfig, LiveAtlasChat, LiveAtlasUIModal
|
LiveAtlasServerConfig,
|
||||||
|
LiveAtlasChat,
|
||||||
|
LiveAtlasUIModal,
|
||||||
|
LiveAtlasSidebarSectionState
|
||||||
} from "@/index";
|
} from "@/index";
|
||||||
import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition";
|
import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition";
|
||||||
|
|
||||||
@ -86,8 +89,8 @@ export type State = {
|
|||||||
previouslyVisibleElements: Set<LiveAtlasUIElement>;
|
previouslyVisibleElements: Set<LiveAtlasUIElement>;
|
||||||
|
|
||||||
sidebar: {
|
sidebar: {
|
||||||
collapsedSections: Set<LiveAtlasSidebarSection>;
|
[K in LiveAtlasSidebarSection]: LiveAtlasSidebarSectionState
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
parsedUrl?: LiveAtlasParsedUrl;
|
parsedUrl?: LiveAtlasParsedUrl;
|
||||||
@ -265,7 +268,9 @@ export const state: State = {
|
|||||||
previouslyVisibleElements: new Set(),
|
previouslyVisibleElements: new Set(),
|
||||||
|
|
||||||
sidebar: {
|
sidebar: {
|
||||||
collapsedSections: new Set(),
|
servers: {},
|
||||||
|
players: {},
|
||||||
|
maps: {},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user