Add mobile menu
This commit is contained in:
parent
fc53449cad
commit
46611e86e1
11 changed files with 317 additions and 60 deletions
|
|
@ -25,6 +25,22 @@
|
|||
|
||||
:root {
|
||||
@mixin light-vars;
|
||||
|
||||
--sidenav-width: 300px;
|
||||
--header-height: 3.5rem;
|
||||
|
||||
--spacing-1: 0.25rem;
|
||||
--spacing-2: 0.5rem;
|
||||
--spacing-3: 0.75rem;
|
||||
--spacing-4: 1rem;
|
||||
|
||||
--z-index-scroll-link: 10;
|
||||
--z-index-mobile-bar: 20;
|
||||
--z-index-sidenav: 30;
|
||||
--z-index-modal-overlay: 40;
|
||||
--z-index-modal: 50;
|
||||
--z-index-dropdown: 60;
|
||||
--z-index-context-menu: 70;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
|
|
@ -51,6 +67,137 @@
|
|||
}
|
||||
}
|
||||
|
||||
body {
|
||||
&.sidebar-is-opened {
|
||||
overflow: hidden;
|
||||
|
||||
.sidenav {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.sidenav-background {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.sidenav-sections {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.app {
|
||||
display: grid;
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: 1fr auto;
|
||||
grid-template-areas: 'main';
|
||||
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.sidenav {
|
||||
grid-area: sidenav;
|
||||
position: fixed;
|
||||
z-index: var(--z-index-sidenav);
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
visibility: hidden;
|
||||
transition-property: visibility;
|
||||
@apply border-r;
|
||||
}
|
||||
|
||||
.sidenav-background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
transition-property: opacity;
|
||||
transform: translateZ(0);
|
||||
opacity: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.sidenav-sections {
|
||||
transition-duration: 200ms;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: var(--sidenav-width);
|
||||
transition-property: transform;
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
@apply bg-base-7 p-4;
|
||||
}
|
||||
|
||||
.main {
|
||||
grid-area: main;
|
||||
padding: calc(var(--spacing-4) + var(--header-height)) var(--spacing-4) var(--spacing-4);
|
||||
@apply bg-base-7;
|
||||
}
|
||||
|
||||
.mobile-bar {
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: var(--header-height);
|
||||
width: 100%;
|
||||
z-index: var(--z-index-mobile-bar);
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
/* min-width: calc(var(--sidenav-width) - 2px); */
|
||||
@apply bg-base-7;
|
||||
|
||||
& > button {
|
||||
position: absolute;
|
||||
padding: var(--spacing-3);
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
|
||||
&:focus {
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: theme("screens.lg")) {
|
||||
body.sidebar-is-opened {
|
||||
overflow: initial;
|
||||
}
|
||||
|
||||
.app {
|
||||
grid-template-columns: var(--sidenav-width) calc(100% - var(--sidenav-width));
|
||||
grid-template-areas: "sidenav main";
|
||||
}
|
||||
|
||||
.sidenav {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.sidenav-background {
|
||||
opacity: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidenav-sections {
|
||||
position: relative;
|
||||
transform: none;
|
||||
transition-duration: none;
|
||||
position: initial;
|
||||
top: initial;
|
||||
bottom: initial;
|
||||
left: initial;
|
||||
width: auto;
|
||||
transition-property: initial;
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: var(--spacing-4);
|
||||
}
|
||||
}
|
||||
|
||||
.royal-table {
|
||||
@apply table-auto text-left mb-4;
|
||||
|
||||
|
|
|
|||
1
app/components/icons/dots-horizontal.js
Normal file
1
app/components/icons/dots-horizontal.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { DotsHorizontal as default } from 'ember-mdi';
|
||||
1
app/components/icons/menu.js
Normal file
1
app/components/icons/menu.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { Menu as default } from 'ember-mdi';
|
||||
20
app/components/mobile-bar.hbs
Normal file
20
app/components/mobile-bar.hbs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<div class="mobile-bar" ...attributes>
|
||||
<button
|
||||
type='button'
|
||||
class='inline-flex items-center lg:hidden'
|
||||
aria-label='Toggle sidebar'
|
||||
{{on 'click' this.toggleSidebar}}
|
||||
>
|
||||
<Icons::Menu @title='Menu' />
|
||||
</button>
|
||||
|
||||
<LinkTo @route="index" class='text-2xl font-display flex-1 flex items-center justify-center'>
|
||||
MeiliAdmin
|
||||
</LinkTo>
|
||||
</div>
|
||||
{{!-- <a
|
||||
href='/'
|
||||
title='{{@siteName}}'
|
||||
class='text-2xl font-display flex-1 flex items-center justify-center lg:mt-6'
|
||||
{{on 'click' this.closeSidebar}}
|
||||
>{{@siteName}}</a> --}}
|
||||
14
app/components/mobile-bar.js
Normal file
14
app/components/mobile-bar.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
export default class MobileBarComponent extends Component {
|
||||
@action
|
||||
toggleSidebar() {
|
||||
document.body.classList.toggle('sidebar-is-opened');
|
||||
}
|
||||
|
||||
@action
|
||||
closeSidebar() {
|
||||
document.body.classList.remove('sidebar-is-opened');
|
||||
}
|
||||
}
|
||||
5
app/components/sidenav-background.hbs
Normal file
5
app/components/sidenav-background.hbs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<div
|
||||
role='button'
|
||||
class='sidenav-background'
|
||||
{{on 'click' this.closeSidebar}}
|
||||
></div>
|
||||
9
app/components/sidenav-background.js
Normal file
9
app/components/sidenav-background.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
export default class SidenavBackgroundComponent extends Component {
|
||||
@action
|
||||
closeSidebar() {
|
||||
document.body.classList.remove('sidebar-is-opened');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,16 @@
|
|||
<div class='relative min-h-screen flex'>
|
||||
<div class='flex flex-col w-64 min-h-screen px-4 py-4 border-r'>
|
||||
<LinkTo
|
||||
@route='admin'
|
||||
class='flex items-center justify-center font-semibold text-xl mt-4 mb-8'
|
||||
>
|
||||
MeiliAdmin
|
||||
</LinkTo>
|
||||
<div class='app'>
|
||||
<MobileBar class='fixed flex shadow-sm lg:hidden' />
|
||||
|
||||
{{#let
|
||||
'flex items-center px-4 py-2 font-semibold text-lg text-base-2'
|
||||
as |classLink|
|
||||
}}
|
||||
<nav class='flex flex-col flex-1 mb-4'>
|
||||
{{!-- <div class='px-4 py-2 text-sm text-base-3'>Indexes</div>
|
||||
<aside class='sidenav'>
|
||||
<SidenavBackground />
|
||||
<div class='sidenav-sections'>
|
||||
<MobileBar class='relative flex mb-4' />
|
||||
{{#let
|
||||
'flex items-center px-4 py-2 font-semibold text-lg text-base-2'
|
||||
as |classLink|
|
||||
}}
|
||||
<nav class='flex flex-col flex-1 mb-4'>
|
||||
{{!-- <div class='px-4 py-2 text-sm text-base-3'>Indexes</div>
|
||||
{{#each @model.results as |item|}}
|
||||
<LinkTo
|
||||
@route='admin.indexes.item'
|
||||
|
|
@ -23,57 +21,58 @@
|
|||
{{capitalize item.uid}}
|
||||
</LinkTo>
|
||||
{{/each}} --}}
|
||||
<LinkTo @route='admin.indexes.index' class={{classLink}}>
|
||||
<Icons::FolderMultipleOutline class='fill-base-3 mr-2' />
|
||||
Indexes
|
||||
</LinkTo>
|
||||
<LinkTo @route='admin.tasks.index' class={{classLink}}>
|
||||
<Icons::FormatListChecks class='fill-base-3 mr-2' />
|
||||
Tasks
|
||||
</LinkTo>
|
||||
<LinkTo @route='admin.keys.index' class={{classLink}}>
|
||||
<Icons::KeyOutline class='fill-base-3 mr-2' />
|
||||
Keys
|
||||
</LinkTo>
|
||||
<LinkTo @route='admin.indexes.index' class={{classLink}}>
|
||||
<Icons::FolderMultipleOutline class='fill-base-3 mr-2' />
|
||||
Indexes
|
||||
</LinkTo>
|
||||
<LinkTo @route='admin.tasks.index' class={{classLink}}>
|
||||
<Icons::FormatListChecks class='fill-base-3 mr-2' />
|
||||
Tasks
|
||||
</LinkTo>
|
||||
<LinkTo @route='admin.keys.index' class={{classLink}}>
|
||||
<Icons::KeyOutline class='fill-base-3 mr-2' />
|
||||
Keys
|
||||
</LinkTo>
|
||||
|
||||
<Divider />
|
||||
<Divider />
|
||||
|
||||
<a
|
||||
href='https://docs.meilisearch.com/'
|
||||
class={{classLink}}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
<Icons::HelpCircleOutline class='fill-base-3 mr-2' />
|
||||
Documentation
|
||||
</a>
|
||||
<a
|
||||
href='https://github.com/kaermorchen/meiliadmin'
|
||||
class={{classLink}}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
<Icons::Github class='fill-base-3 mr-2' />
|
||||
MeiliAdmin
|
||||
</a>
|
||||
<a
|
||||
href='https://docs.meilisearch.com/'
|
||||
class={{classLink}}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
<Icons::HelpCircleOutline class='fill-base-3 mr-2' />
|
||||
Documentation
|
||||
</a>
|
||||
<a
|
||||
href='https://github.com/kaermorchen/meiliadmin'
|
||||
class={{classLink}}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
<Icons::Github class='fill-base-3 mr-2' />
|
||||
MeiliAdmin
|
||||
</a>
|
||||
|
||||
<Divider />
|
||||
<Divider />
|
||||
|
||||
<button
|
||||
type='button'
|
||||
{{on 'click' this.invalidateSession}}
|
||||
class={{classLink}}
|
||||
>
|
||||
<Icons::Logout class='fill-base-3 mr-2' />
|
||||
Logout
|
||||
</button>
|
||||
</nav>
|
||||
<button
|
||||
type='button'
|
||||
{{on 'click' this.invalidateSession}}
|
||||
class={{classLink}}
|
||||
>
|
||||
<Icons::Logout class='fill-base-3 mr-2' />
|
||||
Logout
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<ThemeToggler />
|
||||
{{/let}}
|
||||
</div>
|
||||
<ThemeToggler />
|
||||
{{/let}}
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class='flex-1 p-4'>
|
||||
<main class='main'>
|
||||
{{outlet}}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,15 @@ module.exports = {
|
|||
dark: colors.green['800'],
|
||||
},
|
||||
},
|
||||
zIndex: {
|
||||
'scroll-link': '10',
|
||||
'mobile-bar': '20',
|
||||
sidenav: '30',
|
||||
'modal-overlay': '40',
|
||||
modal: '50',
|
||||
dropdown: '60',
|
||||
'context-menu': '70',
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
|
|
|
|||
26
tests/integration/components/mobile-bar-test.js
Normal file
26
tests/integration/components/mobile-bar-test.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'meiliadmin/tests/helpers';
|
||||
import { render } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
module('Integration | Component | mobile-bar', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.set('myAction', function(val) { ... });
|
||||
|
||||
await render(hbs`<MobileBar />`);
|
||||
|
||||
assert.dom(this.element).hasText('');
|
||||
|
||||
// Template block usage:
|
||||
await render(hbs`
|
||||
<MobileBar>
|
||||
template block text
|
||||
</MobileBar>
|
||||
`);
|
||||
|
||||
assert.dom(this.element).hasText('template block text');
|
||||
});
|
||||
});
|
||||
26
tests/integration/components/sidenav-background-test.js
Normal file
26
tests/integration/components/sidenav-background-test.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { module, test } from 'qunit';
|
||||
import { setupRenderingTest } from 'meiliadmin/tests/helpers';
|
||||
import { render } from '@ember/test-helpers';
|
||||
import { hbs } from 'ember-cli-htmlbars';
|
||||
|
||||
module('Integration | Component | sidenav-background', function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function (assert) {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.set('myAction', function(val) { ... });
|
||||
|
||||
await render(hbs`<SidenavBackground />`);
|
||||
|
||||
assert.dom(this.element).hasText('');
|
||||
|
||||
// Template block usage:
|
||||
await render(hbs`
|
||||
<SidenavBackground>
|
||||
template block text
|
||||
</SidenavBackground>
|
||||
`);
|
||||
|
||||
assert.dom(this.element).hasText('template block text');
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue