diff --git a/app/assets/styles.css b/app/assets/styles.css index ff8f783..87a5a16 100644 --- a/app/assets/styles.css +++ b/app/assets/styles.css @@ -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; diff --git a/app/components/icons/dots-horizontal.js b/app/components/icons/dots-horizontal.js new file mode 100644 index 0000000..1fbd917 --- /dev/null +++ b/app/components/icons/dots-horizontal.js @@ -0,0 +1 @@ +export { DotsHorizontal as default } from 'ember-mdi'; diff --git a/app/components/icons/menu.js b/app/components/icons/menu.js new file mode 100644 index 0000000..066b681 --- /dev/null +++ b/app/components/icons/menu.js @@ -0,0 +1 @@ +export { Menu as default } from 'ember-mdi'; diff --git a/app/components/mobile-bar.hbs b/app/components/mobile-bar.hbs new file mode 100644 index 0000000..d0b85c1 --- /dev/null +++ b/app/components/mobile-bar.hbs @@ -0,0 +1,20 @@ +
+ + + + MeiliAdmin + +
+{{!-- {{@siteName}} --}} diff --git a/app/components/mobile-bar.js b/app/components/mobile-bar.js new file mode 100644 index 0000000..950d3f9 --- /dev/null +++ b/app/components/mobile-bar.js @@ -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'); + } +} diff --git a/app/components/sidenav-background.hbs b/app/components/sidenav-background.hbs new file mode 100644 index 0000000..7645682 --- /dev/null +++ b/app/components/sidenav-background.hbs @@ -0,0 +1,5 @@ +
diff --git a/app/components/sidenav-background.js b/app/components/sidenav-background.js new file mode 100644 index 0000000..6ffb288 --- /dev/null +++ b/app/components/sidenav-background.js @@ -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'); + } +} diff --git a/app/templates/admin.hbs b/app/templates/admin.hbs index 24bd76d..25d6cd8 100644 --- a/app/templates/admin.hbs +++ b/app/templates/admin.hbs @@ -1,18 +1,16 @@ -
-
- - MeiliAdmin - +
+ - {{#let - 'flex items-center px-4 py-2 font-semibold text-lg text-base-2' - as |classLink| - }} - - - {{/let}} -
+ + {{/let}} +
+ -
+
{{outlet}} -
+
diff --git a/config/tailwind.config.js b/config/tailwind.config.js index 0d6ca9f..b78faf0 100644 --- a/config/tailwind.config.js +++ b/config/tailwind.config.js @@ -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: { diff --git a/tests/integration/components/mobile-bar-test.js b/tests/integration/components/mobile-bar-test.js new file mode 100644 index 0000000..911881c --- /dev/null +++ b/tests/integration/components/mobile-bar-test.js @@ -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``); + + assert.dom(this.element).hasText(''); + + // Template block usage: + await render(hbs` + + template block text + + `); + + assert.dom(this.element).hasText('template block text'); + }); +}); diff --git a/tests/integration/components/sidenav-background-test.js b/tests/integration/components/sidenav-background-test.js new file mode 100644 index 0000000..d08629d --- /dev/null +++ b/tests/integration/components/sidenav-background-test.js @@ -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``); + + assert.dom(this.element).hasText(''); + + // Template block usage: + await render(hbs` + + template block text + + `); + + assert.dom(this.element).hasText('template block text'); + }); +});