UBER-177: fixed Filter pop-ups (#3225)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2023-05-20 23:01:09 -07:00 committed by GitHub
parent c0bb68be9e
commit 78034e6a00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 204 additions and 207 deletions

View File

@ -745,7 +745,7 @@
.list-container .datetime-button,
.list-container .datetime-button:hover {
background-color: var(--theme-list-button-color) !important;
.icon {
.icon, .btn-icon {
margin-right: .5rem;
color: var(--theme-halfcontent-color) !important;
}

View File

@ -48,11 +48,12 @@
max-width: 40rem !important;
}
.header {
margin-bottom: .5rem;
padding: .5rem;
border-bottom: 1px solid var(--theme-popup-divider);
&.no-border { border-bottom-color: transparent; }
&:not(.no-border) {
margin-bottom: .5rem;
border-bottom: 1px solid var(--theme-popup-divider);
}
.clear-btn {
display: flex;
justify-content: center;
@ -345,11 +346,13 @@
align-items: center;
flex-shrink: 0;
justify-content: flex-start;
margin: 0 .5rem;
padding: .25rem .5rem;
min-width: 0;
min-height: 2.25rem;
text-align: left;
color: var(--theme-caption-color);
border-radius: .25rem;
outline: none;
cursor: pointer;

View File

@ -153,11 +153,7 @@
>
<svelte:fragment slot="item" let:item={itemId}>
{@const item = filteredObjects[itemId]}
<button
class="menu-item withList w-full"
class:selected={item.isSelected}
on:click={() => dispatch('close', item.id)}
>
<button class="menu-item withList w-full" on:click={() => dispatch('close', item.id)}>
<div class="flex-row-center flex-grow pointer-events-none">
{#if item.component}
<div class="flex-grow clear-mins"><svelte:component this={item.component} {...item.props} /></div>

View File

@ -70,6 +70,7 @@
"DM": "Direct message",
"DMNotification": "Sent you a message",
"ConfigLabel": "Chat",
"ConfigDescription": "Extension to perform text communications"
"ConfigDescription": "Extension to perform text communications",
"LastMessage": "Last message"
}
}

View File

@ -70,6 +70,7 @@
"DM": "Личное сообщение",
"DMNotification": "Отправил сообщение",
"ConfigLabel": "Чат",
"ConfigDescription": "Расширение для текстовых переписок"
"ConfigDescription": "Расширение для текстовых переписок",
"LastMessage": "Последнее сообщение"
}
}

View File

@ -15,7 +15,7 @@
<script lang="ts">
import { ChannelProvider } from '@hcengineering/contact'
import { Ref } from '@hcengineering/core'
import { CheckBox, Icon, Label, resizeObserver } from '@hcengineering/ui'
import { IconCheck, Icon, Label, resizeObserver } from '@hcengineering/ui'
import { Filter } from '@hcengineering/view'
import { FILTER_DEBOUNCE_MS, FilterQuery, sortFilterValues } from '@hcengineering/view-resources'
import { createEventDispatcher } from 'svelte'
@ -65,28 +65,28 @@
</script>
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
<div class="menu-space" />
<div class="scroll">
<div class="box">
{#each sortFilterValues($channelProviders, (v) => isSelected(v, selected)) as element}
<button
class="menu-item"
class="menu-item no-focus flex-row-center content-pointer-events-none"
on:click={() => {
handleFilterToggle(element)
}}
>
<div class="flex-between w-full">
<div class="flex">
<div class="check pointer-events-none">
<CheckBox checked={isSelected(element, selected)} primary />
</div>
{#if element.icon}
<span class="mr-2"><Icon icon={element.icon} size="inline" /></span>
{/if}
<Label label={element.label} />
</div>
{#if element.icon}
<div class="icon"><Icon icon={element.icon} size={'small'} /></div>
{/if}
<span class="overflow-label label flex-grow"><Label label={element.label} /></span>
<div class="check">
{#if isSelected(element, selected)}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div>
</button>
{/each}
</div>
</div>
<div class="menu-space" />
</div>

View File

@ -17,11 +17,20 @@
import core, { Doc, FindResult, getObjectValue, Ref, SortingOrder, Space } from '@hcengineering/core'
import { translate } from '@hcengineering/platform'
import presentation, { getClient } from '@hcengineering/presentation'
import ui, { addNotification, deviceOptionsStore, Icon, IconCheck, Loading, resizeObserver } from '@hcengineering/ui'
import ui, {
addNotification,
deviceOptionsStore,
Icon,
IconCheck,
Loading,
resizeObserver,
EditWithIcon,
IconSearch
} from '@hcengineering/ui'
import { Filter } from '@hcengineering/view'
import { FILTER_DEBOUNCE_MS, FilterRemovedNotification, sortFilterValues } from '@hcengineering/view-resources'
import view from '@hcengineering/view-resources/src/plugin'
import { createEventDispatcher, onMount } from 'svelte'
import { createEventDispatcher } from 'svelte'
import EmployeePresenter from './EmployeePresenter.svelte'
export let filter: Filter
@ -113,15 +122,6 @@
}
let search: string = ''
let phTraslate: string = ''
let searchInput: HTMLInputElement
$: translate(presentation.string.Search, {}).then((res) => {
phTraslate = res
})
onMount(() => {
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
})
const dispatch = createEventDispatcher()
$: getValues(search)
@ -129,14 +129,16 @@
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
<div class="header">
<input
bind:this={searchInput}
type="text"
<EditWithIcon
icon={IconSearch}
size={'large'}
width={'100%'}
focus={!$deviceOptionsStore.isMobile}
bind:value={search}
placeholder={presentation.string.Search}
on:change={() => {
getValues(search)
}}
placeholder={phTraslate}
/>
</div>
<div class="scroll">
@ -146,24 +148,23 @@
{:else}
{#each sortFilterValues(values, (v) => isSelected(v, filter.value)) as value}
<button
class="menu-item no-focus"
class="menu-item no-focus flex-row-center"
on:click={() => {
handleFilterToggle(value)
}}
>
<div class="flex-between w-full">
<div class="flex-row-center">
<EmployeePresenter {value} shouldShowPlaceholder defaultName={ui.string.NotSelected} disabled />
</div>
<div class="pointer-events-none">
{#if isSelected(value, filter.value)}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div>
<div class="clear-mins flex-grow">
<EmployeePresenter {value} shouldShowPlaceholder defaultName={ui.string.NotSelected} disabled />
</div>
<div class="check pointer-events-none">
{#if isSelected(value, filter.value)}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div>
</button>
{/each}
{/if}
</div>
</div>
<div class="menu-space" />
</div>

View File

@ -27,12 +27,12 @@
</script>
{#if value}
<DocNavLink {disabled} object={value} {inline} component={recruit.component.EditVacancy}>
<DocNavLink {disabled} object={value} {inline} noUnderline={disabled} component={recruit.component.EditVacancy}>
<div class="flex-presenter" class:inline-presenter={inline} use:tooltip={{ label: getEmbeddedLabel(value.name) }}>
{#if !inline}
<div class="icon"><Icon icon={recruit.icon.Vacancy} size={'small'} /></div>
{/if}
<span class="label">{value.name}</span>
<span class="label" class:no-underline={disabled}>{value.name}</span>
</div>
</DocNavLink>
{/if}

View File

@ -14,13 +14,14 @@
-->
<script lang="ts">
import { Class, Doc, FindResult, Ref } from '@hcengineering/core'
import { translate } from '@hcengineering/platform'
import presentation, { getClient } from '@hcengineering/presentation'
import { TagCategory, TagElement } from '@hcengineering/tags'
import {
Button,
Icon,
IconCheck,
IconSearch,
EditWithIcon,
Label,
Loading,
deviceOptionsStore,
@ -31,7 +32,7 @@
} from '@hcengineering/ui'
import { Filter } from '@hcengineering/view'
import { FILTER_DEBOUNCE_MS, FilterQuery, sortFilterValues } from '@hcengineering/view-resources'
import { createEventDispatcher, onMount } from 'svelte'
import { createEventDispatcher } from 'svelte'
import tags from '../plugin'
import { tagLevel } from '../utils'
import WeightPopup from './WeightPopup.svelte'
@ -76,15 +77,6 @@
}
let search: string = ''
let phTraslate: string = ''
let searchInput: HTMLInputElement
$: translate(presentation.string.Search, {}).then((res) => {
phTraslate = res
})
onMount(() => {
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
})
const toggleGroup = (ev: MouseEvent): void => {
const el: HTMLElement = ev.currentTarget as HTMLElement
@ -137,18 +129,20 @@
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
<div class="header">
<input
bind:this={searchInput}
type="text"
<EditWithIcon
icon={IconSearch}
size={'large'}
width={'100%'}
focus={!$deviceOptionsStore.isMobile}
bind:value={search}
placeholder={presentation.string.Search}
on:change={() => {
getValues(search)
}}
placeholder={phTraslate}
/>
{#if schema !== '0'}
<div class="flex-row-center flex-between flex-grow p-1">
<Label label={tags.string.Weight} />
<div class="flex-between w-full mt-2">
<span class="overflow-label pl-2 mr-2"><Label label={tags.string.Weight} /></span>
<Button
label={tagLevelLabel}
icon={tagLevelIcon}
@ -170,9 +164,10 @@
{#if objectsPromise}
<Loading />
{:else}
{#each categories as cat}
{#each categories as cat, i}
{@const values = objects.filter((el) => el.category === cat._id)}
{#if values.length > 0}
{#if i > 0}<div class="menu-separator" />{/if}
<div class="sticky-wrapper">
<button
class="menu-group__header"
@ -198,21 +193,17 @@
<div class="menu-group">
{#each sortFilterValues(values, isSelected) as element}
<button
class="menu-item"
class="menu-item no-focus flex-row-center"
on:click={() => {
handleFilterToggle(element)
}}
>
<div class="flex-between w-full">
<div class="flex">
<div class="tag" style="background-color: {getPlatformColor(element.color)};" />
{element.title}
</div>
<div class="pointer-events-none">
{#if isSelected(element)}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div>
<div class="tag" style="background-color: {getPlatformColor(element.color)};" />
<span class="overflow-label label flex-grow">{element.title}</span>
<div class="check pointer-events-none">
{#if isSelected(element)}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div>
</button>
{/each}
@ -223,6 +214,7 @@
{/if}
</div>
</div>
<div class="menu-space" />
</div>
<style>

View File

@ -13,7 +13,7 @@
// limitations under the License.
-->
<script lang="ts">
import { Button, resizeObserver } from '@hcengineering/ui'
import { resizeObserver, Icon, IconCheck, Label } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import tags from '../plugin'
import { tagLevel } from '../utils'
@ -27,34 +27,36 @@
</script>
<div class="selectPopup max-width-40" use:resizeObserver={() => dispatch('changeContent')}>
<div class="header no-border p-3">
{#each labels as l, i}
<div class="flex gap-2 p-1">
<div class="menu-space" />
<div class="scroll">
<div class="box">
{#each labels as l, i}
{#if schema === '9'}
{#each Object.entries(tagLevel) as k, j}
{@const valueK = i * 3 + j}
<Button
label={l}
icon={k[1]}
size={'small'}
justify={'left'}
selected={value === valueK}
on:click={() => dispatch('close', valueK)}
width={'8rem'}
/>
<button class="menu-item flex-row-center" on:click={() => dispatch('close', valueK)}>
<div class="icon"><Icon icon={k[1]} size={'small'} /></div>
<span class="overflow-label label flex-grow"><Label label={l} /></span>
<div class="check pointer-events-none">
{#if value === valueK}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div>
</button>
{/each}
{:else}
{@const valueK = i * 3}
<Button
label={l}
size={'small'}
justify={'left'}
selected={value === valueK}
on:click={() => dispatch('close', valueK)}
width={'8rem'}
/>
<button class="menu-item flex-row-center" on:click={() => dispatch('close', valueK)}>
<span class="overflow-label label flex-grow"><Label label={l} /></span>
<div class="check pointer-events-none">
{#if value === valueK}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div>
</button>
{/if}
</div>
{/each}
{/each}
</div>
</div>
<div class="menu-space" />
</div>

View File

@ -23,6 +23,8 @@
export let inline: boolean = false
export let colorInherit: boolean = false
export let accent: boolean = false
export let disabled: boolean = false
export let oneLine: boolean = false
const dispatch = createEventDispatcher()
@ -46,7 +48,7 @@
{#if shouldShowAvatar}
<div class="state-container" class:inline style="background-color: {fill}" />
{/if}
<span class="label nowrap">{value.name}</span>
<span class="overflow-label label" class:nowrap={oneLine} class:no-underline={disabled}>{value.name}</span>
</div>
{/if}

View File

@ -14,13 +14,21 @@
-->
<script lang="ts">
import { DocumentQuery, FindResult, Ref, SortingOrder } from '@hcengineering/core'
import { translate } from '@hcengineering/platform'
import presentation, { getClient } from '@hcengineering/presentation'
import { Project, Milestone, MilestoneStatus } from '@hcengineering/tracker'
import ui, { CheckBox, Icon, Label, Loading, deviceOptionsStore, resizeObserver } from '@hcengineering/ui'
import ui, {
IconCheck,
Icon,
Label,
Loading,
deviceOptionsStore,
resizeObserver,
EditWithIcon,
IconSearch
} from '@hcengineering/ui'
import { FILTER_DEBOUNCE_MS, sortFilterValues } from '@hcengineering/view-resources'
import view, { Filter } from '@hcengineering/view'
import { createEventDispatcher, onMount } from 'svelte'
import { createEventDispatcher } from 'svelte'
import tracker from '../../plugin'
import { milestoneStatusAssets } from '../../types'
import MilestoneTitlePresenter from './MilestoneTitlePresenter.svelte'
@ -34,11 +42,6 @@
const dispatch = createEventDispatcher()
let search: string = ''
let phTraslate: string = ''
let searchInput: HTMLInputElement
$: translate(presentation.string.Search, {}).then((res) => {
phTraslate = res
})
let values: Milestone[] = []
let objectsPromise: Promise<FindResult<Milestone>> | undefined = undefined
@ -110,23 +113,21 @@
return res
}
onMount(() => {
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
})
getValues(search)
</script>
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
<div class="header">
<input
bind:this={searchInput}
type="text"
<EditWithIcon
icon={IconSearch}
size={'large'}
width={'100%'}
focus={!$deviceOptionsStore.isMobile}
bind:value={search}
placeholder={presentation.string.Search}
on:change={() => {
getValues(search)
}}
placeholder={phTraslate}
/>
</div>
<div class="scroll">
@ -135,41 +136,46 @@
<Loading />
{:else}
<button
class="menu-item"
class="menu-item no-focus flex-row-center"
on:click={() => {
handleFilterToggle(undefined)
}}
>
<div class="flex clear-mins">
<div class="check pointer-events-none">
<CheckBox checked={isSelected(undefined, selectedValues)} primary />
</div>
<div class="overflow-label flex-grow">
<Label label={ui.string.NotSelected} />
</div>
<div class="check pointer-events-none">
{#if isSelected(undefined, selectedValues)}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div>
</button>
{#each getStatuses() as group}
{@const status = milestoneStatusAssets[group]}
{@const items = getStatusItem(group, values)}
{#if items.length > 0}
<div class="flex-row-center p-1">
<Icon icon={status.icon} size={'small'} />
<div class="ml-2">
<Label label={status.label} />
<div class="menu-separator" />
<div class="menu-group__header">
<div class="flex-row-center gap-2">
<Icon icon={status.icon} size={'small'} />
<span class="overflow-label"><Label label={status.label} /></span>
</div>
</div>
{#each sortFilterValues(items, (v) => isSelected(v._id, selectedValues)) as doc}
<button
class="menu-item"
class="menu-item no-focus flex-row-center"
on:click={() => {
handleFilterToggle(doc._id)
}}
>
<div class="flex clear-mins">
<div class="check pointer-events-none">
<CheckBox checked={isSelected(doc._id, selectedValues)} primary />
</div>
<div class="flex-grow clear-mins">
<MilestoneTitlePresenter value={doc} />
</div>
<div class="check pointer-events-none">
{#if isSelected(doc._id, selectedValues)}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div>
</button>
{/each}
{/if}
@ -177,4 +183,5 @@
{/if}
</div>
</div>
<div class="menu-space" />
</div>

View File

@ -265,6 +265,7 @@
</script>
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
<div class="menu-space" />
<Scroller>
{#if nestedFrom}
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
@ -320,15 +321,9 @@
</button>
{/if}
{#if nextDiffCat(types, i)}
<div class="divider" />
<div class="menu-separator" />
{/if}
{/each}
</Scroller>
<div class="menu-space" />
</div>
<style lang="scss">
.divider {
height: 1px;
background-color: var(--theme-popup-divider);
}
</style>

View File

@ -20,13 +20,15 @@
addNotification,
Icon,
IconCheck,
IconSearch,
deviceOptionsStore,
Label,
Loading,
resizeObserver
resizeObserver,
EditWithIcon
} from '@hcengineering/ui'
import { Filter } from '@hcengineering/view'
import { createEventDispatcher, onMount } from 'svelte'
import { createEventDispatcher } from 'svelte'
import view from '../../plugin'
import { FILTER_DEBOUNCE_MS, sortFilterValues } from '../../filter'
import { buildConfigLookup, getPresenter } from '../../utils'
@ -152,15 +154,6 @@
}
let search: string = ''
let phTraslate: string = ''
let searchInput: HTMLInputElement
$: translate(presentation.string.Search, {}).then((res) => {
phTraslate = res
})
onMount(() => {
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
})
const dispatch = createEventDispatcher()
$: if (targetClass) getValues(search)
@ -169,16 +162,20 @@
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
{#if clazz.sortingKey}
<div class="header">
<input
bind:this={searchInput}
type="text"
<EditWithIcon
icon={IconSearch}
size={'large'}
width={'100%'}
focus={!$deviceOptionsStore.isMobile}
bind:value={search}
placeholder={presentation.string.Search}
on:change={() => {
getValues(search)
}}
placeholder={phTraslate}
/>
</div>
{:else}
<div class="menu-space" />
{/if}
<div class="scroll">
<div class="box">
@ -188,7 +185,7 @@
{:else}
{#each sortFilterValues(values, (v) => isSelected(v, filter.value)) as value}
<button
class="menu-item no-focus"
class="menu-item no-focus content-pointer-events-none"
on:click={() => {
handleFilterToggle(value)
}}
@ -215,4 +212,5 @@
{/await}
</div>
</div>
<div class="menu-space" />
</div>

View File

@ -13,10 +13,9 @@
// limitations under the License.
-->
<script lang="ts">
import { translate } from '@hcengineering/platform'
import { Button, resizeObserver, deviceOptionsStore } from '@hcengineering/ui'
import { Button, resizeObserver, deviceOptionsStore, EditWithIcon, IconSearch } from '@hcengineering/ui'
import { Filter } from '@hcengineering/view'
import { onMount, createEventDispatcher } from 'svelte'
import { createEventDispatcher } from 'svelte'
import view from '../../plugin'
export let filter: Filter
@ -24,9 +23,7 @@
const dispatch = createEventDispatcher()
let searchInput: HTMLInputElement
let search = filter.value[0] ?? ''
let phTraslate = ''
filter.modes = [view.filter.FilterContains]
filter.mode ??= filter.modes[0]
@ -49,19 +46,19 @@
onChange(filter)
dispatch('close')
}
$: translate(filter.key.label, {}).then((res) => {
phTraslate = res
})
onMount(() => {
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
})
</script>
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')} on:keydown={onKeyDown}>
<div class="header">
<input bind:this={searchInput} bind:value={search} type="text" placeholder={phTraslate} />
<div class="header no-border">
<EditWithIcon
icon={IconSearch}
size={'large'}
width={'100%'}
focus={!$deviceOptionsStore.isMobile}
bind:value={search}
placeholder={filter.key.label}
on:change
/>
</div>
<Button shape="filter" label={view.string.Apply} on:click={save} />
</div>

View File

@ -14,11 +14,19 @@
-->
<script lang="ts">
import core, { Class, Doc, FindResult, getObjectValue, Ref, SortingOrder, Space } from '@hcengineering/core'
import { translate } from '@hcengineering/platform'
import presentation, { getClient } from '@hcengineering/presentation'
import ui, { Icon, IconCheck, Label, Loading, resizeObserver, deviceOptionsStore } from '@hcengineering/ui'
import ui, {
EditWithIcon,
Icon,
IconSearch,
IconCheck,
Label,
Loading,
resizeObserver,
deviceOptionsStore
} from '@hcengineering/ui'
import { Filter } from '@hcengineering/view'
import { onMount, createEventDispatcher } from 'svelte'
import { createEventDispatcher } from 'svelte'
import { getPresenter } from '../../utils'
import { FILTER_DEBOUNCE_MS, sortFilterValues } from '../../filter'
import view from '../../plugin'
@ -127,34 +135,29 @@
}
let search: string = ''
let phTraslate: string = ''
let searchInput: HTMLInputElement
$: translate(presentation.string.Search, {}).then((res) => {
phTraslate = res
})
const dispatch = createEventDispatcher()
onMount(() => {
if (searchInput && !$deviceOptionsStore.isMobile) searchInput.focus()
})
getValues(search)
</script>
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
{#if isSearchable}
<div class="header">
<input
bind:this={searchInput}
type="text"
<EditWithIcon
icon={IconSearch}
size={'large'}
width={'100%'}
focus={!$deviceOptionsStore.isMobile}
bind:value={search}
placeholder={presentation.string.Search}
on:change={() => {
getValues(search)
}}
placeholder={phTraslate}
/>
</div>
{:else}
<div class="menu-space" />
{/if}
<div class="scroll">
<div class="box">
@ -165,29 +168,27 @@
{#each sortFilterValues([...values.keys()], (v) => isSelected(v, selectedValues)) as value}
{@const realValue = [...(realValues.get(value) ?? [])][0]}
<button
class="menu-item no-focus"
class="menu-item no-focus content-pointer-events-none"
on:click={() => {
handleFilterToggle(value)
}}
>
<div class="flex-between w-full">
<div class="flex-row-center">
{#if value !== undefined}
<svelte:component
this={attribute.presenter}
value={typeof value === 'string' ? realValue : value}
{...attribute.props}
oneLine
/>
{:else}
<Label label={ui.string.NotSelected} />
{/if}
</div>
<div class="pointer-events-none">
{#if isSelected(value, selectedValues)}
<Icon icon={IconCheck} size={'small'} />
{/if}
{#if value !== undefined}
<div class="clear-mins flex-grow">
<svelte:component
this={attribute.presenter}
value={typeof value === 'string' ? realValue : value}
{...attribute.props}
oneLine
/>
</div>
{:else}
<span class="overflow-label flex-grow"><Label label={ui.string.NotSelected} /></span>
{/if}
<div class="check pointer-events-none">
{#if isSelected(value, selectedValues)}
<Icon icon={IconCheck} size={'small'} />
{/if}
</div>
</button>
{/each}
@ -195,4 +196,5 @@
{/await}
</div>
</div>
<div class="menu-space" />
</div>