From cbb1c280f031024335cf3b103b0e2c242c5862b1 Mon Sep 17 00:00:00 2001 From: Joe Date: Thu, 14 May 2020 14:23:49 +0800 Subject: [PATCH] DEV: v2 (#8) --- LICENSE | 2 +- README.md | 4 +- common/common.scss | 215 ++++++------------ common/header.html | 126 ---------- desktop/desktop.scss | 44 ++-- .../above-site-header/header-submenus.hbs | 39 ++++ .../above-site-header/header-submenus.js.es6 | 90 ++++++++ mobile/mobile.scss | 46 ++-- settings.yml | 32 ++- 9 files changed, 264 insertions(+), 334 deletions(-) delete mode 100644 common/header.html create mode 100644 javascripts/discourse/connectors/above-site-header/header-submenus.hbs create mode 100644 javascripts/discourse/connectors/above-site-header/header-submenus.js.es6 diff --git a/LICENSE b/LICENSE index e88cba6..b442934 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018 Joe +Copyright (c) 2018 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index abf15ef..c83fe99 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,4 @@ A theme component that allows you to build a header menu - with submenus - using plain text! -More information https://meta.discourse.org/ - -jquery-dropdown courtesy of Cory LaViska - MIT license +More information https://meta.discourse.org/t/header-submenus/94584 diff --git a/common/common.scss b/common/common.scss index 3416f5b..babb32e 100644 --- a/common/common.scss +++ b/common/common.scss @@ -1,183 +1,114 @@ -@import "common/foundation/variables"; - -$menu-background: null !default; -$menu-item-color: null !default; -$menu-item-active-background: null !default; -$menu-item-active-color: null !default; -$submenu-background: null !default; -$submenu-item-color: null !default; -$submenu-item-hover-background: null !default; -$submenu-item-hover-color: null !default; -$divider-color: null !default; - -@if $Menu_background != "" { - $menu-background: #{$Menu_background}; -} @else { - $menu-background: $primary; +@function fallback($setting, $color) { + @if not $setting or $setting == "" { + @return $color; + } @else { + @return $setting; + } } -@if $Menu_item_color != "" { - $menu-item-color: #{$Menu_item_color}; -} @else { - $menu-item-color: $secondary; -} - -@if $Menu_item-active_background != "" { - $menu-item-active-background: #{$Menu_item_active_background}; -} @else { - $menu-item-active-background: $primary-low; -} - -@if $Menu_item_active_color != "" { - $menu-item-active-color: #{$Menu_item_active_color}; -} @else { - $menu-item-active-color: $primary; -} - -@if $Submenu_background != "" { - $submenu-background: #{$Submenu_background}; -} @else { - $submenu-background: $secondary; -} - -@if $Submenu_item_color != "" { - $submenu-item-color: #{$Submenu_item_color}; -} @else { - $submenu-item-color: $primary; -} - -@if $Submenu_item_hover_background != "" { - $submenu-item-hover-background: #{$Submenu_item_hover_background}; -} @else { - $submenu-item-hover-background: $tertiary-low; -} - -@if $Submenu_item_hover_color != "" { - $submenu-item-hover-color: #{$Submenu_item_hover_color}; -} @else { - $submenu-item-hover-color: $primary; -} - -@if $Divider_color != "" { - $divider-color: #{$Divider_color}; -} @else { - $divider-color: $primary-low; -} +$item-height: 40px; +$icon-opacity: 0.7; .top-menu { - background: $menu-background; + background: fallback($Menu_background, $primary); + width: 100%; - .wrap { + .menu-content { display: flex; align-items: center; - - @if $Invert_position == "true" { - justify-content: flex-end; - } + justify-content: if($Invert_position == "true", flex-end, flex-start); } - .wrap > a { - color: $menu-item-color; + .menu-items { + display: flex; + height: $item-height; + } + + .menu-item { + position: relative; + color: fallback($Menu_item_color, $secondary); border: none; - padding: 10px 12px; + padding: 0 0.5em; font-size: $font-up-1; - line-height: $line-height-medium; transition: all 0.15s; display: flex; align-items: center; - white-space: nowrap; - &:first-of-type { - margin-left: -12px; - } + &:hover, + &:active, + &:focus { + background: fallback($Menu_item-active_background, $primary-low); + color: fallback($Menu-item-active-background, $primary); + cursor: default; + .d-icon-caret-right { + transform: rotate(90deg); + } + .d-header-dropdown { + display: block; + top: $item-height; + left: 0; + z-index: z("header") + 1; - .rtl & { - &:first-of-type { - margin-right: -12px; + .rtl & { + left: unset; + right: 0; + } } } - &.d-dropdown-open { - background: $menu-item-active-background; - color: $menu-item-active-color; - z-index: z("header") + 2; + .d-icon-caret-right { + margin-left: 0.25em; + transition: transform 0.15s ease-in-out; + + .rtl & { + margin-left: 0em; + margin-right: 0.25em; + } } } - .d-icon { - margin-right: 5px; - opacity: 0.7; - min-width: 16px; - text-align: center; - - &.fa-none { - min-width: unset; - } - - .rtl & { - margin-right: 0; - margin-left: 5px; - } + .d-header-dropdown { + position: absolute; + display: none; } - .d-icon-caret-down { - transform: rotate(-90deg); - transition: transform ease 0.15s; - - .rtl & { - transform: rotate(90deg); - } - } - - .d-dropdown-open .d-icon-caret-down { - transform: rotate(0); - } -} - -.d-dropdown { - position: absolute; - z-index: z("header") + 1; - display: none; - .d-dropdown-menu { min-width: 160px; - max-width: 360px; - list-style: none; - background: $submenu-background; + background: fallback($Submenu_background, $secondary); box-shadow: shadow("menu-panel"); - overflow: visible; - padding: 4px 0; margin: 0; - } - - .d-dropdown-menu li { list-style: none; - padding: 0 0; - margin: 0; - line-height: 18px; } - .d-dropdown-menu li > a { + .submenu-link { display: flex; align-items: center; - color: $submenu-item-color; - text-decoration: none; - line-height: 18px; - padding: 3px 15px; - margin: 0; + color: fallback($Submenu_item_color, $primary); + padding: 0.5em; + font-size: $font-down-1; white-space: nowrap; &:hover { - background-color: $submenu-item-hover-background; - color: inherit; - cursor: pointer; + color: fallback($Submenu_item_hover_color, $primary); + background-color: fallback($Submenu_item_hover_background, $tertiary-low); } } - .d-dropdown-menu .divider { - font-size: 1px; - border-top: solid 1px $divider-color; - padding: 0; - margin: 5px 0; + .divider { + border-top: solid 1px fallback($Divider_color, $primary-low); + margin: 0.25em auto; + } + + .d-icon { + opacity: $icon-opacity; + min-width: 1em; + &:not(.d-icon-caret-right) { + margin-right: 0.5em; + + .rtl & { + margin-right: 0; + margin-left: 0.5em; + } + } } } diff --git a/common/header.html b/common/header.html deleted file mode 100644 index 1e153ec..0000000 --- a/common/header.html +++ /dev/null @@ -1,126 +0,0 @@ -
-
-
- - - - - diff --git a/desktop/desktop.scss b/desktop/desktop.scss index e39fcda..d0b269e 100644 --- a/desktop/desktop.scss +++ b/desktop/desktop.scss @@ -1,20 +1,30 @@ +$item-height: 40px; + +@if $Fixed_mode == "true" { + .top-menu { + position: fixed; + top: 0; + z-index: z("header") + 1; + } + + .d-header { + top: $item-height; + position: fixed; + } + + #main-outlet { + padding-top: calc(5.8572em + #{$item-height}); + } +} @else { + .d-header { + top: $item-height; + + .docked & { + top: 0; + } + } +} + .vmo { display: none; } - -@if $Fixed_mode == "true" { - .d-dropdown { - top: 38.5px !important; - } - .d-header { - margin-top: 38.5px; - } - .top-menu { - position: fixed; - width: 100%; - z-index: z("header") + 1; - } - #main-outlet { - padding-top: 8.65em; - } -} diff --git a/javascripts/discourse/connectors/above-site-header/header-submenus.hbs b/javascripts/discourse/connectors/above-site-header/header-submenus.hbs new file mode 100644 index 0000000..938eca3 --- /dev/null +++ b/javascripts/discourse/connectors/above-site-header/header-submenus.hbs @@ -0,0 +1,39 @@ +
+ +
\ No newline at end of file diff --git a/javascripts/discourse/connectors/above-site-header/header-submenus.js.es6 b/javascripts/discourse/connectors/above-site-header/header-submenus.js.es6 new file mode 100644 index 0000000..c01a4ea --- /dev/null +++ b/javascripts/discourse/connectors/above-site-header/header-submenus.js.es6 @@ -0,0 +1,90 @@ +// Used instead of dasherize for backwards compatibility with stable +const getClassName = text => { + return text.toLowerCase().replace(/\s/g, "-"); +}; + +export default { + setupComponent(args, component) { + try { + const splitMenuItems = settings.Menu_items.split("|").filter(Boolean); + const splitSubmenuItems = settings.Submenu_items.split("|").filter( + Boolean + ); + + const menuItemsArray = []; + const SubmenuItemsArray = []; + + splitSubmenuItems.forEach(item => { + const fragments = item.split(",").map(fragment => fragment.trim()); + const parent = fragments[0].toLowerCase(); + const text = fragments[1]; + + if (text.toLowerCase() === "divider") { + const divider = { + parent, + divider: true + }; + return SubmenuItemsArray.push(divider); + } + + const className = getClassName(text); + const icon = + fragments[2].toLowerCase() === "none" + ? "" + : fragments[2].toLowerCase(); + const href = fragments[3]; + const target = fragments[4] === "blank" ? "_blank" : ""; + const title = fragments[5]; + + const submenItem = { + parent, + text, + className, + icon, + href, + target, + title + }; + SubmenuItemsArray.push(submenItem); + }); + + splitMenuItems.forEach(item => { + const fragments = item.split(",").map(fragment => fragment.trim()); + const parentFor = fragments[0].toLowerCase(); + const text = fragments[0]; + const className = getClassName(text); + const icon = + fragments[1].toLowerCase() === "none" + ? "" + : fragments[1].toLowerCase(); + const title = fragments[2]; + const view = fragments[3]; + const childItems = SubmenuItemsArray.filter( + link => link.parent === parentFor + ); + + const menuItem = { + text, + className, + icon, + title, + view, + childItems + }; + menuItemsArray.push(menuItem); + }); + + const showCaret = settings.Show_caret; + + this.setProperties({ + menuItems: menuItemsArray, + showCaret + }); + } catch (error) { + console.error(error); + console.error( + "There's an issue in the Header Submenus Component. Check if your settings are entered correctly" + ); + } + } +}; diff --git a/mobile/mobile.scss b/mobile/mobile.scss index 2b9d699..8b9507a 100644 --- a/mobile/mobile.scss +++ b/mobile/mobile.scss @@ -1,37 +1,29 @@ -@import "common/foundation/variables"; +$item-height: 40px; -.top-menu { - .wrap > a { - font-size: $font-0; - padding: 10px 8px; +.menu-items { + display: flex; + width: 100%; + height: $item-height; +} + +.d-header { + margin-top: $item-height; + .docked & { + margin-top: 0; } } -.top-menu .wrap > a:first-of-type { - margin-left: -10px; +.menu-item-container { + overflow-x: scroll; + height: 100vh; +} - .rtl & { - margin-right: -10px; - } +.menu-placeholder { + height: $item-height; + position: relative; + width: 100%; } .vdo { display: none; } - -.top-menu .wrap { - overflow-x: scroll; - > a { - white-space: nowrap; - } -} - -// handles last menu item dropdown position -.top-menu .wrap > div:last-of-type { - left: unset !important; - right: 0 !important; - .rtl & { - left: 0 !important; - right: unset !important; - } -} diff --git a/settings.yml b/settings.yml index 1aa5934..d46b435 100644 --- a/settings.yml +++ b/settings.yml @@ -2,67 +2,63 @@ Menu_items: type: list default: "Design, magic, Get inspired!, vdm|Code, far-keyboard, Learn new things!, vdm|Business, far-money-bill-alt, Start a new career!, vdm|Shop, shopping-cart, Buy cool stuff!, vdo|More, none, Even more cool things!, vdo" description: - en: "Add menu items. One item per line in this order: Text, icon, title, view.
Text: what appears on the menu.
Icon: the icon displayed next to the item. If you do not want to use an icon, use `none`
Title: the text that appears when the item is hovered.
View: Choose what devices the item appears on. `vdm` appears on both desktop and mobile, `vdo` appears on desktops only, `vmo` appears on mobiles only. Due to lack of space, it is reccomended to not add more than 3-4 items on mobile." + en: "Add menu items. One item per line in this order: Text, icon, title, view.

Text: what appears on the menu.
Icon: the icon displayed next to the item. If you do not want to use an icon, use `none`
Title: the text that appears when the item is hovered.
View: Choose what devices the item appears on. `vdm` appears on both desktop and mobile, `vdo` appears on desktops only, `vmo` appears on mobiles only." Submenu_items: type: list default: "Design, Galleries, th, #, blank, Cool galleries for you to look at.|Design, Design process, far-lightbulb, #, blank, Learn the basics.|Design, Blog design, columns, #, blank, What makes for a great blog?|Design, divider|Design, Freebies, gift, #, blank, Everyone likes freebies!|Design, Photoshop tutorials, book, #, blank, Photoshop for beginners.|Design, Design trends, far-chart-bar, #, blank, Stay on top of the current trends! |Code, Wordpress, wordpress, #, blank, Wordpress code examples|Code, Tools, wrench, #, blank, Tools that will make your life easier!|Code, Tutorials, fab-leanpub, #, blank, Just starting out? We'll guide you through the basics|Business, Blogging, none, #, blank, Why not start a blog?|Business, Social media, none, #, blank, Learn how to leverage Social media and make it work for your business |Business, Make money, none, #, blank, Everyone like to be paid!|Business, Marketing, none, #, blank, No business will survive without customers...Here's how to get'em!|Shop, Vectors, none, #, blank,|Shop, Textures, none, #, blank,|Shop, Brushes, none, #, blank,|Shop, divider|Shop, UI kits, none, #, blank,|Shop, Templates , none, #, blank,|Shop, PSDs, none, #, blank,|More, About us, none, /about, self, Meet the gang!|More, Contact us, none, #, blank, Let's get in touch|More, Terms of Service, none, /tos, self, |More, Privacy policy, none, /privacy, self" description: - en: "Add submenu items. One item per line in this order: Parent, text, icon, URL, target, title.
Parent: the name of the parent menu item which this submenu item show under. Use the `text` value from the list above
Text: the text that shows for this submenu item.
Icon: the icon for this submenu item, use `none` if no icon is needed
URL: the path this menu item links to. You can use relative paths as well.
Target: Choose whether this item will open in a new tab or in the same tab. Use `blank` to open the link in a new tab, or use `self` to open it in the same tab.
Title: the text that shows when the item is hovered.
Dividers: You can also add dividers between submenu items. To add a divider user `parent, divider`" + en: "Add submenu items. One item per line in this order: Parent, text, icon, URL, target, title.

Parent: the name of the parent menu item which this submenu item show under. Use the `text` value from the list above
Text: the text that shows for this submenu item.
Icon: the icon for this submenu item, use `none` if no icon is needed
URL: the path this menu item links to.
You can use relative paths as well.
Target: Choose whether this item will open in a new tab or in the same tab. Use `blank` to open the link in a new tab, or use `self` to open it in the same tab.
Title: the text that shows when the item is hovered.
Dividers: You can also add dividers between submenu items. To add a divider user `parent, divider`" Svg_icons: type: "list" list_type: "compact" - default: "fa-magic|far-keyboard|far-money-bill-alt|fa-shopping-cart|far-lightbulb|fa-columns|fa-gift|fa-book|far-chart-bar|fab-wordpress|fa-wrench|fab-leanpub" + default: "fa-th|fa-magic|far-keyboard|far-money-bill-alt|fa-shopping-cart|far-lightbulb|fa-columns|fa-gift|fa-book|far-chart-bar|fab-wordpress|fa-wrench|fab-leanpub" description: en: "Include FontAwesome icon classes for each icon used in the lists above." Fixed_mode: default: false description: - en: "Force the menu to be visible on top regardless of scroll - Desktop only" + en: "Force the menu to be visible at the top of the screen regardless of scroll position - Desktop only" Show_caret: default: true description: - en: "Show caret icon next to menu items" + en: "Show caret icons next to menu items" Invert_position: default: false description: en: "Display menu items on the opposite side of the screen" -RTL_support: - default: false - description: - en: "Enable RTL support" Menu_background: default: "" description: - en: "Background color for the menu" + en: "Background color for the menu. (hex, rgb, rgba or CSS color name)" Menu_item_color: default: "" description: - en: "Color for menu items" + en: "Color for menu items. (hex, rgb, rgba or CSS color name)" Menu-item-active-background: default: "" description: - en: "Background color for menu items when active" + en: "Background color for menu items when active. (hex, rgb, rgba or CSS color name)" Menu-item-active-color: default: "" description: - en: "Color for menu items when active" + en: "Color for menu items when active. (hex, rgb, rgba or CSS color name)" Submenu_background: default: "" description: - en: "Background color for submenus" + en: "Background color for submenus. (hex, rgb, rgba or CSS color name)" Submenu_item_color: default: "" description: - en: "Color for submenu items" + en: "Color for submenu items. (hex, rgb, rgba or CSS color name)" Submenu_item_hover_background: default: "" description: - en: "Background color for submenus items when hovered" + en: "Background color for submenus items when hovered. (hex, rgb, rgba or CSS color name)" Submenu_item_hover_color: default: "" description: - en: "Color for submenus items when hovered" + en: "Color for submenus items when hovered. (hex, rgb, rgba or CSS color name)" Divider_color: default: "" description: - en: "Color for divider lines in submenus" + en: "Color for divider lines in submenus. (hex, rgb, rgba or CSS color name)"