From f714225e20414b136c919c07ad123b680641a8dd Mon Sep 17 00:00:00 2001 From: Tanya Date: Tue, 24 May 2022 12:49:06 +0800 Subject: [PATCH 1/5] Add button component (twig) (#188) * Add button component * Replace old buttons with the new ones * Update icons and border radius * Update add page button * Set size small to add page btn * Update button indentation * Cleanup * icons and button component updated * upd secondary colour, page button call * Update small button padding right Co-authored-by: Peter Savchenko --- src/backend/views/components/button.twig | 37 +++++++++ src/backend/views/components/header.twig | 7 +- src/backend/views/pages/form.twig | 9 ++- src/backend/views/pages/page.twig | 8 +- src/frontend/styles/components/button.pcss | 83 +++++++++++++++++++++ src/frontend/styles/components/header.pcss | 22 +++--- src/frontend/styles/components/page.pcss | 8 +- src/frontend/styles/components/writing.pcss | 7 +- src/frontend/styles/main.pcss | 6 ++ src/frontend/styles/vars.pcss | 23 +++--- src/frontend/svg/check.svg | 3 + src/frontend/svg/pencil.svg | 3 + src/frontend/svg/plus.svg | 4 +- src/frontend/svg/trash.svg | 3 + 14 files changed, 177 insertions(+), 46 deletions(-) create mode 100644 src/backend/views/components/button.twig create mode 100644 src/frontend/styles/components/button.pcss create mode 100644 src/frontend/svg/check.svg create mode 100644 src/frontend/svg/pencil.svg create mode 100644 src/frontend/svg/trash.svg diff --git a/src/backend/views/components/button.twig b/src/backend/views/components/button.twig new file mode 100644 index 0000000..9527399 --- /dev/null +++ b/src/backend/views/components/button.twig @@ -0,0 +1,37 @@ +{# + Reusable button component. + Available props: + - label + - icon + - name + - style: primary, secondary or warning + - size: small, default + - url: URL to navigate in case if button is the navigation link + - class: additional class for the button + + Usage example: + {% include 'components/button.twig' with {label: 'Label', icon: 'check', style: 'secondary', size: 'default'} %} +#} + +{% set mainClass = 'docs-button' %} + + +{% set tag = 'button' %} + +{% if url is not empty %} + {% set tag = 'a' %} +{% endif %} + +<{{tag}} + {{ name is not empty ? 'name="' ~ name ~ '"': '' }} + class="{{ mainClass }} {{ mainClass }}--{{ style|default('primary') }} {{ mainClass }}--{{ size|default('default') }} {{ icon ? mainClass ~ '--with-icon' : '' }} {{ class ?? '' }}" + {{ url is not empty ? 'href="' ~ url ~ '"' : '' }} +> + {% if icon %} +
+ {{ svg(icon) }} +
+ {% endif %} + + {{ label }} + diff --git a/src/backend/views/components/header.twig b/src/backend/views/components/header.twig index 90dc96d..3707906 100644 --- a/src/backend/views/components/header.twig +++ b/src/backend/views/components/header.twig @@ -5,15 +5,12 @@ + {% endif %} + + {% endfor %} + + +
+ Powered by CodeX Docs +
+
diff --git a/src/frontend/styles/components/aside.pcss b/src/frontend/styles/components/aside.pcss index 7f99599..bb43bab 100644 --- a/src/frontend/styles/components/aside.pcss +++ b/src/frontend/styles/components/aside.pcss @@ -63,6 +63,17 @@ &__current { color: var(--color-page-active) !important; } + + &__logo-wrapper { + margin-top: 5rem; + display: flex; + align-items: center; + gap: 18px; + + .logo { + display: inline-flex; + } + } } .docs-aside-toggler { diff --git a/src/frontend/svg/aside-logo.svg b/src/frontend/svg/aside-logo.svg new file mode 100644 index 0000000..c4e1295 --- /dev/null +++ b/src/frontend/svg/aside-logo.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 30d96909d3efd686f53bbc139118ef934594fbfa Mon Sep 17 00:00:00 2001 From: Tanya Date: Thu, 16 Jun 2022 21:37:37 +0800 Subject: [PATCH 5/5] Sidebar redesign (#200) * New sidebar * Save state to local storage * Make sidebar sticky * Text overflow * Fix add page button on mobile * Mobile layout * Display sidebar when ready * Add logo * Remove files * Fix margin * Update logo padding-bottom * Hovers * Decrease logo's font size * Make logo not sticky * Cleanup classnames * Simplify css * Update sidebar module * Fix animation * Fix cursor issue * Fix vars and logo paddings --- src/backend/views/components/aside.twig | 49 ----- src/backend/views/components/header.twig | 5 +- src/backend/views/components/sidebar.twig | 55 +++++ src/backend/views/layout.twig | 6 +- src/frontend/js/app.js | 2 + src/frontend/js/modules/sidebar.js | 178 ++++++++++++++++ src/frontend/js/utils/storage.js | 30 +++ src/frontend/styles/components/aside.pcss | 92 --------- src/frontend/styles/components/button.pcss | 6 +- src/frontend/styles/components/header.pcss | 33 +-- src/frontend/styles/components/sidebar.pcss | 216 ++++++++++++++++++++ src/frontend/styles/layout.pcss | 25 +-- src/frontend/styles/main.pcss | 2 +- src/frontend/styles/vars.pcss | 14 +- src/frontend/svg/arrow-up.svg | 3 + 15 files changed, 531 insertions(+), 185 deletions(-) delete mode 100644 src/backend/views/components/aside.twig create mode 100644 src/backend/views/components/sidebar.twig create mode 100644 src/frontend/js/modules/sidebar.js create mode 100644 src/frontend/js/utils/storage.js delete mode 100644 src/frontend/styles/components/aside.pcss create mode 100644 src/frontend/styles/components/sidebar.pcss create mode 100644 src/frontend/svg/arrow-up.svg diff --git a/src/backend/views/components/aside.twig b/src/backend/views/components/aside.twig deleted file mode 100644 index 25a6133..0000000 --- a/src/backend/views/components/aside.twig +++ /dev/null @@ -1,49 +0,0 @@ -
- {{ svg('menu') }} Table of contents -
-
- {% for firstLevelPage in menu %} -
- - {{ firstLevelPage.title | striptags }} - - {% if firstLevelPage.children is not empty %} - - {% endif %} -
- {% endfor %} - - -
- Powered by CodeX Docs -
-
-
diff --git a/src/backend/views/components/header.twig b/src/backend/views/components/header.twig index 3707906..6946c0b 100644 --- a/src/backend/views/components/header.twig +++ b/src/backend/views/components/header.twig @@ -4,9 +4,12 @@
    {% if isAuthorized == true %} -
  • +
  • {% include 'components/button.twig' with {label: 'Add page', icon: 'plus', size: 'small', url: '/page/new'} %}
  • +
  • + {% include 'components/button.twig' with {icon: 'plus', size: 'small', url: '/page/new'} %} +
  • {% endif %} {% for option in config.menu %}
  • diff --git a/src/backend/views/components/sidebar.twig b/src/backend/views/components/sidebar.twig new file mode 100644 index 0000000..d452cc8 --- /dev/null +++ b/src/backend/views/components/sidebar.twig @@ -0,0 +1,55 @@ + +
    + +
    + {{ svg('menu') }} Table of contents +
    + + +
    diff --git a/src/backend/views/layout.twig b/src/backend/views/layout.twig index afecadf..72d20fd 100644 --- a/src/backend/views/layout.twig +++ b/src/backend/views/layout.twig @@ -17,9 +17,9 @@ {% include "components/header.twig" with res.locals.isAuthorized %}
    - + + {% include "components/sidebar.twig" %} +
    {% block body %}{% endblock %} diff --git a/src/frontend/js/app.js b/src/frontend/js/app.js index 8a676fa..1cfdbd9 100644 --- a/src/frontend/js/app.js +++ b/src/frontend/js/app.js @@ -16,6 +16,7 @@ import ModuleDispatcher from 'module-dispatcher'; import Writing from './modules/writing'; import Page from './modules/page'; import Extensions from './modules/extensions'; +import Sidebar from './modules/sidebar'; /** * Main app class @@ -28,6 +29,7 @@ class Docs { this.writing = new Writing(); this.page = new Page(); this.extensions = new Extensions(); + this.sidebar = new Sidebar(); document.addEventListener('DOMContentLoaded', (event) => { this.docReady(); diff --git a/src/frontend/js/modules/sidebar.js b/src/frontend/js/modules/sidebar.js new file mode 100644 index 0000000..b64e675 --- /dev/null +++ b/src/frontend/js/modules/sidebar.js @@ -0,0 +1,178 @@ +import { Storage } from '../utils/storage'; + +/** + * Local storage key + */ +const LOCAL_STORAGE_KEY = 'docs_sidebar_state'; + + +/** + * Section list item height in px + */ +const ITEM_HEIGHT = 31; + +/** + * Sidebar module + */ +export default class Sidebar { + /** + * CSS classes + * + * @returns {Record} + */ + static get CSS() { + return { + toggler: 'docs-sidebar__section-toggler', + section: 'docs-sidebar__section', + sectionCollapsed: 'docs-sidebar__section--collapsed', + sectionAnimated: 'docs-sidebar__section--animated', + sectionTitle: 'docs-sidebar__section-title', + sectionTitleActive: 'docs-sidebar__section-title--active', + sectionList: 'docs-sidebar__section-list', + sectionListItemActive: 'docs-sidebar__section-list-item--active', + sidebarToggler: 'docs-sidebar__toggler', + sidebarContent: 'docs-sidebar__content', + sidebarContentHidden: 'docs-sidebar__content--hidden', + }; + } + + /** + * Creates base properties + */ + constructor() { + /** + * Stores refs to HTML elements needed for correct sidebar work + */ + this.nodes = { + sections: [], + sidebarContent: null, + toggler: null, + }; + this.sidebarStorage = new Storage(LOCAL_STORAGE_KEY); + const storedState = this.sidebarStorage.get(); + + this.sectionsState = storedState ? JSON.parse(storedState) : {}; + } + + /** + * Called by ModuleDispatcher to initialize module from DOM + * + * @param {writingSettings} settings - module settings + * @param {HTMLElement} moduleEl - module element + */ + init(settings, moduleEl) { + this.nodes.sections = Array.from(moduleEl.querySelectorAll('.' + Sidebar.CSS.section)); + this.nodes.sections.forEach(section => this.initSection(section)); + this.nodes.sidebarContent = moduleEl.querySelector('.' + Sidebar.CSS.sidebarContent); + this.nodes.toggler = moduleEl.querySelector('.' + Sidebar.CSS.sidebarToggler); + this.nodes.toggler.addEventListener('click', () => this.toggleSidebar()); + this.ready(); + } + + /** + * Initializes sidebar sections: applies stored state and adds event listeners + * + * @param {HTMLElement} section + * @returns {void} + */ + initSection(section) { + const id = section.dataset.id; + const togglerEl = section.querySelector('.' + Sidebar.CSS.toggler); + + if (!togglerEl) { + return; + } + + togglerEl.addEventListener('click', e => this.handleSectionTogglerClick(id, section, e)); + + if (typeof this.sectionsState[id] === 'undefined') { + this.sectionsState[id] = false; + } + if (this.sectionsState[id]) { + this.setSectionCollapsed(section, true, false); + } + + /** + * Calculate and set sections list max height for smooth animation + */ + const sectionList = section.querySelector('.' + Sidebar.CSS.sectionList); + + if (!sectionList) { + return; + } + + const itemsCount = sectionList.children.length; + + sectionList.style.maxHeight = `${ itemsCount * ITEM_HEIGHT }px`; + } + + /** + * Toggles section expansion + * + * @param {number} sectionId - id of the section to toggle + * @param {HTMLElement} sectionEl - section html element + * @param {MouseEvent} event - click event + * @returns {void} + */ + handleSectionTogglerClick(sectionId, sectionEl, event) { + event.preventDefault(); + this.sectionsState[sectionId] = !this.sectionsState[sectionId]; + this.sidebarStorage.set(JSON.stringify(this.sectionsState)); + this.setSectionCollapsed(sectionEl, this.sectionsState[sectionId]); + } + + /** + * Updates section's collapsed state + * + * @param {HTMLElement} sectionEl - element of the section to toggle + * @param {boolean} collapsed - new collapsed state + * @param {boolean} [animated] - true if state should change with animation + */ + setSectionCollapsed(sectionEl, collapsed, animated = true) { + const sectionList = sectionEl.querySelector('.' + Sidebar.CSS.sectionList); + + if (!sectionList) { + return; + } + sectionEl.classList.toggle(Sidebar.CSS.sectionAnimated, animated); + sectionEl.classList.toggle(Sidebar.CSS.sectionCollapsed, collapsed); + + /** + * Highlight section item as active if active child item is collapsed. + */ + const activeSectionListItem = sectionList.querySelector('.' + Sidebar.CSS.sectionListItemActive); + const sectionTitle = sectionEl.querySelector('.' + Sidebar.CSS.sectionTitle); + + if (!activeSectionListItem) { + return; + } + if (collapsed && animated) { + /** + * Highlights section title as active with a delay to let section collapse animation finish first + */ + setTimeout(() => { + sectionTitle.classList.toggle(Sidebar.CSS.sectionTitleActive, collapsed); + }, 200); + } else { + sectionTitle.classList.toggle(Sidebar.CSS.sectionTitleActive, collapsed); + } + } + + /** + * Toggles sidebar visibility + * + * @returns {void} + */ + toggleSidebar() { + this.nodes.sidebarContent.classList.toggle(Sidebar.CSS.sidebarContentHidden); + } + + /** + * Displays sidebar when ready + * + * @returns {void} + */ + ready() { + this.nodes.sidebarContent.classList.remove(Sidebar.CSS.sidebarContentHidden); + } +} diff --git a/src/frontend/js/utils/storage.js b/src/frontend/js/utils/storage.js new file mode 100644 index 0000000..53dff08 --- /dev/null +++ b/src/frontend/js/utils/storage.js @@ -0,0 +1,30 @@ + +/** + * Utility class to handle interaction with local storage + */ +export class Storage { + /** + * @param {string} key - storage key + */ + constructor(key) { + this.key = key; + } + + /** + * Saves value to storage + * + * @param {string} value - value to be saved + */ + set(value) { + localStorage.setItem(this.key, value); + } + + /** + * Retreives value from storage + * + * @returns {string} + */ + get() { + return localStorage.getItem(this.key); + } +} \ No newline at end of file diff --git a/src/frontend/styles/components/aside.pcss b/src/frontend/styles/components/aside.pcss deleted file mode 100644 index bb43bab..0000000 --- a/src/frontend/styles/components/aside.pcss +++ /dev/null @@ -1,92 +0,0 @@ -.docs-aside { - font-size: 14px; - letter-spacing: 0.01em; - - @media (--mobile) { - position: static; - overflow: visible; - max-height: none; - font-size: 13px; - display: none; - margin-top: 20px; - } - - &--toggled { - display: block !important; - } - - a { - color: inherit; - text-decoration: none; - - &:hover { - color: var(--color-link-active); - } - } - - &__section { - margin-bottom: 30px; - - @media (--mobile) { - margin-bottom: 20px; - } - - &:last-of-type { - margin-bottom: 0; - } - - &-title { - display: inline-block; - margin-bottom: 10px; - font-size: 1.18em; - font-weight: 600; - - @media (--mobile) { - margin-bottom: 10px; - } - } - - &-list { - padding-left: 0; - margin: 0; - list-style: none; - - a { - display: inline-block; - color: inherit; - padding: 8px 0; - line-height: 1.5em; - } - } - } - - &__current { - color: var(--color-page-active) !important; - } - - &__logo-wrapper { - margin-top: 5rem; - display: flex; - align-items: center; - gap: 18px; - - .logo { - display: inline-flex; - } - } -} - -.docs-aside-toggler { - display: none; - font-size: 13px; - cursor: pointer; - color: var(--color-text-second); - - @media (--mobile) { - display: block; - } - - svg { - margin-right: 10px; - } -} diff --git a/src/frontend/styles/components/button.pcss b/src/frontend/styles/components/button.pcss index 6e807a4..5b887fb 100644 --- a/src/frontend/styles/components/button.pcss +++ b/src/frontend/styles/components/button.pcss @@ -14,10 +14,8 @@ transition-duration: 0.1s; border-radius: 8px; - @supports(-webkit-mask-box-image: url('')){ - border-radius: 0; - -webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 10.3872C0 1.83334 1.83334 0 10.3872 0H13.6128C22.1667 0 24 1.83334 24 10.3872V13.6128C24 22.1667 22.1667 24 13.6128 24H10.3872C1.83334 24 0 22.1667 0 13.6128V10.3872Z' fill='black'/%3E%3C/svg%3E%0A") 48% 41% 37.9% 53.3%;; - } + @apply --squircle; + &__icon { display: inline-flex; diff --git a/src/frontend/styles/components/header.pcss b/src/frontend/styles/components/header.pcss index 701b766..bd9c7b6 100644 --- a/src/frontend/styles/components/header.pcss +++ b/src/frontend/styles/components/header.pcss @@ -7,6 +7,12 @@ font-size: 18px; flex-wrap: wrap; position: relative; + height: var(--layout-height-header); + box-sizing: border-box; + position: sticky; + top: 0; + background: white; + z-index: 10; @media (--mobile){ line-height: 40px; @@ -60,25 +66,24 @@ } } - &-add { - @media (--mobile) { - position: absolute; - right: 15px; - top: 15px; - line-height: 1em; - margin: 0 !important; - } - a { + li&-add { + flex-shrink: 0; + + &--desktop { @media (--mobile) { - font-size: 0; - padding: 0 4px; - margin-right: 0; + display: none; } } - .docs-button__icon { + &--mobile { + display: none; + @media (--mobile) { - margin-right: 0; + display: block; + position: absolute; + right: 15px; + top: 15px; + line-height: 1em; } } } diff --git a/src/frontend/styles/components/sidebar.pcss b/src/frontend/styles/components/sidebar.pcss new file mode 100644 index 0000000..5747c70 --- /dev/null +++ b/src/frontend/styles/components/sidebar.pcss @@ -0,0 +1,216 @@ +.docs-sidebar { + width: 100vw; + + @media (--desktop) { + width: var(--layout-sidebar-width); + } + + &__content { + border-bottom: 1px solid var(--color-line-gray); + box-sizing: border-box; + padding: var(--layout-padding-vertical) var(--layout-padding-horizontal); + position: sticky; + top: var(--layout-height-header); + display: flex; + flex-direction: column; + overflow: auto; + + @media (--desktop) { + height: calc(100vh - var(--layout-height-header)); + border-right: 1px solid var(--color-line-gray); + border-bottom: 0; + padding-bottom: 0; + } + + &--hidden { + display: none; + } + } + + + &__section { + overflow: hidden; + flex-shrink: 0; + + &--animated { + .docs-sidebar__section-list { + transition: max-height 200ms ease-in-out; + } + + .docs-sidebar__section-toggler { + svg { + transition: transform 200ms ease-in; + } + } + } + + &--collapsed { + .docs-sidebar__section-list { + max-height: 0 !important; + } + + .docs-sidebar__section-toggler { + svg { + transform: rotate(180deg); + } + } + } + } + + &__section:not(:first-child) { + margin-top: 20px; + } + + &__section-title { + font-size: 16px; + line-height: 24px; + font-weight: 700; + z-index: 2; + position: relative; + height: 34px; + } + + &__section-list-item { + font-size: 14px; + line-height: 21px; + height: 29px; + } + + &__section-title, + &__section-list-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 8px; + transition-property: background-color; + transition-duration: 0.1s; + @apply --squircle; + } + + &__section-title > span, + &__section-list-item > span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + &__section-title-wrapper { + &:not(:last-child) { + padding-bottom: 1px; + display: block; + } + } + + + &__section-list-item-wrapper { + padding: 1px 0; + display: block; + } + + li:last-child { + .docs-sidebar__section-list-item-wrapper { + padding-bottom: 0; + } + } + + + &__section-title:not(&__section-title--active), + &__section-list-item:not(&__section-list-item--active) { + @media (--can-hover) { + &:hover { + background: var(--color-link-hover); + } + } + } + + &__section-title--active, + &__section-list-item--active { + background: linear-gradient(270deg, #129BFF 0%, #8A53FF 100%); + color: white; + + @media (--can-hover) { + .docs-sidebar__section-toggler:hover { + background: rgba(0,0,0,0.3); + } + } + } + + &__section-list { + list-style: none; + padding: 0; + margin: 0; + z-index: 1; + position: relative; + } + + &__section-toggler { + color: inherit; + background: transparent; + padding: 0; + border: 0; + cursor: pointer; + width: 24px; + height: 24px; + transition-property: background-color; + transition-duration: 0.1s; + + @apply --squircle; + + @media (--can-hover) { + &:hover { + background: white; + } + } + + svg { + display: block; + } + } + + + &__toggler { + font-size: 13px; + cursor: pointer; + color: var(--color-text-second); + padding: 20px 15px; + border-bottom: 1px solid var(--color-line-gray); + + @media (--desktop) { + display: none; + } + + svg { + margin-right: 10px; + } + } + + &__logo { + display: none; + margin-top: auto; + background: white; + z-index: 2; + padding-bottom: 20px; + padding-top: 60px; + font-size: 14px; + + @media (--desktop) { + display: block; + } + + &-image{ + display: inline-flex; + } + + &-caption { + margin: 0; + } + + &-wrapper { + display: flex; + align-items: center; + gap: 18px; + padding: 8px; + } + } + +} \ No newline at end of file diff --git a/src/frontend/styles/layout.pcss b/src/frontend/styles/layout.pcss index 81d32eb..ca89c3f 100644 --- a/src/frontend/styles/layout.pcss +++ b/src/frontend/styles/layout.pcss @@ -1,27 +1,15 @@ .docs { - display: flex; - padding: 0 var(--layout-padding-horizontal); + min-height: calc(100vh - var(--layout-height-header)); - @media (--mobile) { - flex-wrap: wrap; - } - - &__aside { - width: var(--layout-width-aside); - - @media (--mobile) { - width: 100%; - flex-basis: 100%; - padding: 20px var(--layout-padding-horizontal) !important; - margin: 0 calc(-1 * var(--layout-padding-horizontal)); - border-bottom: 1px solid var(--color-line-gray); - } + @media (--desktop) { + display: flex; } &__content { flex-grow: 2; word-wrap: break-word; + @media (--mobile) { width: 100%; flex-basis: 100%; @@ -33,12 +21,11 @@ } } - &__aside, &__content { - padding: var(--layout-padding-vertical) 0; + padding: var(--layout-padding-vertical) var(--layout-padding-horizontal); @media (--mobile) { - padding: 20px 0; + padding: 20px var(--layout-padding-horizontal); } } } diff --git a/src/frontend/styles/main.pcss b/src/frontend/styles/main.pcss index 29c7df5..389e7b8 100644 --- a/src/frontend/styles/main.pcss +++ b/src/frontend/styles/main.pcss @@ -3,12 +3,12 @@ @import './layout.pcss'; @import './carbon.pcss'; @import './components/header.pcss'; -@import './components/aside.pcss'; @import './components/writing.pcss'; @import './components/page.pcss'; @import './components/landing.pcss'; @import './components/auth.pcss'; @import './components/button.pcss'; +@import './components/sidebar.pcss'; body { font-family: system-ui, Helvetica, Arial, Verdana; diff --git a/src/frontend/styles/vars.pcss b/src/frontend/styles/vars.pcss index cf80d1c..c9a780d 100644 --- a/src/frontend/styles/vars.pcss +++ b/src/frontend/styles/vars.pcss @@ -23,14 +23,16 @@ /** * Site layout sizes */ - --layout-padding-horizontal: 16px; + --layout-padding-horizontal: 22px; --layout-padding-vertical: 30px; - --layout-width-aside: 300px; + --layout-sidebar-width: 344px; --layout-width-main-col: 650px; + --layout-height-header: 56px; @media (--mobile) { --layout-padding-horizontal: 15px; --layout-padding-vertical: 15px; + --layout-height-header: 88px; } --font-mono: Menlo,Monaco,Consolas,Courier New,monospace; @@ -70,6 +72,13 @@ background: color-mod(var(--color-link-active) blackness(+10%)); } } + + --squircle { + @supports(-webkit-mask-box-image: url('')){ + border-radius: 0; + -webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 10.3872C0 1.83334 1.83334 0 10.3872 0H13.6128C22.1667 0 24 1.83334 24 10.3872V13.6128C24 22.1667 22.1667 24 13.6128 24H10.3872C1.83334 24 0 22.1667 0 13.6128V10.3872Z' fill='black'/%3E%3C/svg%3E%0A") 48% 41% 37.9% 53.3%;; + } + } } /** @@ -80,3 +89,4 @@ @custom-media --tablet all and (min-width: 980px) and (max-width: 1050px); @custom-media --mobile all and (max-width: 980px); @custom-media --retina all and (-webkit-min-device-pixel-ratio: 1.5); +@custom-media --can-hover all and (hover:hover) \ No newline at end of file diff --git a/src/frontend/svg/arrow-up.svg b/src/frontend/svg/arrow-up.svg new file mode 100644 index 0000000..4404c6f --- /dev/null +++ b/src/frontend/svg/arrow-up.svg @@ -0,0 +1,3 @@ + + +