refactor modules code a bit; still working on menu component

This commit is contained in:
Sacha Greif 2015-10-08 11:13:48 +09:00
parent 963d4ef701
commit 2a3981253e
23 changed files with 342 additions and 332 deletions

View file

@ -20,7 +20,7 @@ wrapperId (String) [optional]
-->
<template name="modules">
<div class="{{getClass}}" data-zone="{{getZone}}" id="{{getId}}">
<div class="{{getClass}}" data-zone="{{zone}}" id="{{getId}}">
{{#each getModules}}
{{#if showModule}}
{{> Template.dynamic template=template data=moduleData}}

View file

@ -2,9 +2,6 @@ Template.modules.helpers({
isDebug: function () {
return Session.get('debug');
},
getZone: function () {
return this.zone || this.toString();
},
getClass: function () {
var zoneClass = "zone-wrapper ";
if (this.zoneClass) {
@ -18,9 +15,12 @@ Template.modules.helpers({
return this.wrapperId;
},
getModules: function () {
// look for the zone name in either the zone variable, or the data context itself
var zone = this.zone || this.toString();
return Telescope.modules.get(zone);
var modules = this;
var modules = Telescope.modules.get(modules.zone).map(function (module) {
module.modules = modules;
return module;
});
return modules;
},
showModule: function () {
var module = this;
@ -38,8 +38,10 @@ Template.modules.helpers({
return true;
},
moduleData: function () {
var zoneData = Template.parentData(1) || {}; // might not always have data context
var moduleData = zoneData.moduleData || {};
return moduleData;
var data = _.extend({
zone: this.modules.zone,
moduleClass: this.modules.moduleClass
}, this.modules.moduleData);
return data;
}
});

View file

@ -1,5 +1,5 @@
<template name="submit_button">
<div class="submit-button {{moduleClass}}">
<a id="submit" class="submit btn btn-primary" href="{{pathFor 'postSubmit'}}">{{_ "post"}}</a>
<a id="submit" class="submit btn btn-primary" href="{{pathFor 'postSubmit'}}">{{_ "post"}}</a>
</div>
</template>

View file

@ -2,21 +2,21 @@
Telescope.modules.add("secondaryNav", [
{
template: 'submit_button',
template: "submit_button",
order: 30
}
]);
Telescope.modules.add("mobileNav", [
{
template: 'submit_button',
template: "submit_button",
order: 30
}
]);
Telescope.modules.add("footer", [
{
template: 'footer_code',
template: "footer_code",
order: 10
}
]);

View file

@ -4,7 +4,13 @@ This is a component for generating flexible, nestable menus. It can generates ne
### Usage
Just include the `menuComponent` template while passing the necessary arguments:
Install with:
```
meteor add telescope:menu
```
Then just include the `menuComponent` template while passing the necessary arguments:
```
{{> menuComponent menuItems=menuItems menuLabel="My Menu" menuClass="my-menu-class"}}

View file

@ -1,268 +0,0 @@
@function black($opacity){
@return rgba(0,0,0,$opacity);
}
@function white($opacity){
@return rgba(255,255,255,$opacity);
}
// $medium-text: #a4a9ab;
// $red: #DD3416;
// $text: #444444;
// ------------------------------------ Common ------------------------------------ //
.menu-list, .menu-dropdown, .menu-collapsible{
// .menu-item{
// margin: 10px 0;
// a{
// font-size:14px;
// }
// &:first-child{
// margin-top: 0px;
// }
// &:last-child{
// margin-bottom: 0px;
// }
// }
// .menu-items-toggle{
// display: none;
// }
// .menu-item-wrapper{
// // padding: 5px 0px;
// }
// .menu-label{
// display: block;
// font-weight: bold;
// cursor: pointer;
// }
// .menu-description{
// display: block;
// font-weight: normal;
// font-size: 12px;
// margin-top: 2px;
// // color: $medium-text;
// }
// .item-active{
// .dark-bg &, .medium-dark-bg &{
// background: white(0.1);
// }
// .light-bg &, .medium-light-bg &, white-bg &{
// background: black(0.1);
// }
// }
// .item-active.item-never-active{
// background: none;
// }
// .menu-top-label{
// cursor: pointer;
// }
// .menu-no-items{
// .menu-label{
// pointer-events: none;
// .menu-items-toggle{
// display: none;
// }
// }
// }
// active item
.item-active{
.menu-item-label-text{
&:before{
content: "> ";
}
}
}
// toggle icons
.menu-items-toggle{
display: none;
border-radius: 100%;
border: 1px solid white(0.3);
&:hover{
background: white(0.1);
}
}
.menu-icon{
height: 20px;
width: 20px;
display: flex;
justify-content: center;
align-items: center;
svg{
display: block;
width: 14px;
height: 14px;
fill: currentColor;
}
}
}
// ------------------------------------ Collapsible ------------------------------------ //
.menu-collapsible{
// menu
.menu-label{
display: flex;
justify-content: space-between;
}
.menu-label-text, .menu-items-toggle{
display: block;
}
.menu-items{
// hide menu items by default
display: none;
}
.menu-items-toggle{
display: block;
}
.menu-items, .menu-child-items{
padding-left: 10px;
border-left: 5px solid rgba(0,0,0,0.1);
margin: 10px 0 10px 6px;
.medium-dark-bg &, .dark-bg & {
border-color: rgba(255,255,255,0.1);
}
.light-bg &, .menu-dropdown & {
border-color: rgba(0,0,0,0.1);
}
}
// expanded menu
&.menu-component.js-expanded{
&>.menu-label-wrapper .menu-icon-expand{
display: none;
}
.menu-items{
display: block;
}
}
// collapsed menu
&.menu-component.js-collapsed{
&>.menu-label-wrapper .menu-icon-collapse{
display: none;
}
.menu-items{
display: none;
}
}
// menu item
.menu-item-label-wrapper{
display: flex;
justify-content: space-between;
}
.menu-item-label-text, .menu-items-toggle{
display: block;
}
.menu-child-items{
display: none;
}
// expanded menu item
.menu-item.js-expanded{
&>.menu-item-label-wrapper .menu-icon-expand{
display: none;
}
.menu-child-items{
display: block;
}
}
// collapsed menu item
.menu-item.js-collapsed{
&>.menu-item-label-wrapper .menu-icon-collapse{
display: none;
}
.menu-child-items{
display: none;
}
}
}
// ------------------------------------ Dropdown ------------------------------------ //
.menu-dropdown{
text-align: left;
position:relative;
&.menu-has-items{
.menu-label-wrapper{
cursor: pointer;
.menu-label{
font-weight: normal;
}
&:after{
display:inline-block;
position:relative;
top:-1px;
margin-left:4px;
content:"";
font-size:8px;
}
}
}
// menu items
.menu-items{
display:none;
top:30px;
left:10px;
position:absolute;
// padding-top:20px;
z-index: 10000;
background:white;
padding: 10px;
overflow: hidden; // prevent margin collapsing
min-width:180px;
border-radius: 3px;
box-shadow: 0 1px 3px black(0.35);
list-style-type: none;
}
&:hover{
// show menu items
.menu-items{
display:block;
}
// add special pseudo-element to preserve hover continuity between menu label and menu items
.menu-label{
&:after{
content: " ";
display: block;
position: absolute;
top: 10px;
width: 100%;
height: 20px;
}
}
}
}

View file

@ -118,27 +118,33 @@ Template.menuItem.helpers({
// generate item's CSS class
itemClass: function () {
var itemClass = "";
var classes = [];
var currentPath = getCurrentPath();
if (this.item.route && (getRoute(this.item) === currentPath || getRoute(this.item) === Meteor.absoluteUrl() + currentPath.substr(1))) {
// substr(1) is to avoid having two "/" in the URL
itemClass += " item-active";
classes.push("item-active");
}
if (getChildMenuItems(this).length) {
classes.push("menu-item-has-children");
} else {
classes.push("menu-item-no-children");
}
if (Template.instance().expanded) {
itemClass += " js-expanded";
classes.push("js-expanded");
} else {
itemClass += " js-collapsed";
classes.push("js-collapsed");
}
if (this.item.itemClass) {
itemClass += " "+this.item.itemClass;
classes.push(this.item.itemClass);
}
itemClass += " menu-level-" + this.level;
classes.push("menu-level-" + this.level);
return itemClass;
return _.unique(classes).join(" ");;
},
// generate array of child menu items

View file

@ -0,0 +1,83 @@
.menu-collapsible{
// menu
.menu-label{
display: flex;
justify-content: space-between;
align-items: center;
}
.menu-label-text, .menu-items-toggle{
display: block;
}
.menu-items{
// hide menu items by default
display: none;
}
.menu-items-toggle{
display: block;
}
.menu-items, .menu-child-items{
padding-left: 10px;
border-left: 5px solid rgba(0,0,0,0.1);
margin: 10px 0 10px 6px;
.medium-dark-bg &, .dark-bg & {
border-color: rgba(255,255,255,0.1);
}
.light-bg &, .menu-dropdown & {
border-color: rgba(0,0,0,0.1);
}
}
// expanded menu
&.menu-component.js-expanded{
&>.menu-label-wrapper .menu-icon-expand{
display: none;
}
.menu-items{
display: block;
}
}
// collapsed menu
&.menu-component.js-collapsed{
&>.menu-label-wrapper .menu-icon-collapse{
display: none;
}
.menu-items{
display: none;
}
}
.menu-child-items{
display: none;
}
// expanded menu item
.menu-item.js-expanded{
&>.menu-item-label-wrapper .menu-icon-expand{
display: none;
}
.menu-child-items{
display: block;
}
}
// collapsed menu item
.menu-item.js-collapsed{
&>.menu-item-label-wrapper .menu-icon-collapse{
display: none;
}
.menu-child-items{
display: none;
}
}
}

View file

@ -0,0 +1,59 @@
@function black($opacity){
@return rgba(0,0,0,$opacity);
}
@function white($opacity){
@return rgba(255,255,255,$opacity);
}
// ------------------------------------ Common ------------------------------------ //
.menu-list, .menu-dropdown, .menu-collapsible{
// active item
.item-active{
.menu-item-label-text{
&:before{
content: "> ";
}
}
}
// menu item
.menu-item-label-wrapper{
display: flex;
justify-content: space-between;
align-items: center;
}
.menu-item-label-text, .menu-items-toggle{
display: block;
}
// toggle icons
.menu-items-toggle{
display: none;
border-radius: 100%;
border: 1px solid white(0.3);
&:hover{
background: white(0.1);
}
}
.menu-icon{
height: 20px;
width: 20px;
display: flex;
justify-content: center;
align-items: center;
svg{
display: block;
width: 14px;
height: 14px;
fill: currentColor;
}
}
}

View file

@ -0,0 +1,109 @@
.menu-dropdown{
// menu
text-align: left;
position:relative;
// indicator for menu with items
&.menu-has-items{
.menu-label-wrapper{
cursor: pointer;
.menu-label{
font-weight: normal;
}
&:after{
display:inline-block;
position:relative;
top:-1px;
margin-left:4px;
content:"";
font-size:8px;
}
}
}
// hover state
&:hover{
// show menu items
.menu-items{
display:block;
}
// add special pseudo-element to preserve hover continuity between menu label and menu items
.menu-label{
&:after{
content: " ";
display: block;
position: absolute;
top: 10px;
width: 100%;
height: 20px;
}
}
}
// dropdown style
.menu-items, .menu-child-items{
display:none; // hidden until user hovers
top:30px;
left:0px;
position:absolute;
z-index: 10000;
background:white;
min-width:180px;
border-radius: 3px;
box-shadow: 0 1px 3px black(0.35);
list-style-type: none;
padding: 5px 0;
}
// menu item
.menu-item{
position: relative;
margin-bottom: 0px;
padding: 5px 10px;
// hover
&:hover{
background: black(0.05);
&>.menu-child-items{
display: block;
}
}
// indicator for menu items with children
&.menu-item-has-children{
.menu-items-toggle{
display: block;
}
.menu-icon-collapse{
display: none;
}
.menu-icon-expand{
position: relative;
right: -5px;
opacity: 0.5;
}
}
}
.menu-item-label{
display: block;
width: 100%;
}
.menu-child-items{
top: -5px;
left: 100%;
}
}

View file

@ -0,0 +1,3 @@
@import "common";
@import "collapsible";
@import "dropdown";

View file

@ -16,10 +16,15 @@ Package.onUse(function(api) {
]);
api.addFiles([
"lib/menu.scss",
"lib/helpers.js",
"lib/menu_component.html",
"lib/menu_component.js",
"lib/stylesheets/menu.scss",
"lib/stylesheets/_common.scss",
"lib/stylesheets/_collapsible.scss",
"lib/stylesheets/_dropdown.scss"
], 'client');
});

View file

@ -40,7 +40,7 @@ Template.notifications_menu.helpers({
return menuItems;
},
menuClass: function () {
if (!!this.mobile) {
if (this.zone === "mobileNav") {
return 'menu-collapsible';
} else if (Settings.get('navLayout', 'top-nav') === 'top-nav') {
return 'menu-dropdown';

View file

@ -1,5 +1,5 @@
<template name="post_author">
<div class="{{moduleClass}}">
<a class="post-author" href="{{getProfileUrl userId}}">{{displayName}}</a>
<a class="post-author" href="{{getProfileUrl item.userId}}">{{displayName}}</a>
</div>
</template>

View file

@ -1,3 +1,3 @@
<template name="post_item">
{{> modules zone="postComponents" zoneClass=postClass moduleClass="post-module" wrapperId=_id moduleData=this}}
{{> modules zone="postComponents" zoneClass=postClass moduleClass="post-module" wrapperId=_id moduleData=post}}
</template>

View file

@ -32,7 +32,7 @@ showFilters (Boolean)
<div class="posts list {{postsLayout}}" aria-live="polite">
{{#each postsCursor}}
{{> before_post_item}}
{{> post_item}}
{{> post_item post=this}}
{{> after_post_item}}
{{/each}}
</div>

View file

@ -1,7 +1,7 @@
<template name="categories_menu">
<div class="categories-menu-wrapper {{moduleClass}}">
{{#if hasCategories}}
{{> menuComponent menuName="categories" menuLabel=menuLabel itemTemplate="categories_menu_item" menuItems=menuItems menuClass=menuClass startPosition="expanded"}}
{{> menuComponent menuName="categories" menuLabel=menuLabel itemTemplate="categories_menu_item" menuItems=menuItems menuClass=menuClass startPosition=startPosition}}
{{/if}}
</div>
</template>

View file

@ -57,14 +57,20 @@ Meteor.startup(function () {
return defaultItem.concat(menuItems);
},
startPosition: function () {
if (this.zone === "mobileNav") {
return "collapsed";
} else {
return "expanded";
}
},
menuClass: function () {
// go back up 4 levels to get the zone that's including the menu
if (Template.parentData(4).zone === "mobileNav") {
if (this.zone === "mobileNav") {
return 'menu-collapsible';
} else if (Settings.get('navLayout', 'top-nav') === 'top-nav') {
return 'menu-dropdown';
} else {
return 'menu-collapsible menu-always-expanded';
return 'menu-collapsible';
}
}
});

View file

@ -20,6 +20,7 @@
@import "specific/avatars";
@import "specific/banners";
@import "specific/errors";
@import "specific/menus";
@import "specific/nav";
@import "specific/layout";
@import "specific/loading";

View file

@ -0,0 +1,5 @@
.menu-dropdown{
.menu-items{
color: #333;
}
}

View file

@ -112,49 +112,41 @@ $mobile-nav-width: 200px;
margin-bottom: 0;
border-top:1px white(0.2) solid;
padding: 0;
.menu-item-wrapper{
padding: 10px;
}
}
.submit{
margin: 10px;
.menu-label, .menu-item-label-wrapper{
padding: 10px;
}
.menu-wrapper{
border: 0;
padding-left: 0;
.menu-items, .menu-child-items{
margin: 0;
}
.menu-item-wrapper{
border-left: 15px solid rgba(255,255,255, 0.1);
padding-left: 0;
}
.menu-child-items{
margin: 0;
padding: 0;
border: none;
.menu-item-wrapper{
border-width: 30px;
}
.menu-child-items .menu-item-wrapper{
border-width: 45px;
}
.menu-child-items .menu-child-items .menu-item-wrapper{
border-width: 60px;
}
.menu-child-items .menu-child-items .menu-child-items .menu-item-wrapper{
border-width: 75px;
}
// .menu-child-items{
// .menu-item-wrapper{
// border-width: 30px;
// }
// .menu-child-items .menu-item-wrapper{
// border-width: 45px;
// }
// .menu-child-items .menu-child-items .menu-item-wrapper{
// border-width: 60px;
// }
// .menu-child-items .menu-child-items .menu-child-items .menu-item-wrapper{
// border-width: 75px;
// }
// }
.submit-button{
padding: 10px;
border-bottom:1px white(0.2) solid;
}
}
.mobile-submit{
padding: 10px;
border-bottom:1px white(0.2) solid;
.button{
.btn, .button{
display: block;
width: 100%;
max-width: none;
}
}
.mobile-menu-button{
position: absolute;
left: 10px;

View file

@ -31,6 +31,7 @@ Package.onUse(function (api) {
'lib/client/scss/specific/_avatars.scss',
'lib/client/scss/specific/_banners.scss',
'lib/client/scss/specific/_errors.scss',
'lib/client/scss/specific/_menus.scss',
'lib/client/scss/specific/_nav.scss',
'lib/client/scss/specific/_layout.scss',
'lib/client/scss/specific/_loading.scss',

View file

@ -21,7 +21,7 @@ Template.user_menu.helpers({
return viewableItems;
},
menuClass: function () {
if (!!this.mobile) {
if (this.zone === "mobileNav") {
return 'menu-collapsible';
} else if (Settings.get('navLayout', 'top-nav') === 'top-nav') {
return 'menu-dropdown';