summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorivarlovlie <git@ivarlovlie.no>2022-06-30 01:04:48 +0200
committerivarlovlie <git@ivarlovlie.no>2022-06-30 01:04:48 +0200
commit6f16b7ca72899e2ae81f4669cdf1b10a43c692e7 (patch)
treed2b1e249a0a9e953316dac9bfbcd415eda893e92 /apps
parenta19e31557f6ef33ed33d694968abe7416e878c60 (diff)
downloadgreatoffice-6f16b7ca72899e2ae81f4669cdf1b10a43c692e7.tar.xz
greatoffice-6f16b7ca72899e2ae81f4669cdf1b10a43c692e7.zip
latest from desktop
Diffstat (limited to 'apps')
-rw-r--r--apps/projects/src/_assets/projects.pngbin0 -> 7951 bytes
-rw-r--r--apps/projects/src/app/index.scss1
-rw-r--r--apps/projects/src/app/pages/_layout.svelte200
-rw-r--r--apps/web-shared/src/assets/logos/projects.pngbin0 -> 7951 bytes
-rw-r--r--apps/web-shared/src/styles/components/side-navigation.scss233
-rw-r--r--apps/web-shared/src/styles/components/vanilla-responsive-sidebar.scss146
6 files changed, 531 insertions, 49 deletions
diff --git a/apps/projects/src/_assets/projects.png b/apps/projects/src/_assets/projects.png
new file mode 100644
index 0000000..e49191f
--- /dev/null
+++ b/apps/projects/src/_assets/projects.png
Binary files differ
diff --git a/apps/projects/src/app/index.scss b/apps/projects/src/app/index.scss
index 0892d63..b47151f 100644
--- a/apps/projects/src/app/index.scss
+++ b/apps/projects/src/app/index.scss
@@ -37,3 +37,4 @@
@use '../../web-shared/src/styles/components/menu';
@use '../../web-shared/src/styles/components/user-menu';
@use '../../web-shared/src/styles/components/light-dark-switch';
+@use '../../web-shared/src/styles/components/side-navigation';
diff --git a/apps/projects/src/app/pages/_layout.svelte b/apps/projects/src/app/pages/_layout.svelte
index f725397..594fe9e 100644
--- a/apps/projects/src/app/pages/_layout.svelte
+++ b/apps/projects/src/app/pages/_layout.svelte
@@ -25,56 +25,158 @@
<ProfileModal bind:functions={ProfileModalFunctions}/>
<BlowoutToolbelt/>
-<nav class="container max-width-xl@md width-fit-content@md width-100% max-width-none margin-y-xs@md margin-bottom-xs block@md position-relative@md position-fixed z-index-fixed-element bottom-unset@md bottom-0">
- <div class="tabs-nav-v2 justify-between">
- <div class="tab-v2">
- <div class="tab-v2">
- <a href="/home"
- use:link
- class="tabs-nav-v2__item {($location === '/' || $location.startsWith('/home')) ? 'tabs-nav-v2__item--selected' : ''}">{$LL.nav.home()}</a>
- </div>
- <div class="tab-v2">
- <a href="/data"
- use:link
- class="tabs-nav-v2__item {$location.startsWith('/data') ? 'tabs-nav-v2__item--selected' : ''}">{$LL.nav.data()}</a>
- </div>
- <div class="tab-v2">
- <a href="/settings"
- use:link
- class="tabs-nav-v2__item {$location.startsWith('/settings') ? 'tabs-nav-v2__item--selected' : ''}">{$LL.nav.settings()}</a>
+<header class="position-sticky top-0 z-index-header bg shadow-xs padding-x-component padding-y-sm flex items-center justify-between hide@md">
+ <a class="block size-32 hover:reduce-opacity"
+ href="#">
+ <svg class="block"
+ viewBox="0 0 40 40">
+ <circle fill="var(--color-contrast-higher)"
+ cx="20"
+ cy="20"
+ r="20"/>
+ <path d="M12.64,20.564a6.437,6.437,0,0,0-4.4,1.388S10,24.2,12.133,24.475a6.486,6.486,0,0,0,3.625-.846S14.455,20.8,12.64,20.564Z"
+ fill="var(--color-bg)"/>
+ <path d="M22.036,13.407a7.041,7.041,0,0,0-1.111-3.88s-3,1.562-3.152,3.54a6.978,6.978,0,0,0,1.739,4.688S21.851,15.73,22.036,13.407Z"
+ fill="var(--color-bg)"/>
+ <path d="M29.048,26.433a7.624,7.624,0,0,0-.321-4.122c-1.052-2.448-4.326-3.784-4.326-3.784a7.973,7.973,0,0,0-.164,5.713A3.294,3.294,0,0,0,25.451,25.6,16.016,16.016,0,0,1,14.758,10.527v-1h-2v1A17.988,17.988,0,0,0,21.19,25.746a5.859,5.859,0,0,0-2.433-.151,8.093,8.093,0,0,0-4,2.352s2.6,2.883,4.846,2.49a7.889,7.889,0,0,0,4.627-3.153,17.885,17.885,0,0,0,6.527,1.243h1v-2h-1A16.094,16.094,0,0,1,29.048,26.433Z"
+ fill="var(--color-bg)"/>
+ </svg>
+ </a>
+
+ <button class="btn btn--subtle">Menu</button>
+</header>
+
+<div class="flex@md">
+ <aside class="sidebar sidebar--static@md sidebar--is-visible"
+ data-static-class="position-relative z-index-2 bg-dark flex flex-column">
+ <div class="sidebar__panel flex-grow flex flex-column">
+ <header class="sidebar__header bg padding-y-sm padding-left-md padding-right-sm border-bottom z-index-2">
+ <h1 class="text-md text-truncate">Menu</h1>
+
+ <button class="reset sidebar__close-btn">
+ <svg class="icon icon--xs"
+ viewBox="0 0 16 16"><title>Close panel</title>
+ <g stroke-width="2"
+ stroke="currentColor"
+ fill="none"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-miterlimit="10">
+ <line x1="13.5"
+ y1="2.5"
+ x2="2.5"
+ y2="13.5"></line>
+ <line x1="2.5"
+ y1="2.5"
+ x2="13.5"
+ y2="13.5"></line>
+ </g>
+ </svg>
+ </button>
+ </header>
+
+ <header class="display@md padding-x-xs margin-bottom-lg">
+ <div class="flex items-center justify-between padding-right-xs padding-left-xxxs">
+ <a class="block hover:reduce-opacity width-xl"
+ href="#">
+ <img src="/_assets/projects.png"
+ alt="Projects from Greatoffice">
+ </a>
+ </div>
+ </header>
+
+ <div class="position-relative z-index-1">
+ <nav class="sidenav-v4 padding-x-xs padding-bottom-xs">
+ <ul>
+ <li class="sidenav-v4__item">
+ <a href="/home"
+ use:link
+ class="sidenav-v4__link {($location === '/' || $location.startsWith('/home')) ? 'tabs-nav-v2__item--selected' : ''}">{$LL.nav.home()}</a>
+ </li>
+ <li class="sidenav-v4__item">
+ <a href="/data"
+ use:link
+ class="sidenav-v4__link {$location.startsWith('/data') ? 'tabs-nav-v2__item--selected' : ''}">{$LL.nav.data()}</a>
+ </li>
+ <li class="sidenav-v4__item">
+ <a href="/settings"
+ use:link
+ class="sidenav-v4__link {$location.startsWith('/settings') ? 'tabs-nav-v2__item--selected' : ''}">{$LL.nav.settings()}</a>
+ </li>
+ </ul>
+ </nav>
+
+ <div class="padding-x-xs padding-bottom-sm hide@md">
+ <div class="padding-x-sm">
+ <div class="search-input search-input--icon-left text-md">
+ <input class="search-input__input form-control"
+ type="search"
+ name="search-input"
+ id="search-input"
+ placeholder="Search..."
+ aria-label="Search">
+ <button class="search-input__btn">
+ <svg class="icon"
+ viewBox="0 0 20 20"><title>Submit</title>
+ <g fill="none"
+ stroke="currentColor"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ stroke-width="2">
+ <circle cx="8"
+ cy="8"
+ r="6"/>
+ <line x1="12.242"
+ y1="12.242"
+ x2="18"
+ y2="18"/>
+ </g>
+ </svg>
+ </button>
+ </div>
+ </div>
+ </div>
</div>
+
+ <footer class="sidebar__footer border-top border-alpha padding-xs margin-top-auto position-sticky bottom-0 z-index-1">
+ </footer>
</div>
- <div class="tab-v2 padding-x-sm">
- <Button class="user-menu-control"
- variant="reset"
- id="open-user-menu"
- on:click={() => showUserMenu = !showUserMenu}
- text={username}
- icon={IconNames.chevronDown}
- icon_width="2rem"
- icon_height="2rem"
- icon_right_aligned="true"
- title="{$LL.nav.usermenu.toggleTitle()}"
- aria-controls="{userMenuId}"
- />
- <Menu bind:show="{showUserMenu}"
- trigger={userMenuTriggerNode}
- id="{userMenuId}">
- <div slot="options">
- <MenuItem on:click={() => ProfileModalFunctions.open()}>
- <span title="{$LL.nav.usermenu.profileTitle()}">{$LL.nav.usermenu.profile()}</span>
- </MenuItem>
- <MenuItemSeparator/>
- <MenuItem danger="true"
- on:click={() => logout_user()}>
- <span title="{$LL.nav.usermenu.logoutTitle()}">{$LL.nav.usermenu.logout()}</span>
- </MenuItem>
- </div>
- </Menu>
+ </aside>
+
+ <nav class="container max-width-xl@md width-fit-content@md width-100% max-width-none margin-y-xs@md margin-bottom-xs block@md position-relative@md position-fixed z-index-fixed-element bottom-unset@md bottom-0 is-hidden">
+ <div class="tabs-nav-v2 justify-between">
+ <div class="tab-v2 padding-x-sm">
+ <Button class="user-menu-control"
+ variant="reset"
+ id="open-user-menu"
+ on:click={() => showUserMenu = !showUserMenu}
+ text={username}
+ icon={IconNames.chevronDown}
+ icon_width="2rem"
+ icon_height="2rem"
+ icon_right_aligned="true"
+ title="{$LL.nav.usermenu.toggleTitle()}"
+ aria-controls="{userMenuId}"
+ />
+ <Menu bind:show="{showUserMenu}"
+ trigger={userMenuTriggerNode}
+ id="{userMenuId}">
+ <div slot="options">
+ <MenuItem on:click={() => ProfileModalFunctions.open()}>
+ <span title="{$LL.nav.usermenu.profileTitle()}">{$LL.nav.usermenu.profile()}</span>
+ </MenuItem>
+ <MenuItemSeparator/>
+ <MenuItem danger="true"
+ on:click={() => logout_user()}>
+ <span title="{$LL.nav.usermenu.logoutTitle()}">{$LL.nav.usermenu.logout()}</span>
+ </MenuItem>
+ </div>
+ </Menu>
+ </div>
</div>
- </div>
-</nav>
+ </nav>
-<main class="container max-width-xl">
- <slot/>
-</main>
+ <main class="container max-width-xl position-relative z-index-1 flex-grow min-height-100vh position-sticky@md top-0@md height-100vh@md overflow-auto@md">
+ <slot/>
+ </main>
+</div>
diff --git a/apps/web-shared/src/assets/logos/projects.png b/apps/web-shared/src/assets/logos/projects.png
new file mode 100644
index 0000000..e49191f
--- /dev/null
+++ b/apps/web-shared/src/assets/logos/projects.png
Binary files differ
diff --git a/apps/web-shared/src/styles/components/side-navigation.scss b/apps/web-shared/src/styles/components/side-navigation.scss
new file mode 100644
index 0000000..0b30c7b
--- /dev/null
+++ b/apps/web-shared/src/styles/components/side-navigation.scss
@@ -0,0 +1,233 @@
+@use '../base' as *;
+@use 'vanilla-responsive-sidebar' as *;
+
+/* --------------------------------
+
+File#: _2_side-navigation-v4
+Title: Side Navigation v4
+Descr: Main, side navigation
+Usage: codyhouse.co/license
+
+-------------------------------- */
+
+.sidenav-v4 {
+ --sidenav-v4-icon-size: 20px;
+ --sidenav-v4-icon-margin-right: var(--space-xxs);
+}
+
+.sidenav-v4__item {
+ position: relative;
+}
+
+.sidenav-v4__link,
+.sidenav-v4__sub-link,
+.sidenav-v4__separator {
+ padding: var(--space-sm);
+}
+
+.sidenav-v4__link, .sidenav-v4__sub-link {
+ display: flex;
+ align-items: center;
+
+ width: 100%;
+ border-radius: var(--radius-md);
+
+ text-decoration: none;
+ color: inherit;
+ line-height: 1;
+ font-size: var(--text-md);
+
+ transition: .2s;
+
+ &:hover {
+ color: var(--color-primary);
+ background-color: alpha(var(--color-contrast-higher), 0.075);
+ }
+
+ &[aria-current="page"] {
+ color: var(--color-primary);
+ }
+}
+
+.sidenav-v4__sub-link {
+ position: relative;
+ color: var(--color-contrast-medium);
+
+ /* dot indicator */
+ &::before {
+ content: '';
+ display: block;
+ --size: 6px;
+ width: var(--size);
+ height: var(--size);
+ background: currentColor;
+ border-radius: 50%;
+ margin-left: calc(var(--sidenav-v4-icon-size)/2 - var(--size)/2);
+ margin-right: calc(var(--sidenav-v4-icon-size)/2 - var(--size)/2 + var(--sidenav-v4-icon-margin-right));
+
+ opacity: 0; /* visible only if current */
+ }
+
+ &[aria-current="page"] {
+ &::before { /* show dot indicator */
+ opacity: 1;
+ }
+ }
+}
+
+.sidenav-v4__notification-marker {
+ margin-left: auto;
+ background-color: var(--color-accent);
+ border-radius: var(--radius-md);
+
+ height: 16px;
+ line-height: 16px;
+ padding: 0 4px;
+ color: var(--color-white);
+ font-size: 12px;
+
+ /* hide - visible only on desktop */
+ display: none;
+}
+
+/* label icon */
+.sidenav-v4__icon {
+ --size: var(--sidenav-v4-icon-size);
+ margin-right: var(--sidenav-v4-icon-margin-right);
+}
+
+/* arrow icon - visible on mobile if item is expandable */
+.sidenav-v4__arrow-icon {
+ --size: 20px;
+
+ .icon__group {
+ will-change: transform;
+ transform-origin: 50% 50%;
+ transform: rotate(-90deg);
+ transition: transform .3s var(--ease-out);
+
+ > * {
+ transform-origin: 50% 50%;
+ stroke-dasharray: 20;
+ stroke-dashoffset: 0;
+ transform: translateY(0px);
+ transition: transform .3s, stroke-dashoffset .3s;
+ transition-timing-function: var(--ease-out);
+ }
+
+ .sidenav-v4__item--collapsed & {
+ transform: rotate(0deg);
+
+ > * {
+ transform: translateY(4px);
+ }
+
+ > *:first-child {
+ stroke-dashoffset: 10.15;
+ }
+
+ > *:last-child {
+ stroke-dashoffset: 10.15;
+ }
+ }
+ }
+
+}
+
+/* current item */
+.sidenav-v4__item--current {
+ .sidenav-v4__sub-list {
+ display: block; /* show sublist */
+ }
+}
+
+/* separator */
+.sidenav-v4__separator {
+ span {
+ display: block;
+ width: var(--sidenav-v4-icon-size);
+ height: 1px;
+ background-color: var(--color-contrast-lower);
+ }
+}
+
+/* mobile only */
+@include breakpoint(md, "not all") {
+ .sidenav-v4__item--collapsed {
+ .sidenav-v4__sub-list {
+ display: none;
+ }
+ }
+
+ .sidenav-v4__link--href {
+ display: none; /* hide link -> show button */
+ }
+}
+
+/* desktop */
+@include breakpoint(md) {
+ .sidenav-v4__sub-list {
+ display: none;
+ }
+
+ .sidenav-v4__link,
+ .sidenav-v4__sub-link,
+ .sidenav-v4__separator {
+ padding: var(--space-xs);
+ }
+
+ .sidenav-v4__link,
+ .sidenav-v4__sub-link {
+ font-size: var(--text-base);
+ }
+
+ .sidenav-v4__link--btn {
+ display: none; /* hide button -> show link */
+ }
+
+ /* tooltip */
+ .sidenav-v4__item:not(.sidenav-v4__item--current) {
+ .sidenav-v4__sub-list {
+ width: 220px;
+ position: absolute;
+ z-index: var(--z-index-overlay);
+ left: 100%;
+ top: 0;
+
+ background-color: var(--color-bg-light);
+ box-shadow: var(--inner-glow), var(--shadow-md);
+ border-radius: var(--radius-md);
+
+ overflow: hidden;
+ }
+
+ .sidenav-v4__sub-link {
+ border-radius: 0;
+ color: var(--color-contrast-high);
+
+ &::before {
+ display: none; /* remove dot indicator */
+ }
+
+ &:hover {
+ color: var(--color-primary);
+ }
+ }
+
+ &.sidenav-v4__item--hover, &:focus-within {
+ .sidenav-v4__sub-list {
+ display: block;
+ }
+ }
+
+ &:hover .sidenav-v4__link { /* highlight main link if tooltip is visible */
+ color: var(--color-primary);
+ background-color: alpha(var(--color-contrast-higher), 0.075);
+ }
+ }
+
+ /* notification marker */
+ .sidenav-v4__notification-marker {
+ display: block;
+ }
+}
diff --git a/apps/web-shared/src/styles/components/vanilla-responsive-sidebar.scss b/apps/web-shared/src/styles/components/vanilla-responsive-sidebar.scss
new file mode 100644
index 0000000..735cc1e
--- /dev/null
+++ b/apps/web-shared/src/styles/components/vanilla-responsive-sidebar.scss
@@ -0,0 +1,146 @@
+@use '../base' as *;
+
+/* --------------------------------
+
+File#: _1_responsive-sidebar
+Title: Responsive Sidebar
+Descr: Responsive sidebar container
+Usage: codyhouse.co/license
+
+-------------------------------- */
+
+/* mobile version only (--default) 👇 */
+.sidebar:not(.sidebar--static) {
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: var(--z-index-fixed-element, 10);
+ width: 100%;
+ height: 100%;
+ visibility: hidden;
+ transition: visibility 0s 0.3s;
+
+ &::after { /* overlay layer */
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: alpha(var(--color-black), 0);
+ transition: background-color .3s;
+ z-index: 1;
+ }
+
+ .sidebar__panel { /* content */
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 2;
+ width: 100%;
+ max-width: 380px;
+ height: 100%;
+ overflow: auto;
+ -webkit-overflow-scrolling: touch;
+ background-color: var(--color-bg);
+ transform: translateX(-100%);
+ transition: box-shadow 0.3s, transform 0.3s;
+ }
+
+ &.sidebar--right-on-mobile {
+ .sidebar__panel {
+ left: auto;
+ right: 0;
+ transform: translateX(100%);
+ }
+ }
+
+ &.sidebar--is-visible {
+ visibility: visible;
+ transition: none;
+
+ &::after {
+ background-color: alpha(var(--color-black), 0.85);
+ }
+
+ .sidebar__panel {
+ transform: translateX(0);
+ box-shadow: var(--shadow-md);
+ }
+ }
+}
+
+/* end mobile version */
+
+.sidebar__header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ position: sticky;
+ top: 0;
+}
+
+.sidebar__close-btn {
+ --size: 32px;
+ width: var(--size);
+ height: var(--size);
+ display: flex;
+ border-radius: 50%;
+ background-color: var(--color-bg-light);
+ box-shadow: var(--inner-glow), var(--shadow-sm);
+ transition: .2s;
+ flex-shrink: 0;
+
+ .icon {
+ display: block;
+ margin: auto;
+ }
+
+ &:hover {
+ background-color: var(--color-bg-lighter);
+ box-shadow: var(--inner-glow), var(--shadow-md);
+ }
+}
+
+.sidebar__footer {
+ background-color: var(--color-bg);
+}
+
+/* desktop version only (--static) 👇 */
+.sidebar--static {
+ flex-shrink: 0;
+ flex-grow: 1;
+ width: 100%;
+ max-width: 320px;
+
+ .sidebar__header {
+ display: none;
+ }
+
+ .sidebar__footer {
+ background-color: var(--color-bg-dark);
+ }
+}
+
+.sidebar--sticky-on-desktop {
+ position: sticky;
+ top: var(--space-sm);
+ max-height: calc(100vh - var(--space-sm));
+ overflow: auto;
+ -webkit-overflow-scrolling: touch;
+}
+
+/* end desktop version */
+
+.sidebar--static::before {
+ content: 'static';
+}
+
+@each $breakpoint, $value in $breakpoints {
+ .sidebar--static\@#{$breakpoint}::before {
+ content: 'mobile';
+ @include breakpoint(#{$breakpoint}) {
+ content: 'static';
+ }
+ }
+}