Merge remote-tracking branch 'origin/dev' into housekeeping/remove-angularjs

This commit is contained in:
Oliver Günther
2019-07-02 07:30:23 +02:00
1113 changed files with 116662 additions and 147929 deletions
+1 -1
View File
@@ -37,7 +37,6 @@ dist: trusty
cache:
bundler: true
directories:
- frontend/node_modules/foundation-apps
- public/assets
- app/assets/javascripts/bundles
- app/assets/javascripts/locales
@@ -77,6 +76,7 @@ jobs:
- stage: prepare cache
name: 'Prepare cache'
script:
- bash script/ci/db_setup.sh
- bash script/ci/cache_prepare.sh
- stage: test
name: 'npm'
+2 -2
View File
@@ -251,7 +251,7 @@ group :development do
end
group :development, :test do
gem 'puma', '~> 3.12.0'
gem 'puma', '~> 4.0.0'
gem 'thin', '~> 1.7.2'
# Tracing and profiling gems
@@ -285,7 +285,7 @@ platforms :mri, :mingw, :x64_mingw do
end
group :opf_plugins do
gem 'openproject-translations', git: 'https://github.com/opf/openproject-translations.git', branch: 'dev'
gem 'openproject-translations', git: 'https://github.com/opf/openproject-translations.git', ref: 'e88f311daa95e8530686d3dafe2ffefc86f6c8bc'
end
group :docker, optional: true do
+7 -7
View File
@@ -58,8 +58,8 @@ GIT
GIT
remote: https://github.com/opf/openproject-translations.git
revision: 03086ece9d9c745d41c4af0bb236f5b15d58a19f
branch: dev
revision: e88f311daa95e8530686d3dafe2ffefc86f6c8bc
ref: e88f311daa95e8530686d3dafe2ffefc86f6c8bc
specs:
openproject-translations (7.4.0)
crowdin-api (~> 0.5.0)
@@ -113,7 +113,7 @@ PATH
remote: modules/backlogs
specs:
openproject-backlogs (1.0.0)
acts_as_silent_list (~> 3.0.0)
acts_as_list (~> 0.9.18)
openproject-pdf_export
PATH
@@ -293,9 +293,8 @@ GEM
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
acts_as_list (0.9.11)
acts_as_list (0.9.19)
activerecord (>= 3.0)
acts_as_silent_list (3.0.0)
acts_as_tree (2.8.0)
activerecord (>= 3.0.0)
addressable (2.6.0)
@@ -648,7 +647,8 @@ GEM
binding_of_caller (>= 0.7)
pry (>= 0.9.11)
public_suffix (3.0.3)
puma (3.12.0)
puma (4.0.0)
nio4r (~> 2.0)
rack (2.0.6)
rack-accept (0.4.5)
rack (>= 0.4)
@@ -993,7 +993,7 @@ DEPENDENCIES
pry-rails (~> 0.3.6)
pry-rescue (~> 1.5.0)
pry-stack_explorer (~> 0.4.9.2)
puma (~> 3.12.0)
puma (~> 4.0.0)
rack-attack (~> 5.4.2)
rack-mini-profiler
rack-protection (~> 2.0.0)
+18
View File
@@ -27,6 +27,8 @@ $grid--header-width: 20px
.widget-box
height: 100%
&:hover icon-triggered-context-menu
visibility: visible
&.-resizing
border: 1px solid $primary-color
@@ -38,6 +40,12 @@ $grid--header-width: 20px
justify-content: center
align-items: center
&.-placeholder
pointer-events: none
&.-dragged
display: none
.resizer
margin-top: 0
margin-left: auto
@@ -47,6 +55,15 @@ $grid--header-width: 20px
.cdk-drag-handle
cursor: grab
.widget-box--header
display: flex
.widget-box--header-title
flex-grow: 1
icon-triggered-context-menu
visibility: hidden
.grid--area-drag-handle
margin-left: -19px
padding-right: 1px
@@ -147,3 +164,4 @@ $grid--header-width: 20px
&:last-of-type
border-bottom: none
@@ -34,5 +34,8 @@ div#search-results-counts
a
padding: 0 5px
.top-menu-search--wrapper
float: left
.global-search--tabs
margin-bottom: 1rem
@@ -224,6 +224,7 @@ thead.-sticky th
.generic-table--empty-header
padding: 0 6px
height: $generic-table--header-height
line-height: $generic-table--header-height
border-bottom: 1px solid $table-row-border-color
z-index: 1
+3 -24
View File
@@ -26,25 +26,9 @@
// See docs/COPYRIGHT.rdoc for more details.
//++
#watchers
img
vertical-align: middle
margin-right: 7px
.delete
vertical-align: sub
li
list-style-type: none
margin: 0 10px 0 0
padding: 0
float: left
line-height: $user-avatar-mini-width
div#watchers
margin-top: 25px
> form > p
margin-top: 5px
.work-package--watchers
user-avatar
margin-right: 5px
.work-package--watchers.-read-only
.remove-watcher-btn
@@ -53,8 +37,3 @@ div#watchers
// Fix margin for inplace-edit controls
.work-package--watchers-lookup .dropdown-wrapper
margin-bottom: 50px
// Position avatar-minis correctly in listing and typeahead
#detail-panel-watchers
img.avatar-mini
float: inherit
@@ -6,6 +6,10 @@
float: left
margin-right: 20px
&.-multi-line
margin-bottom: 0
line-height: 40px
input
margin-top: 0px
@@ -19,5 +23,5 @@
.ee-attribute-highlighting-upsale
margin-bottom: 1.5rem
multi-toggled-select
display: inline-block
ng-select
width: fit-content
@@ -154,7 +154,6 @@ body.-browser-edge
height: 22px !important
line-height: 22px !important
.inplace-editing--container
display: inline-block
border: 1px solid transparent
@@ -162,8 +161,10 @@ body.-browser-edge
overflow: visible
width: 100%
// Special width rules for more or less fixed with fields
.wp-table--cell-td.startDate,
.wp-table--cell-td.dueDate
width: 160px
.wp-table--cell-td img.thumbnail
height: 40px
@@ -70,7 +70,7 @@
// Highlight additional hierarchy table rows
// that are not part of the normal result list
body:not(.accessibility-mode)
body
.wp-table--hierarchy-aditional-row,
.wp-table--hierarchy-aditional-row .wp-table--hierarchy-indicator-icon
color: $table-row-hierarchies-row-font-color
@@ -1,5 +1,4 @@
body:not(.accessibility-mode )
body
.wp-table--relations-aditional-row,
.wp-table--relation-cell-td.-expanded
background: $table-row-relations-row-background-color
@@ -163,7 +163,7 @@ i
@supports (column-span: all)
// Remove the outline on focus since that breaks the column in chrome
// Chrome bug https://bugs.chromium.org/p/chromium/issues/detail?id=565116
body:not(.accessibility-mode)
body
.attributes-key-value--value-container
*:focus
outline: 1px solid $gray
@@ -5,14 +5,6 @@
float: left
z-index: 0
.timeline-element--bg
width: 100%
height: 100%
&:hover:not(.-clamp-style)
.leftHandle, .rightHandle
background-color: rgba(1, 1, 1, 0.2)
.bar-label
overflow: hidden
padding: 0 0 0 5px
@@ -34,14 +26,10 @@
max-width: 20%
height: 100%
&.-readonly
cursor: not-allowed !important
.leftHandle
cursor: not-allowed !important
.rightHandle
cursor: not-allowed !important
&:hover .timeline-element--bg:not(.-clamp-style)
&~.leftHandle,
&~.rightHandle
background-color: rgba(1, 1, 1, 0.2)
&.-editable
cursor: ew-resize
@@ -52,6 +40,19 @@
.rightHandle
cursor: col-resize
.timeline-element--bg
width: 100%
height: 100%
&.-readonly
cursor: not-allowed !important
&~.leftHandle
cursor: not-allowed !important
&~.rightHandle
cursor: not-allowed !important
.active-selection-mode
.timeline-element.bar.selection-start
@@ -20,6 +20,11 @@
#main
background: #fff
// This counters 'overflow: auto' active in the non print version
// which will lead to only the first page being printed on some pages.
// For whatever reasons, all the pages are displayed in the print rendering emulation
// regardless of the overflow.
overflow: initial
#content-wrapper
width: 99%
@@ -29,11 +29,6 @@
$hamburger-right: -3px
$hamburger-width: 50px
// search bar has a min-width of 160px and should adapt to every screen size
$search-input-width: calc(160px + 3vw)
$search-input-width-expanded: calc(160px + 13vw)
$search-input-height: 30px
%top-menu-hover-styles
@include varprop(background, header-item-bg-hover-color)
@include varprop(color, header-item-font-hover-color)
@@ -169,121 +164,6 @@ $search-input-height: 30px
left: 260px
@include varprop(color, font-color-on-primary)
.top-menu-search--wrapper
float: left
.top-menu-search
display: flex
align-items: center
position: relative
height: $header-height
line-height: $header-height
margin: 0 15px
.top-menu-search--back-button
display: none
.top-menu-search--button
position: absolute
right: 2px
@include varprop(font-size, header-item-font-size)
@include varprop(color, header-item-font-color)
&:hover
text-decoration: none
&.-input-focused
color: $header-search-field-font-color
.top-menu-search--loading
top: $header-height - 11px // display directly under ng-input field
height: 46px // ng-option height + 1px border
z-index: 1051
#global-search-input
width: $search-input-width
font-size: 0.9rem
-webkit-transition: width 0.2s ease-in-out
transition: width 0.2s ease-in-out
&::-ms-clear
margin-right: 5px
width: 20px
.ng-select-container
background: transparent
@include varprop(border-color, header-item-font-color)
.ng-arrow-wrapper
display: none
.ng-clear-wrapper
@include varprop(color, header-item-font-color)
top: 1px
width: 30px
right: 25px
text-align: center
.ng-input
top: 0
input
@include varprop(color, header-item-font-color)
height: $search-input-height
cursor: text
.ng-placeholder
@include varprop(color, header-item-font-color)
&.-expanded
width: $search-input-width-expanded
background: white
border-radius: 4px
color: $header-search-field-font-color
.ng-placeholder,
.ng-clear-wrapper,
input
@include varprop(color, header-search-field-font-color)
.scroll-host
@include styled-scroll-bar
max-height: 80vh
height: auto
.ng-option
border-bottom: 1px solid #EAEAEA
white-space: normal
padding: 5px 10px
&:last-child
border-bottom: none
&.ng-option-marked
@include varprop(background-color, drop-down-hover-bg-color)
@include varprop(color, header-drop-down-item-font-hover-color)
&.ng-option-disabled
display: none
&.ng-option-selected
@include varprop(background-color, drop-down-selected-bg-color)
@include varprop(color, header-drop-down-item-font-hover-color)
.global-search--wp-id
color: $gray-dark
font-size: 13px
white-space: nowrap
.global-search--option-wrapper
padding: 5px 5px
line-height: 25px
min-height: 35px // line-height + padding
word-break: break-word
.global-search--project-scope
position: absolute
right: 7px
border: 1px solid $button--border-color
font-size: 13px
background: $button--background-color
border-radius: 2px
padding: 0 4px
color: $body-font-color
#quick-search
float: right
@@ -29,27 +29,11 @@
@include breakpoint(680px down)
$hamburger-right: -3px
$hamburger-width: 50px
$search-input-height-mobile: 36px
#logo
background-color: transparent
#top-menu
&.-global-search-expanded
#account-nav-right,
#account-nav-left,
#main-menu-toggle
display: none
.top-menu-search
width: 100vw
margin: 0
padding-right: 15px
.top-menu-search--button
display: none
@include varprop(color, header-item-font-color)
#nav-login-content
float: none
padding: 15px 20px
@@ -81,49 +65,6 @@
.nosidebar &
left: 0px
#global-search-input
display: none
&.-expanded
display: block
width: calc(100vw - 50px)
min-width: unset
position: unset
.scroll-host
max-height: calc(100vh - #{$header-height})
.ng-clear-wrapper
width: 40px
right: 0
.ng-select-bottom
height: calc(100vh - #{$header-height})
overflow-y: auto
margin: 0
.ng-select-container
height: $search-input-height-mobile !important
border-radius: 4px
.ng-input input
height: 36px
// The font-size is necessary to avoid iOS to zoom in when being focused
font-size: 16px
.top-menu-search--back-button
display: initial
width: 50px
text-align: center
@include varprop(color, header-item-font-color)
&:hover, &:focus, &:active
text-decoration: none
.top-menu-search--loading
top: $header-height + 1px
.top-menu-search--button.-input-focused
@include varprop(color, header-item-font-color)
#account-nav-right
> li ul
top: $header-height-mobile
+22
View File
@@ -0,0 +1,22 @@
Copyright (c) 2014 ZURB, inc.
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+131
View File
@@ -0,0 +1,131 @@
/*
GLOBAL
------
Global styles and settings for Foundation for Apps are stored here. This file must always
be imported, no matter what.
Includes:
-
*/
/// @Foundation.settings
// Global Styles
// This sets 1rem to be 16px
$rem-base: 16px;
// The default font-size is set to 100% of the browser style sheet (usually 16px)
// for compatibility with browser-based text zoom or user-set defaults.
// Since the typical default browser font-size is 16px, that makes the calculation for grid size.
// If you want your base font-size to be different and not have it affect the grid breakpoints,
// set $rem-base to $base-font-size and make sure $base-font-size is a px value.
$base-font-size: 100% !default;
// $base-line-height is 24px while $base-font-size is 16px
$base-line-height: 1.5 !default;
// Text selector helpers
$headers: "h1,h2,h3,h4,h5,h6";
// We use these to define default font weights
$font-weight-normal: normal !default;
$font-weight-bold: bold !default;
// We use these to control various global styles
$body-background: #fff !default;
$body-font-color: #222 !default;
$body-font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif !default;
$body-font-weight: $font-weight-normal !default;
$body-font-style: normal !default;
$body-antialiased: true;
// Application Colors
$primary-color: #00558b !default;
$secondary-color: #f1f1f1 !default;
$alert-color: #F04124 !default;
$info-color: #A0D3E8 !default;
$success-color: #43AC6A !default;
$warning-color: #F08A24 !default;
$dark-color: #232323 !default;
$gray: #dfdfdf !default;
$gray-dark: darken($gray, 8) !default;
$gray-light: lighten($gray, 8) !default;
// We use these to make sure border radius matches unless we want it different.
$global-radius: 4px !default;
$global-rounded: 1000px !default;
// We use this for default spacing
$global-padding: 1rem !default;
$global-spacing: rem-calc(15) !default;
///
// For internal use: a color map
$foundation-colors: (
primary: $primary-color,
success: $success-color,
warning: $warning-color,
alert: $alert-color,
dark: $dark-color,
);
@include exports(global) {
// Make extra sure we're using the whole window
html, body {
height: 100%;
font-size: $base-font-size;
}
// Set box-sizing globally to handle padding and border widths
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
// Default body styles
body {
background: $body-background;
color: $body-font-color;
padding: 0;
margin: 0;
font-family: $body-font-family;
font-weight: $body-font-weight;
font-style: $body-font-style;
line-height: 1;
position: relative;
@if $body-antialiased {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
}
img {
// Grid Defaults to get images and embeds to work properly
max-width: 100%;
height: auto;
-ms-interpolation-mode: bicubic;
// Get rid of gap under images by making them display: inline-block; by default
display: inline-block;
vertical-align: middle;
}
// Give all anchors and interactive directives the hover cusor
a, [ui-sref], [zf-open], [zf-close], [zf-toggle] {
cursor: pointer;
}
#map_canvas,
.map_canvas {
img,
embed,
object { max-width: none !important; }
}
.padding {
padding: $global-padding;
}
}
@@ -0,0 +1,614 @@
// FOUNDATION FOR APPS SETTINGS
// ----------------------------
//
// Table of Contents:
//
// 1. CSS Exports
// 2. Global Styles
// 3. Breakpoints
// 4. Typography
// 5. Grid
// 6. Button
// 7. Accordion
// 8. Action Sheet
// 9. Block List
// 10. Button Group
// 11. Card
// 12. Extras
// 13. Forms
// 14. Iconic
// 15. Label
// 16. Menu Bar
// 17. Modal
// 18. Motion UI
// 19. Notification
// 20. Off-canvas
// 21. Panel
// 22. Popup
// 23. Switch
// 24. Tabs
// 25. Title Bar
@import "helpers/functions";
// 1. CSS Exports
// - - - - - - - - - - - - - - -
// Change any value in this map from "true" to "false" to disable that component's CSS class output. You'll still be able to use the component's mixins, but none of our pre-written classes will be in your CSS.
// $include-css: (
// accordion: true,
// action-sheet: true,
// block-list: true,
// button: true,
// button-group: true,
// card: true,
// coloring: true,
// extras: true,
// forms: true,
// grid: true,
// iconic: true,
// label: true,
// badge: true,
// list: true,
// menu-bar: true,
// modal: true,
// motion: true,
// notification: true,
// off-canvas: true,
// panel: true,
// popup: true,
// switch: true,
// tabs: true,
// title-bar: true,
// typography: true,
// utilities: true,
// );
// 2. Global Styles
// - - - - - - - - - - - - - - -
// This sets 1rem to be 16px
// $rem-base: 16px;
// The default font-size is set to 100% of the browser style sheet (usually 16px)
// for compatibility with browser-based text zoom or user-set defaults.
// Since the typical default browser font-size is 16px, that makes the calculation for grid size.
// If you want your base font-size to be different and not have it affect the grid breakpoints,
// set $rem-base to $base-font-size and make sure $base-font-size is a px value.
// $base-font-size: 100%;
// $base-line-height is 24px while $base-font-size is 16px
// $base-line-height: 1.5;
// Text selector helpers
// $headers: "h1,h2,h3,h4,h5,h6";
// We use these to define default font weights
// $font-weight-normal: normal;
// $font-weight-bold: bold;
// We use these to control various global styles
// $body-background: #fff;
// $body-font-color: #222;
// $body-font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif;
// $body-font-weight: $font-weight-normal;
// $body-font-style: normal;
// $body-antialiased: true;
// Application Colors
// $primary-color: #00558b;
// $secondary-color: #f1f1f1;
// $alert-color: #F04124;
// $info-color: #A0D3E8;
// $success-color: #43AC6A;
// $warning-color: #F08A24;
// $dark-color: #232323;
// $gray: #dfdfdf;
// $gray-dark: darken($gray, 8);
// $gray-light: lighten($gray, 8);
// We use these to make sure border radius matches unless we want it different.
// $global-radius: 4px;
// $global-rounded: 1000px;
// We use this for default spacing
// $global-padding: 1rem;
// $global-spacing: rem-calc(15);
// 3. Breakpoints
// - - - - - - - - - - - - - - -
// These are our named breakpoints. You can use them in our breakpoint function like this: @include breakpoint(medium) { // Medium and larger styles }
// $breakpoints: (
// small: rem-calc(0),
// medium: rem-calc(640),
// large: rem-calc(1200),
// xlarge: rem-calc(1440),
// xxlarge: rem-calc(1920),
// );
// All of the names in this list will be output as classes in your CSS, like small-12, medium-6, and so on.
// $breakpoint-classes: (small medium large);
// 4. Typography
// - - - - - - - - - - - - - - -
// We use these to control header font styles
// $header-font-family: $body-font-family;
// $header-font-weight: $font-weight-normal;
// $header-font-style: $font-weight-normal;
// $header-font-color: #222;
// $header-line-height: 1.4;
// $header-top-margin: .2rem;
// $header-bottom-margin: .5rem;
// $header-text-rendering: optimizeLegibility;
// We use these to control header font sizes
// $h1-font-size: rem-calc(44);
// $h2-font-size: rem-calc(37);
// $h3-font-size: rem-calc(27);
// $h4-font-size: rem-calc(23);
// $h5-font-size: rem-calc(18);
// $h6-font-size: 1rem;
// We use these to control header size reduction on small screens
// $h1-font-reduction: rem-calc(10);
// $h2-font-reduction: rem-calc(10);
// $h3-font-reduction: rem-calc(5);
// $h4-font-reduction: rem-calc(5);
// $h5-font-reduction: 0;
// $h6-font-reduction: 0;
// These control how subheaders are styled.
// $subheader-line-height: 1.4;
// $subheader-font-color: scale-color($header-font-color, $lightness: 35%);
// $subheader-font-weight: $font-weight-normal;
// $subheader-top-margin: .2rem;
// $subheader-bottom-margin: .5rem;
// A general <small> styling
// $small-font-size: 60%;
// $small-font-color: scale-color($header-font-color, $lightness: 35%);
// We use these to style paragraphs
// $paragraph-font-family: inherit;
// $paragraph-font-weight: $font-weight-normal;
// $paragraph-font-size: 1rem;
// $paragraph-line-height: 1.6;
// $paragraph-margin-bottom: rem-calc(20);
// $paragraph-aside-font-size: rem-calc(14);
// $paragraph-aside-line-height: 1.35;
// $paragraph-aside-font-style: italic;
// $paragraph-text-rendering: optimizeLegibility;
// We use these to style <code> tags
// $code-color: grayscale($primary-color);
// $code-font-family: Consolas, 'Liberation Mono', Courier, monospace;
// $code-font-weight: $font-weight-normal;
// $code-background-color: scale-color($secondary-color, $lightness: 70%);
// $code-border-size: 1px;
// $code-border-style: solid;
// $code-border-color: scale-color($code-background-color, $lightness: -10%);
// $code-padding: rem-calc(2) rem-calc(5) rem-calc(1);
// We use these to style anchors
// $anchor-text-decoration: none;
// $anchor-text-decoration-hover: none;
// $anchor-font-color: $primary-color;
// $anchor-font-color-hover: scale-color($anchor-font-color, $lightness: -14%);
// We use these to style the <hr> element
// $hr-border-width: 1px;
// $hr-border-style: solid;
// $hr-border-color: #ddd;
// $hr-margin: rem-calc(20);
// We use these to style lists
// $list-font-family: $paragraph-font-family;
// $list-font-size: $paragraph-font-size;
// $list-line-height: $paragraph-line-height;
// $list-margin-bottom: $paragraph-margin-bottom;
// $list-style-position: outside;
// $list-side-margin: 1.1rem;
// $list-ordered-side-margin: 1.4rem;
// $list-side-margin-no-bullet: 0;
// $list-nested-margin: rem-calc(20);
// $definition-list-header-weight: $font-weight-bold;
// $definition-list-header-margin-bottom: .3rem;
// $definition-list-margin-bottom: rem-calc(12);
// We use these to style blockquotes
// $blockquote-font-color: scale-color($header-font-color, $lightness: 35%);
// $blockquote-padding: rem-calc(9 20 0 19);
// $blockquote-border: 1px solid #ddd;
// $blockquote-cite-font-size: rem-calc(13);
// $blockquote-cite-font-color: scale-color($header-font-color, $lightness: 23%);
// $blockquote-cite-link-color: $blockquote-cite-font-color;
// Acronym styles
// $acronym-underline: 1px dotted #ddd;
// 5. Grid
// - - - - - - - - - - - - - - -
// $container-width: rem-calc(900);
// $block-padding: $global-padding;
// $total-columns: 12;
// $block-grid-max-size: 6;
// 6. Button
// - - - - - - - - - - - - - - -
// $button-padding: 0.85em 1em;
// $button-margin: 0 $global-padding $global-padding 0;
// $button-style: solid;
// $button-background: $primary-color;
// $button-background-hover: scale-color($button-background, $lightness: -15%);
// $button-color: auto;
// $button-radius: 0;
// $button-sizes: (
// tiny: 0.7,
// small: 0.8,
// medium: 1,
// large: 1.3,
// );
// $button-font-size: 0.9rem;
// $button-opacity-disabled: 0.5;
// $button-tag-selector: false;
// 7. Accordion
// - - - - - - - - - - - - - - -
// $accordion-border: 1px solid $gray-dark;
// $accordion-title-background: $gray-light;
// $accordion-title-background-hover: smartscale($accordion-title-background, 5%);
// $accordion-title-background-active: smartscale($accordion-title-background, 3%);
// $accordion-title-color: isitlight($accordion-title-background);
// $accordion-title-color-active: isitlight($accordion-title-background);
// $accordion-title-padding: $global-padding;
// $accordion-content-padding: $global-padding;
// 8. Action Sheet
// - - - - - - - - - - - - - - -
// $actionsheet-background: white;
// $actionsheet-border-color: #ccc;
// $actionsheet-animate: transform opacity;
// $actionsheet-animation-speed: 0.25s;
// $actionsheet-width: 300px;
// $actionsheet-radius: 4px;
// $actionsheet-shadow: 0 -3px 10px rgba(black, 0.25);
// $actionsheet-padding: $global-padding;
// $actionsheet-tail-size: 10px;
// $actionsheet-popup-shadow: 0 0 10px rgba(black, 0.25);
// $actionsheet-link-color: #000;
// $actionsheet-link-background-hover: smartscale($actionsheet-background);
// 9. Block List
// - - - - - - - - - - - - - - -
// $blocklist-background: #fff;
// $blocklist-fullbleed: true;
// $blocklist-fontsize: 1rem;
// $blocklist-item-padding: 0.8rem 1rem;
// $blocklist-item-color: isitlight($blocklist-background, #000, #fff);
// $blocklist-item-background-hover: smartscale($blocklist-background, 4.5%);
// $blocklist-item-color-disabled: #999;
// $blocklist-item-border: 1px solid smartscale($blocklist-background, 18.5%);
// $blocklist-item-label-color: scale-color($blocklist-item-color, $lightness: 60%);
// $blocklist-item-icon-size: 0.8;
// $blocklist-header-fontsize: 0.8em;
// $blocklist-header-color: smartscale($blocklist-item-color, 40%);
// $blocklist-header-uppercase: true;
// $blocklist-check-icons: true;
// 10. Button Group
// - - - - - - - - - - - - - - -
// $btngroup-background: $primary-color;
// $btngroup-color: #fff;
// $btngroup-radius: $button-radius;
// 11. Card
// - - - - - - - - - - - - - - -
// $card-background: #fff;
// $card-color: isitlight($card-background);
// $card-border: 1px solid smartscale($card-background, 7%);
// $card-radius: $global-radius;
// $card-shadow: 0 1px 2px rgba(#000, 0.2);
// $card-padding: $global-padding;
// $card-margin: 0.5rem;
// $card-divider-background: smartscale($card-background, 7%);
// 12. Extras
// - - - - - - - - - - - - - - -
// $closebutton-position: (top right);
// $closebutton-size: 2em;
// $closebutton-lineheight: 0.5;
// $closebutton-color: #999;
// $closebutton-color-hover: #333;
// $thumbnail-padding: 0.5rem;
// $thumbnail-shadow: 0 3px 15px rgba(black, 0.25);
// 13. Forms
// - - - - - - - - - - - - - - -
// Basic form variables
// $form-fontsize: 1rem;
// $form-padding: 0.5rem;
// Text fields
// $input-color: #000;
// $input-color-hover: $input-color;
// $input-color-focus: $input-color;
// $input-background: #fff;
// $input-background-hover: $input-background;
// $input-background-focus: $input-background;
// $input-background-disabled: smartscale($input-background);
// $input-border: 1px solid #ccc;
// $input-border-hover: 1px solid #bbb;
// $input-border-focus: 1px solid #999;
// $input-cursor-disabled: not-allowed;
// Select menus
// $select-color: #000;
// $select-background: #fafafa;
// $select-background-hover: smartscale($select-background, 4%);
// $select-arrow: true;
// $select-arrow-color: $select-color;
// Labels
// $form-label-fontsize: 0.9rem;
// $form-label-margin: 0.5rem;
// $form-label-color: #333;
// Inline labels
// $inlinelabel-color: #333;
// $inlinelabel-background: #eee;
// $inlinelabel-border: $input-border;
// Range slider
// $slider-background: #ddd;
// $slider-height: 1rem;
// $slider-radius: 0px;
// $slider-thumb-height: 1.5rem;
// $slider-thumb-color: $primary-color;
// $slider-thumb-radius: 0px;
// Progress and meter
// $meter-height: 1.5rem;
// $meter-background: #ccc;
// $meter-fill: $primary-color;
// $meter-fill-high: $success-color;
// $meter-fill-medium: #e7cf00;
// $meter-fill-low: $alert-color;
// $meter-radius: 0;
// 14. Iconic
// - - - - - - - - - - - - - - -
// $iconic-primary-fill: $primary-color;
// $iconic-primary-stroke: $primary-color;
// $iconic-accent-fill: $iconic-primary-fill;
// $iconic-accent-stroke: $iconic-accent-fill;
// 15. Label
// - - - - - - - - - - - - - - -
// $label-fontsize: 0.8rem;
// $label-padding: ($global-padding / 3) ($global-padding / 2);
// $label-radius: 0;
// $label-background: $primary-color;
// $label-color: isitlight($primary-color);
// $badge-fontsize: 0.8em;
// $badge-diameter: 1.5rem;
// $badge-background: $primary-color;
// $badge-color: #fff;
// 16. Menu Bar
// - - - - - - - - - - - - - - -
// $menubar-fontsize: 1rem;
// $menubar-background: #fff;
// $menubar-background-hover: smartscale($menubar-background, 7%);
// $menubar-background-active: $menubar-background-hover;
// $menubar-color: isitlight($menubar-background);
// $menubar-color-hover: $menubar-color;
// $menubar-color-active: $menubar-color-hover;
// $menubar-item-padding: $global-padding;
// $menubar-icon-size: 25px;
// $menubar-icon-spacing: $menubar-item-padding;
// 17. Modal
// - - - - - - - - - - - - - - -
// $modal-background: #fff;
// $modal-border: 0;
// $modal-radius: 0px;
// $modal-shadow: none;
// $modal-zindex: 1000;
// $modal-sizes: (
// tiny: 300px,
// small: 500px,
// medium: 600px,
// large: 800px,
// );
// $modal-overlay-class: 'modal-overlay';
// $modal-overlay-background: rgba(#333, 0.7);
// 18. Motion UI
// - - - - - - - - - - - - - - -
// Classes to use when triggering in/out animations
// $motion-class: (
// in: "ng-enter",
// out: "ng-leave",
// );
// $motion-class-active: (
// in: "ng-enter-active",
// out: "ng-leave-active",
// );
// $motion-class-stagger: (
// in: "ng-enter-stagger",
// out: "ng-leave-stagger",
// );
// $motion-class-showhide: (
// in: "ng-hide-remove",
// out: "ng-hide-add",
// );
// $motion-class-showhide-active: (
// in: "ng-hide-remove-active",
// out: "ng-hide-add-active",
// );
// Set if movement-based transitions should also fade the element in and out
// $motion-slide-and-fade: false;
// $motion-hinge-and-fade: true;
// $motion-scale-and-fade: true;
// $motion-spin-and-fade: true;
// Default speed for transitions and animations
// $motion-duration-default: 500ms;
// Slow and fast modifiders
// $motion-duration-slow: 750ms;
// $motion-duration-fast: 250ms;
// $motion-stagger-duration-default: 150ms;
// $motion-stagger-duration-short: 50ms;
// $motion-stagger-duration-long: 300ms;
// Default timing function for transitions and animations
// $motion-timing-default: ease;
// Built-in and custom easing functions
// Every item in this map becomes a CSS class
// $motion-timings: (
// linear: linear,
// ease: ease,
// easeIn: ease-in,
// easeOut: ease-out,
// easeInOut: ease-in-out,
// bounceIn: cubic-bezier(0.485, 0.155, 0.240, 1.245),
// bounceOut: cubic-bezier(0.485, 0.155, 0.515, 0.845),
// bounceInOut: cubic-bezier(0.760, -0.245, 0.240, 1.245),
// );
// Default delay for all transitions and animations
// $motion-delay-default: 0;
// Short and long delay modifiers
// $motion-delay-short: 300ms;
// $motion-delay-long: 700ms;
// 19. Notification
// - - - - - - - - - - - - - - -
// $notification-default-position: right top;
// $notification-width: rem-calc(400);
// $notification-offset: $global-padding;
// $notification-background: $primary-color;
// $notification-color: white;
// $notification-padding: $global-padding;
// $notification-radius: 4px;
// $notification-icon-size: 60px;
// $notification-icon-margin: $global-padding;
// $notification-icon-align: top;
// 20. Off-canvas
// - - - - - - - - - - - - - - -
// $offcanvas-size-horizontal: 250px;
// $offcanvas-size-vertical: 250px;
// $offcanvas-background: #fff;
// $offcanvas-color: isitlight($offcanvas-background);
// $offcanvas-padding: 0;
// $offcanvas-shadow: 3px 0 10px rgba(black, 0.25);
// $offcanvas-animation-speed: 0.25s;
// $offcanvas-frame-selector: '.grid-frame';
// 21. Panel
// - - - - - - - - - - - - - - -
// $panel-size-horizontal: 300px;
// $panel-size-vertical: 300px;
// $panel-padding: 0;
// $panel-background: #fff;
// $panel-shadow: 3px 0 10px rgba(black, 0.25);
// DEPRECATED: these variables will be removed in a future version.
// $panel-animation-speed: 0.25s;
// 22. Popup
// - - - - - - - - - - - - - - -
// $popup-width: rem-calc(300);
// $popup-background: #fff;
// $popup-border: 0;
// $popup-radius: 0;
// $popup-shadow: 0 0 10px rgba(#000, 0.25);
// 23. Switch
// - - - - - - - - - - - - - - -
// $switch-width: rem-calc(50);
// $switch-height: rem-calc(32);
// $switch-background: #ccc;
// $switch-background-active: $primary-color;
// $switch-border: 0;
// $switch-radius: 9999px;
// $switch-animation-speed: 0.15s;
// $switch-paddle-color: white;
// $switch-paddle-offset: 4px;
// 24. Tabs
// - - - - - - - - - - - - - - -
// $tabstrip-background: transparent;
// $tab-title-background: $gray-light;
// $tab-title-background-hover: smartscale($tab-title-background, 5%);
// $tab-title-background-active: smartscale($tab-title-background, 3%);
// $tab-title-color: isitlight($tab-title-background);
// $tab-title-color-active: $tab-title-color;
// $tab-title-padding: $global-padding;
// $tab-content-padding: $global-padding;
// 25. Title Bar
// - - - - - - - - - - - - - - -
// $titlebar-center-width: 50%;
// $titlebar-side-width: (100% - $titlebar-center-width) / 2;
// $titlebar-background: #eee;
// $titlebar-color: #000;
// $titlebar-border: 1px solid #ccc;
// $titlebar-padding: $global-padding;
// $titlebar-item-classes: (
// center: 'center',
// left: 'left',
// right: 'right',
// title: 'title',
// );
@@ -0,0 +1,72 @@
/*
ACCORDION
---------
The trusy accordion allows you to create a series of vertical tabs.
*/
/// @Foundation.settings
// Accordion
$accordion-border: 1px solid $gray-dark !default;
$accordion-title-background: $gray-light !default;
$accordion-title-background-hover: smartscale($accordion-title-background, 5%) !default;
$accordion-title-background-active: smartscale($accordion-title-background, 3%) !default;
$accordion-title-color: isitlight($accordion-title-background) !default;
$accordion-title-color-active: isitlight($accordion-title-background) !default;
$accordion-title-padding: $global-padding !default;
$accordion-content-padding: $global-padding !default;
///
@mixin accordion-title(
$background: $accordion-title-background,
$background-hover: $accordion-title-background-hover,
$background-active: $accordion-title-background-active,
$color: $accordion-title-color,
$color-active: $accordion-title-color-active,
$padding: $accordion-title-padding
) {
padding: $padding;
background: $background;
color: $color;
line-height: 1;
cursor: pointer;
&:hover {
background: $background-hover;
}
.is-active > & {
background: $background-active;
color: $color-active;
}
}
@mixin accordion-content(
$padding: $accordion-content-padding
) {
padding: $padding;
display: none;
.is-active > & {
display: block;
}
}
@include exports(accordion) {
.accordion {
@if hasvalue($accordion-border) {
border: $accordion-border;
}
}
.accordion-item {
}
.accordion-title {
@include accordion-title;
}
.accordion-content {
@include accordion-content;
}
}
@@ -0,0 +1,265 @@
/*
ACTION SHEET
------------
A dropdown menu that sticks to the bottom of the screen on small devices, and becomes a dropdown menu on larger devices.
*/
/// @Foundation.settings
// Action Sheet
$actionsheet-background: white !default;
$actionsheet-border-color: #ccc !default;
$actionsheet-animate: transform opacity !default;
$actionsheet-animation-speed: 0.25s !default;
$actionsheet-width: 300px !default;
$actionsheet-radius: 4px !default;
$actionsheet-shadow: 0 -3px 10px rgba(black, 0.25) !default;
$actionsheet-padding: $global-padding !default;
$actionsheet-tail-size: 10px !default;
$actionsheet-popup-shadow: 0 0 10px rgba(black, 0.25) !default;
$actionsheet-link-color: #000 !default;
$actionsheet-link-background-hover: smartscale($actionsheet-background) !default;
///
/*
Styles for the list inside an action sheet.
Don't include this mixin if you want to build custom controls inside the sheet.
*/
@mixin action-sheet-menu(
$padding: $actionsheet-padding,
$color: $actionsheet-link-color,
$border-color: $actionsheet-border-color,
$background-hover: $actionsheet-link-background-hover
) {
// Menu container
ul {
margin: -($padding);
margin-top: 0;
list-style-type: none;
user-select: none;
// If the menu has no content above it
&:first-child {
margin-top: -$padding;
li:first-child {
border-top: 0;
}
}
// Menu links
a {
display: block;
padding: $padding * 0.8;
line-height: 1;
color: $color;
border-top: 1px solid $border-color;
&:hover {
color: $color;
background: $background-hover;
}
}
.alert > a {
color: $alert-color;
}
.disabled > a {
pointer-events: none;
color: #999;
}
}
}
/*
Styles for the action sheet container. Action sheets pin to the top or bottom of the screen.
*/
@mixin action-sheet(
$position: bottom,
$shadow: $actionsheet-shadow,
$animate: $actionsheet-animate,
$animation-speed: $actionsheet-animation-speed,
$padding: $actionsheet-padding,
$background: $actionsheet-background
) {
position: fixed;
left: 0;
z-index: 1000;
width: 100%;
padding: $padding;
background: $background;
text-align: center;
transition-property: $animate;
transition-duration: $animation-speed;
transition-timing-function: ease-out;
@if hasvalue($shadow) {
box-shadow: $shadow;
}
// Positions
@if $position == bottom {
bottom: 0;
transform: translateY(100%);
&.is-active {
transform: translateY(0%);
}
}
// These two don't quite work as planned yet
@else if $position == top {
top: 0;
transform: translateY(-100%);
&.is-active {
transform: translateY(0%);
}
}
}
@mixin popup-menu(
$position: bottom,
$background: $actionsheet-background,
$width: $actionsheet-width,
$radius: $actionsheet-radius,
$shadow: $actionsheet-popup-shadow,
$tail-size: $actionsheet-tail-size
) {
/*
Core styles
*/
position: absolute;
left: 50%;
width: $width;
border-radius: $radius;
opacity: 0;
pointer-events: none;
/*
Menu shadow
*/
@if hasvalue($shadow) {
box-shadow: $shadow;
}
/*
Active state
*/
&.is-active {
opacity: 1;
pointer-events: auto;
}
/*
Menu tail
*/
&::before, &::after {
content: '';
position: absolute;
left: 50%;
display: block;
width: 0px;
height: 0px;
border-left: $tail-size solid transparent;
border-right: $tail-size solid transparent;
margin-left: -($tail-size);
}
/*
Positioning
*/
@if $position == bottom {
top: auto;
bottom: 0;
transform: translateX(-50%) translateY(110%);
&.is-active {
transform: translateX(-50%) translateY(100%);
}
&::before, &::after {
top: -($tail-size);
bottom: auto;
border-top: 0;
border-bottom: $tail-size solid $background;
}
&::before {
top: -($tail-size + 2);
border-bottom-color: rgba(black, 0.15);
}
}
@else if $position == top {
top: 0;
bottom: auto;
transform: translateX(-50%) translateY(-120%);
&.is-active {
transform: translateX(-50%) translateY(-110%);
}
&::before, &::after {
top: auto;
bottom: -($tail-size);
border-top: $tail-size solid $background;
border-bottom: 0;
}
&::before {
bottom: -($tail-size + 2);
border-top-color: rgba(black, 0.15);
}
}
}
@include exports(action-sheet) {
.action-sheet-container {
position: relative;
display: inline-block;
.button {
margin-left: 0;
margin-right: 0;
}
}
.action-sheet {
@include action-sheet;
@include action-sheet-menu;
@include breakpoint(medium) {
@include popup-menu;
&.top {
@include popup-menu(top);
}
}
&.primary {
background: $primary-color;
color: isitlight($primary-color);
border: 0;
&::before { display: none; }
&::before, &::after { border-top-color: $primary-color; }
&.top::before, &.top::after { border-bottom-color: $primary-color; }
@include action-sheet-menu(
$color: isitlight($primary-color),
$border-color: smartscale($primary-color, 10%),
$background-hover: smartscale($primary-color)
);
}
&.dark {
background: $dark-color;
color: isitlight($dark-color);
border: 0;
&::before { display: none; }
&::before, &::after { border-top-color: $dark-color; }
&.top::before, &.top::after { border-bottom-color: $dark-color; }
@include action-sheet-menu(
$color: isitlight($dark-color),
$border-color: smartscale($dark-color, 10%),
$background-hover: smartscale($dark-color)
);
}
}
}
@@ -0,0 +1,350 @@
/*
BLOCK LIST
----------
A generic list component that can accomodate a variety of styles and controls.
Features:
- Icons
- Labels
- Chevrons
- Text fields
- Dropdown menus
- Checkbox/radio inputs
*/
/// @Foundation.settings
// Block List
$blocklist-background: #fff !default;
$blocklist-fullbleed: true !default;
$blocklist-fontsize: 1rem !default;
$blocklist-item-padding: 0.8rem 1rem !default;
$blocklist-item-color: isitlight($blocklist-background, #000, #fff) !default;
$blocklist-item-background-hover: smartscale($blocklist-background, 4.5%) !default;
$blocklist-item-color-disabled: #999 !default;
$blocklist-item-border: 1px solid smartscale($blocklist-background, 18.5%) !default;
$blocklist-item-label-color: scale-color($blocklist-item-color, $lightness: 60%) !default;
$blocklist-item-icon-size: 0.8 !default;
$blocklist-header-fontsize: 0.8em !default;
$blocklist-header-color: smartscale($blocklist-item-color, 40%) !default;
$blocklist-header-uppercase: true;
$blocklist-check-icons: true !default;
///
/*
Adds styles for a block list container.
$font-size: global font size for the list.
$full-bleed: when "true", the margins of the list invert to line it up with the edge of a padded element.
*/
%block-list-container {
margin-bottom: 1rem;
line-height: 1;
user-select: none;
&, ul {
list-style-type: none;
}
ul {
margin-left: 0;
}
}
@mixin block-list-container(
$font-size: $blocklist-fontsize,
$full-bleed: $blocklist-fullbleed
) {
@extend %block-list-container;
font-size: $font-size;
@if $full-bleed {
margin-left: -$global-padding;
margin-right: -$global-padding;
}
}
/*
Styles block list headers on the selector you include this mixin in (normally a <header>).
$color - color of the header.
$font-size - font size of the header.
$offset - left margin to add to the header, to line it up with the list items.
*/
@mixin block-list-header(
$color: $blocklist-header-color,
$font-size: $blocklist-header-fontsize,
$uppercase: $blocklist-header-uppercase,
$offset: get-side($blocklist-item-padding, left)
) {
margin-top: 1em;
color: $color;
font-weight: bold;
margin-bottom: 0.5em;
margin-left: $offset;
font-size: $font-size;
cursor: default;
@if $uppercase { text-transform: uppercase; }
}
/*
Styles block list items on the selector you include this mixin in (normally an <li>).
$color - color of items.
$color-hover - color of items on hover.
$background - background of items.
$background-hover - background of items on hover.
$border - border between items.
$padding - padding on items.
*/
@mixin block-list-item(
$color: $blocklist-item-color,
$color-hover: $blocklist-item-color,
$color-disabled: $blocklist-item-color-disabled,
$background: transparent,
$background-hover: $blocklist-item-background-hover,
$border: $blocklist-item-border,
$padding: $blocklist-item-padding
) {
position: relative;
@if hasvalue($border) {
border-bottom: $border;
&:first-child {
border-top: $border;
}
}
// Inner elements share the same basic styles
> a, > span, > label {
display: block;
padding: $padding;
padding-left: get-side($padding, left);
color: $color;
line-height: 1;
}
> span {
cursor: default;
}
> a, > label {
cursor: pointer;
&:hover {
color: $color-hover;
}
}
> a, > label, select {
&:hover {
background: $background-hover;
}
}
// Coloring classes
&.caution > a {
&, &:hover { color: $alert-color; }
}
&.disabled > a {
cursor: default;
&, &:hover { color: $color-disabled; }
&:hover { background: transparent; }
}
}
/*
Adds label styles to the class you include this mixin in.
$color - color of the label.
$left-class - extra class to flip the orientation of the label.
$left-padding - left padding to use for left-hand labels.
*/
@mixin block-list-label(
$color: $blocklist-item-label-color,
$left-class: 'left',
$left-padding: get-side($blocklist-item-padding, top)
) {
display: inline-block;
float: right;
padding: 0;
color: $color;
pointer-events: none;
&.#{$left-class} {
margin-left: $left-padding;
float: none;
}
}
/*
Adds support for chevrons, which appear on the right-hand side of the item.
$color - color of the chevron.
$padding - include the global padding of block list items here.
*/
@mixin block-list-chevron(
$color: $blocklist-header-color,
$padding: $blocklist-item-padding,
$label-class: 'block-list-label'
) {
// Chevrons are a pseudo-element
&::after {
content: '\203A';
display: block;
position: absolute;
right: get-side($padding, right);
top: 50%;
transform: translateY(-50%);
font-weight: bold;
color: $color;
font-size: 2em;
}
// Labels next to links move over to make room for the chevron
// TODO: this selector needs to be customiable, but adding a setting just for it might be weird
.#{$label-class} {
padding-right: get-side($padding, right) * 1.5;
}
}
/*
Adds icon styles. Call this mixin on a block list container.
$size - size of the icon as a percentage (decimal) of the list item's height.
$item-selector - overrides the 'li' selector used for list items.
*/
@mixin block-list-icons(
$size: $blocklist-item-icon-size,
$item-selector: 'li'
) {
// PH - need a better solution
$item-height:
$blocklist-fontsize
+ get-side($blocklist-item-padding, top)
+ get-side($blocklist-item-padding, top);
$icon-height: $item-height * $blocklist-item-icon-size;
$icon-offset: ($item-height - $icon-height) / 2;
#{$item-selector} {
> a, > span, > label {
padding-left: (get-side($blocklist-item-padding, left) * 2) + $blocklist-item-icon-size;
}
img, .iconic {
position: absolute;
top: $icon-offset;
left: $icon-offset;
width: $icon-height;
height: $icon-height;
border-radius: 8px;
pointer-events: none;
}
}
}
/*
Adds support for text fields, select menus, and checkbox/radio groups in block lists.
$color - color of select menu arrow.
$background-hover - color of select menu when hovered over.
$padding - include the global padding of block list items here.
$dropdown-class - class to use for list items that contain a dropdown.
$switch-class - class to use for switches inside list items.
*/
@mixin block-list-inputs(
$color: $blocklist-item-color,
$background: $blocklist-background,
$background-hover: $blocklist-item-background-hover,
$padding: $blocklist-item-padding,
$icons: $blocklist-check-icons,
$dropdown-class: 'with-dropdown',
$switch-class: 'switch'
) {
// Text fields
#{$text-input-selectors} {
margin: 0;
border: 0;
line-height: 1;
height: auto;
padding: $padding;
color: inherit;
&:hover, &:focus {
border: 0;
}
}
// Multiple select
li > input[type="checkbox"], li > input[type="radio"] {
position: absolute;
left: -9999px;
& + label {
display: block;
font-size: $blocklist-fontsize;
margin: 0;
}
@if $icons == true {
&:checked + label {
&::before {
@include image-checkmark($color);
content: '';
background-size: 100% 100%;
width: 1.5em;
height: 1.5em;
color: $primary-color;
float: right;
pointer-events: none;
margin-top: -0.25em;
}
}
}
}
// Dropdowns
.#{$dropdown-class} {
color: inherit;
select {
// Reset pesky <select> styles
-webkit-appearance: none;
-moz-appearance: none;
outline: 0;
background: 0;
border: 0;
height: auto;
padding: $padding;
margin: 0;
font-size: 1em; // Same size as its parent
line-height: 1;
color: inherit;
background-color: transparent;
}
}
// Switches
.#{$switch-class} {
position: absolute;
top: 50%;
right: get-side($padding, right);
transform: translateY(-50%);
}
}
@include exports(block-list) {
.block-list {
@include block-list-container;
@include block-list-inputs;
&.with-icons { @include block-list-icons; }
header { @include block-list-header; }
li {
@include block-list-item;
&.with-chevron { @include block-list-chevron; }
.block-list-label { @include block-list-label; }
}
}
}
@@ -0,0 +1,197 @@
/// @Foundation.settings
// Button Group
$btngroup-background: $primary-color !default;
$btngroup-color: #fff !default;
$btngroup-radius: $button-radius !default;
///
$child-selectors: '> a, > label, > button';
%button-group {
margin: 0;
margin-bottom: 1rem;
list-style-type: none;
display: inline-flex;
border-radius: $btngroup-radius;
overflow: hidden;
font-size: $button-font-size;
> li {
flex: 0 0 auto;
// Links become buttons
#{$child-selectors} {
@extend %button;
border-radius: 0;
font-size: inherit;
display: block;
margin: 0;
}
> input + label {
margin-left: 0;
}
// Add borders between items
&:not(:last-child) {
#{$child-selectors} {
border-right: 1px solid scale-color($btngroup-background, $lightness: -25%);
}
}
}
@if using(iconic) {
.iconic {
width: 1em;
height: 1em;
vertical-align: middle;
margin-right: 0.25em;
margin-top: -2px; // The icons are oddly misaligned
}
}
}
%button-group-segmented {
border: 1px solid $primary-color;
transition-property: background color;
> li {
// Hide the radio button
> input[type="radio"] {
position: absolute;
left: -9999px;
}
// This is the button
#{$child-selectors} {
margin-right: 0;
background: transparent;
}
}
}
@mixin button-group-size($size: medium, $expand: false) {
$size: $button-font-size * map-get($button-sizes, $size);
font-size: $size;
@if $expand {
@include button-group-expand;
}
}
@mixin button-group-expand($stretch: true) {
display: if($stretch, flex, inline-flex);
> li {
flex: if($stretch, 1, 0 0 auto);
#{$child-selectors} {
@if $stretch { @include button-expand; }
}
}
}
@mixin button-group-style(
$segmented: false,
$background: $primary-color,
$color: auto
) {
@if not($segmented) {
> li {
#{$child-selectors} {
@include button-style($background, auto, $color);
border-color: scale-color($background, $lightness: -15%);
}
&.is-active {
#{$child-selectors} {
background: scale-color($background, $lightness: -15%);
}
}
}
}
@else {
@extend %button-group-segmented;
$hover-color: rgba($background, 0.25);
border-color: $background;
> li {
// This is the button
#{$child-selectors} {
border-color: $background;
color: $background;
// This is the button being hovered on
&:hover {
background: $hover-color;
color: $background;
}
@if using(iconic) {
.iconic { @include color-icon($background); }
}
}
// This is the button when it's active
&.is-active > a,
> input:checked + label {
&, &:hover {
background: $background;
color: isitlight($background);
}
@if using(iconic) {
.iconic { @include color-icon(isitlight($background)); }
}
}
}
}
}
@mixin button-group(
$segmented: false,
$expand: false,
$background: $primary-color,
$color: #fff
) {
@extend %button-group;
@include button-group-expand($expand);
@include button-group-style($segmented, $background, $color);
border-radius: $btngroup-radius;
}
@include exports(button-group) {
.button-group {
@include button-group;
// Colors
&.secondary { @include button-group-style(false, $secondary-color); }
&.success { @include button-group-style(false, $success-color); }
&.warning { @include button-group-style(false, $warning-color); }
&.alert { @include button-group-style(false, $alert-color); }
// Individual colors
> li {
&.secondary { #{$child-selectors} { @include button-style($secondary-color, auto, $btngroup: true); } }
&.success { #{$child-selectors} { @include button-style($success-color, auto, $btngroup: true); } }
&.warning { #{$child-selectors} { @include button-style($warning-color, auto, $btngroup: true); } }
&.alert { #{$child-selectors} { @include button-style($alert-color, auto, $btngroup: true); } }
}
// Segmented
&.segmented { @include button-group-style(true);
&.secondary { @include button-group-style(true, $secondary-color); }
&.success { @include button-group-style(true, $success-color); }
&.warning { @include button-group-style(true, $warning-color); }
&.alert { @include button-group-style(true, $alert-color); }
}
// Sizing
&.tiny { @include button-group-size(tiny); }
&.small { @include button-group-size(small); }
&.large { @include button-group-size(large); }
&.expand { @include button-group-expand; }
// Disabled
li.disabled {
#{$child-selectors} {
@include button-disabled;
}
}
}
}
@@ -0,0 +1,205 @@
/// @Foundation.settings
// Button
$button-padding: 0.85em 1em !default;
$button-margin: 0 $global-padding $global-padding 0 !default;
$button-style: solid !default;
$button-background: $primary-color !default;
$button-background-hover: scale-color($button-background, $lightness: -15%) !default;
$button-color: auto !default;
$button-radius: 0 !default;
$button-sizes: (
tiny: 0.7,
small: 0.8,
medium: 1,
large: 1.3,
) !default;
$button-font-size: 0.9rem !default;
$button-opacity-disabled: 0.5 !default;
$button-tag-selector: false !default;
///
%button {
display: inline-block;
border: 0;
text-align: center;
line-height: 1;
cursor: pointer;
-webkit-appearance: none;
-webkit-font-smoothing: antialiased;
transition: background 0.25s ease-out;
vertical-align: middle;
padding: $button-padding;
margin: $button-margin;
font-size: $button-font-size;
border-radius: $button-radius;
// Dropdown arrow
// TODO: Change to class and mixin because now the toggle is 'fa-open' which is too generic
// &[data-popup-toggle] {
// position: relative;
// padding-right: 2em; // Placeholder
// &::after {
// @include css-triangle(6px, black, top);
// position: absolute;
// right: 0.7em;
// top: 50%;
// margin-top: -3px;
// }
// }
}
@mixin button-size($size: medium, $expand: false) {
$size: $button-font-size * map-get($button-sizes, $size);
font-size: $size;
@if $expand {
@include button-expand;
}
@if using(iconic) {
.iconic {
width: 1em;
height: 1em;
vertical-align: middle;
margin-right: 0.25em;
margin-top: -2px; // The icons are oddly misaligned
}
}
}
@mixin button-expand($expand: true) {
@if $expand {
display: block;
width: 100%;
margin-left: 0;
margin-right: 0;
}
@else {
display: inline-block;
width: auto;
margin: $button-margin;
}
}
@mixin button-style(
$background: $button-background,
$background-hover: $button-background-hover,
$color: $button-color,
$style: $button-style,
$radius: $button-radius,
$btngroup: false
){
@if $style == hollow {
border: 1px solid $background;
background: transparent;
color: $background;
&:hover, &:focus {
border-color: scale-color($background, $lightness: 25%);
background: transparent;
color: scale-color($background, $lightness: 25%);
}
}
// Solid is the default
@else {
@if $color == auto {
$color: isitlight($background);
}
background: $background;
color: $color;
&:hover, &:focus {
@if $background-hover == auto {
background: scale-color($background, $lightness: -15%);
}
@else {
background: $background-hover;
}
color: $color;
}
}
@if $btngroup {
border-color: $background;
&:hover, &:focus {
border-color: scale-color($background, $lightness: -25%);
}
}
@if using(iconic) {
@if $style == hollow {
.iconic {
@include color-icon($background);
}
&:hover .iconic {
@include color-icon(scale-color($background, $lightness: 25%));
}
}
@else {
.iconic {
@include color-icon($color);
}
}
}
}
@mixin button-disabled() {
opacity: $button-opacity-disabled;
cursor: default;
pointer-events: none;
}
@mixin button(
$size: medium,
$expand: false,
$background: $button-background,
$background-hover: $button-background-hover,
$color: $button-color,
$style: $button-style,
$radius: $button-radius
) {
@extend %button;
@include button-size($size);
@include button-expand($expand);
@include button-style($background, $background-hover, $color, $style);
}
@include exports(button) {
.button {
@include button;
&.tiny { @include button-size(tiny); }
&.small { @include button-size(small); }
&.large { @include button-size(large); }
&.expand { @include button-expand; }
&.secondary { @include button-style($secondary-color, auto) }
&.success { @include button-style($success-color, auto) }
&.warning { @include button-style($warning-color, auto) }
&.alert { @include button-style($alert-color, auto) }
&.info { @include button-style($info-color, auto) }
&.dark { @include button-style($dark-color, auto) }
@if $button-style != hollow {
&.hollow { @include button-style($style: hollow);
&.secondary { @include button-style($secondary-color, $style: hollow); }
&.success { @include button-style($success-color, $style: hollow); }
&.warning { @include button-style($warning-color, $style: hollow); }
&.alert { @include button-style($alert-color, $style: hollow); }
&.info { @include button-style($info-color, $style: hollow); }
&.dark { @include button-style($dark-color, $style: hollow); }
}
}
&.disabled { @include button-disabled; }
}
@if $button-tag-selector {
button {
@extend .button;
}
}
}
@@ -0,0 +1,93 @@
/*
Cards
Structure:
titles
lists
*/
/// @Foundation.settings
// Card
$card-background: #fff !default;
$card-color: isitlight($card-background) !default;
$card-border: 1px solid smartscale($card-background, 7%) !default;
$card-radius: $global-radius !default;
$card-shadow: 0 1px 2px rgba(#000, 0.2) !default;
$card-padding: $global-padding !default;
$card-margin: 0.5rem !default;
$card-divider-background: smartscale($card-background, 7%) !default;
///
@mixin card-container(
$background: $card-background,
$color: $card-color,
$border: $card-border,
$radius: $card-radius,
$shadow: $card-shadow,
$padding: $card-padding,
$margin: $card-margin
) {
border: $border;
margin-bottom: $margin;
background: $background;
color: $color;
border-radius: $radius;
box-shadow: $shadow;
overflow: hidden;
h1, h2, h3, h4, h5, h6 {
color: inherit;
}
ul {
margin-bottom: 0;
}
img {
width: 100%;
}
}
@mixin card-divider(
$background: $card-divider-background,
$padding: $card-padding
) {
background: $background;
padding: $padding;
}
@mixin card-section(
$padding: $card-padding
) {
padding: $padding;
}
@include exports(card) {
.card {
@include card-container;
@each $color in map-keys($foundation-colors) {
&.#{$color} {
$color-value: map-get($foundation-colors, $color);
@include card-container(
$background: $color-value,
$color: isitlight($color-value),
$border: 0
);
.card-divider {
@include card-divider(
$background: smartscale($color-value, 7%)
);
}
}
}
}
.card-divider {
@include card-divider;
}
.card-section {
@include card-section;
}
}
@@ -0,0 +1,54 @@
/*
Odds and ends.
*/
/// @Foundation.settings
// Extras
$closebutton-position: (top right) !default;
$closebutton-size: 2em !default;
$closebutton-lineheight: 0.5 !default;
$closebutton-color: #999 !default;
$closebutton-color-hover: #333 !default;
$thumbnail-padding: 0.5rem !default;
$thumbnail-shadow: 0 3px 15px rgba(black, 0.25) !default;
///
// A basic close button. They pin to the corner of the thing they're inside.
%close-button {
$x: nth($closebutton-position, 1);
$y: nth($closebutton-position, 2);
position: absolute;
color: $closebutton-color;
#{$x}: $global-padding;
#{$y}: $global-padding;
font-size: $closebutton-size;
line-height: $closebutton-lineheight;
cursor: pointer;
&:hover {
color: $closebutton-color-hover;
}
}
// Make your images fancy-like.
%thumbnail {
padding: $thumbnail-padding;
box-shadow: $thumbnail-shadow;
}
@include exports(extras) {
.close-button {
@extend %close-button;
}
.thumbnail {
@extend %thumbnail;
}
ul.thumbnails > li {
margin-bottom: 1rem;
a { display: block; }
img { @extend %thumbnail; }
}
}
+458
View File
@@ -0,0 +1,458 @@
/*
FORMS
-----
Our form styles include basic resets for text fields, select menus, and so on, along with some of our own custom components.
Includes:
- Text fields
- Text areas
- Select menus
- Checkboxes and radio buttons
- Range slider
- Progress bars and meters
*/
/// @Foundation.settings
// Forms
// Basic form variables
$form-fontsize: 1rem !default;
$form-padding: 0.5rem !default;
// Text fields
$input-color: #000 !default;
$input-color-hover: $input-color !default;
$input-color-focus: $input-color !default;
$input-background: #fff !default;
$input-background-hover: $input-background !default;
$input-background-focus: $input-background !default;
$input-background-disabled: smartscale($input-background) !default;
$input-border: 1px solid #ccc !default;
$input-border-hover: 1px solid #bbb !default;
$input-border-focus: 1px solid #999 !default;
$input-cursor-disabled: not-allowed !default;
// Select menus
$select-color: #000 !default;
$select-background: #fafafa !default;
$select-background-hover: smartscale($select-background, 4%) !default;
$select-arrow: true !default;
$select-arrow-color: $select-color !default;
// Labels
$form-label-fontsize: 0.9rem !default;
$form-label-margin: 0.5rem !default;
$form-label-color: #333 !default;
// Inline labels
$inlinelabel-color: #333 !default;
$inlinelabel-background: #eee !default;
$inlinelabel-border: $input-border !default;
// Range slider
$slider-background: #ddd !default;
$slider-height: 1rem !default;
$slider-radius: 0px !default;
$slider-thumb-height: 1.5rem !default;
$slider-thumb-color: $primary-color !default;
$slider-thumb-radius: 0px !default;
// Progress and meter
$meter-height: 1.5rem !default;
$meter-background: #ccc !default;
$meter-fill: $primary-color !default;
$meter-fill-high: $success-color !default;
$meter-fill-medium: #e7cf00 !default;
$meter-fill-low: $alert-color !default;
$meter-radius: 0 !default;
///
// Disable OS-level styles
@mixin no-appearance {
-webkit-appearance: none;
-moz-appearance: none;
}
// Text fields
// - - - - - - - - - - - - - - - - - - - - - - - - -
#{$text-input-selectors} {
$top-padding: get-side($form-padding, top);
$bottom-padding: get-side($form-padding, bottom);
$height: ($form-fontsize * 1.4) + $top-padding + $bottom-padding;
@include no-appearance;
display: block;
width: 100%;
height: $height;
padding: $form-padding;
margin: 0 0 $global-padding 0;
border: $input-border;
border-radius: 0;
background: $input-background;
color: $input-color;
font-size: $form-fontsize;
-webkit-font-smoothing: antialiased;
vertical-align: middle;
&:hover {
border: $input-border-hover;
background: $input-background-hover;
color: $input-color-hover;
}
&:focus {
outline: 0;
border: $input-border-focus;
background: $input-background-focus;
color: $input-color-focus;
}
label > & {
margin-top: $form-label-margin;
}
}
// Override the content-box declaration set by Normalize
input[type="search"] {
box-sizing: border-box;
}
// Disabled state
input {
&.disabled,
&[disabled],
&[readonly],
fieldset[disabled] & {
cursor: $input-cursor-disabled;
&, &:hover {
background-color: $input-background-disabled;
}
}
}
// Labels
// - - - - - - - - - - - - - - - - - - - - - - - - -
label {
display: block;
font-size: $form-label-fontsize;
margin-bottom: $form-label-margin;
color: $form-label-color;
> input, > textarea {
margin-top: $form-label-margin;
}
}
// Checkbox/radio buttons
// - - - - - - - - - - - - - - - - - - - - - - - - -
input[type="checkbox"], input[type="radio"] {
width: 1rem;
height: 1rem;
// Input inside of a label
label > & {
margin-right: $form-padding * 0.5;
}
// Input next to a label
& + label {
display: inline-block;
margin-left: $form-padding;
margin-right: $form-padding * 2;
margin-bottom: 0;
vertical-align: baseline;
}
}
// Inline labels
// Inline labels allow you to prefix or postfix special labels to inputs
// - - - - - - - - - - - - - - - - - - - - - - - - -
.inline-label {
display: flex;
flex-flow: row nowrap;
align-items: stretch;
margin-bottom: $global-padding;
// Imitates the top margin on normal inputs
label > & {
margin-top: $form-label-margin;
}
// Inputs stretch all the way out
> input, > select {
flex: 1;
margin: 0;
}
// Inline labels and buttons shrink
> .form-label {
flex: 0 0 auto;
background: $inlinelabel-background;
color: $inlinelabel-color;
border: $inlinelabel-border;
padding: 0 $form-padding;
display: flex;
align-items: center;
&:first-child { border-right: 0; }
&:last-child { border-left: 0; }
}
// Buttons also shrink
> a,
> button,
> input[type="button"],
> input[type="submit"] {
flex: 0 0 auto;
display: flex;
align-items: center;
padding-top: 0;
padding-bottom: 0;
margin: 0;
border-radius: 0;
}
}
// Text areas
// - - - - - - - - - - - - - - - - - - - - - - - - -
textarea {
height: auto;
width: 100%;
min-height: 50px;
}
// Select menus
// - - - - - - - - - - - - - - - - - - - - - - - - -
select {
$top-padding: get-side($form-padding, top);
$bottom-padding: get-side($form-padding, bottom);
$height: ($form-fontsize * 1.4) + $top-padding + $bottom-padding;
$color: isitlight($select-background);
@include no-appearance;
display: block;
width: 100%;
height: $height;
padding: $form-padding;
margin: 0 0 $global-padding 0;
font-size: $form-fontsize;
color: $select-color;
border-radius: 0;
border: $input-border;
@if $select-arrow {
background: $select-background url(image-triangle($select-arrow-color)) right 10px center no-repeat;
background-size: 8px 8px;
padding-right: rem-calc(18px) + $form-padding;
}
@else {
background-color: $select-background
}
&:hover {
background-color: $select-background-hover;
}
&:focus {
outline: 0;
}
// Remove the dropdown arrow added in IE10/11
&::-ms-expand {
display: none;
}
}
// Range slider
// - - - - - - - - - - - - - - - - - - - - - - - - -
input[type="range"] {
$margin: ($slider-thumb-height - $slider-height) / 2;
@include no-appearance;
display: block;
width: 100%;
height: auto;
cursor: pointer;
margin-top: $margin;
margin-bottom: $margin;
border: 0;
line-height: 1;
@if hasvalue($slider-radius) {
border-radius: $slider-radius;
}
&:focus {
outline: 0;
}
// Chrome/Safari
&::-webkit-slider-runnable-track {
height: $slider-height;
background: $slider-background;
}
&::-webkit-slider-thumb {
-webkit-appearance: none;
background: $slider-thumb-color;
width: $slider-thumb-height;
height: $slider-thumb-height;
margin-top: -$margin;
@if hasvalue($slider-thumb-radius) {
border-radius: $slider-thumb-radius;
}
}
// Firefox
&::-moz-range-track {
-moz-appearance: none;
height: $slider-height;
background: #ccc;
}
&::-moz-range-thumb {
-moz-appearance: none;
background: $slider-thumb-color;
width: $slider-thumb-height;
height: $slider-thumb-height;
margin-top: -$margin;
@if hasvalue($slider-thumb-radius) {
border-radius: $slider-thumb-radius;
}
}
// Internet Explorer
&::-ms-track {
height: $slider-height;
background: $slider-background;
color: transparent;
border: 0;
overflow: visible;
border-top: $margin solid $body-background;
border-bottom: $margin solid $body-background;
}
&::-ms-thumb {
background: $slider-thumb-color;
width: $slider-thumb-height;
height: $slider-thumb-height;
border: 0;
@if hasvalue($slider-thumb-radius) {
border-radius: $slider-thumb-radius;
}
}
&::-ms-fill-lower, &::-ms-fill-upper {
background: $slider-background;
}
}
output {
line-height: $slider-thumb-height;
vertical-align: middle;
margin-left: 0.5em;
}
// Number inputs
// - - - - - - - - - - - - - - - - - - - - - - - - -
input[type="number"] {
&::-webkit-inner-spin-button {
}
&::-webkit-outer-spin-button {
-webkit-appearance: none;
background: $primary-color;
}
}
// Progress and meter
// - - - - - - - - - - - - - - - - - - - - - - - - -
progress, meter {
@include no-appearance;
display: block;
width: 100%;
height: $meter-height;
margin-bottom: 1rem;
@if hasvalue($meter-radius) {
border-radius: $meter-radius;
}
// For Firefox
background: $meter-background;
border: 0;
}
progress {
&::-webkit-progress-bar {
background: $meter-background;
@if hasvalue($meter-radius) {
border-radius: $meter-radius;
}
}
&::-webkit-progress-value {
background: $meter-fill;
@if hasvalue($meter-radius) {
border-radius: $meter-radius;
}
}
&::-moz-progress-bar {
background: $meter-fill;
@if hasvalue($meter-radius) {
border-radius: $meter-radius;
}
}
@each $name, $color in (high: $meter-fill-high, medium: $meter-fill-medium, low: $meter-fill-low) {
&.#{$name} {
&::-webkit-progress-value {
background: $color;
}
&::-moz-progress-bar {
background: $color;
}
}
}
}
meter {
// Chrome/Safari
&::-webkit-meter-bar {
background: $meter-background;
@if hasvalue($meter-radius) {
border-radius: $meter-radius;
}
}
&::-webkit-meter-inner-element {
@if hasvalue($meter-radius) {
border-radius: $meter-radius;
}
}
&::-webkit-meter-optimum-value {
background: $meter-fill-high;
@if hasvalue($meter-radius) {
border-radius: $meter-radius;
}
}
&::-webkit-meter-suboptimum-value {
background: $meter-fill-medium;
@if hasvalue($meter-radius) {
border-radius: $meter-radius;
}
}
&::-webkit-meter-even-less-good-value {
background: $meter-fill-low;
@if hasvalue($meter-radius) {
border-radius: $meter-radius;
}
}
// Firefox
background: $meter-background;
&::-moz-meter-bar {
background: $primary-color;
@if hasvalue($meter-radius) {
border-radius: $meter-radius;
}
}
&:-moz-meter-optimum::-moz-meter-bar {
background: $meter-fill-high;
}
&:-moz-meter-sub-optimum::-moz-meter-bar {
background: $meter-fill-medium;
}
&:-moz-meter-sub-sub-optimum::-moz-meter-bar {
background: $meter-fill-low;
}
}
@@ -0,0 +1,419 @@
@import "panel";
/*
THE GRID
--------
Foundation's magical, flexbox-powered grid.
Features:
- Horizontal or vertical grids
- Auto-sizing or percentage width grid blocks
- Independently-scrollable blocks
- Column alignment
- Source ordering
- Offsets
*/
/// @Foundation.settings
// Grid
$container-width: rem-calc(900) !default;
$block-padding: $global-padding !default;
$total-columns: 12 !default;
$block-grid-max-size: 6 !default;
///
/*
Define the size of a grid block. Blocks are flex items. By default, they stretch to fill all available space, based on the size of sibling blocks. This is the "expand" behavior.
If set to "shrink", the block will contract and only fill as much space as it needs for its content.
If set to a number, the block will be given a percentage width, based on the total number of columns (12 by default). Percentage widths don't work if a block is inside a vertical grid.
@group grid
@param {number|string} $size - Sizing behavior of the block. Should be expand, shrink, or a number.
@output The flex-basis, flex-grow, and flex-shrink properties.
*/
@mixin grid-size($size: expand) {
@if (type-of($size) == 'number') {
$pct: percentage($size / $total-columns);
flex: 0 0 $pct;
// max-width prevents columns from wrapping early in IE10/11
max-width: $pct;
}
@else if ($size == shrink) {
flex: 0 0 auto;
}
@else if ($size == expand) {
flex: 1 1 auto;
}
}
/*
Set the orientation of blocks within this block. The grid is re-oriented by changing the flex direction of the block.
@group grid
@param {string} $orientation - Direction of the grid, either horizontal or vertical.
@output A flex-flow property to match the direction given.
*/
@mixin grid-orient($orientation: horizontal) {
@if ($orientation == vertical) {
flex-flow: column nowrap;
align-items: stretch;
}
@else {
flex-flow: row wrap;
}
}
/*
Stretch a grid's child blocks across its cross-axis, making every column appear to have the same height.
@group grid
@param {bool} $stretch - Stretch blocks if true, or align blocks to top if false.
@output Sets align-items to "stretch" if $stretch is true, or "flex-start" (the default value) if false.
*/
@mixin grid-wrap($wrap: true) {
@if $wrap {
flex-wrap: wrap;
align-items: flex-start;
}
@else {
flex-wrap: nowrap;
align-items: stretch;
}
}
/*
Set the alignment of blocks within a grid.
left: Items align to the left.
right: Items align to the right.
center: Items align to the center.
justify: Items are spaced equally apart so they occupy the space of the entire grid.
spaced: Items are given equal space to their left and right.
@group grid
@param {string} $align - Alignment to use.
@output An appropriate justify-content value.
*/
@mixin grid-align($align: left) {
$options: (
left: flex-start,
right: flex-end,
center: center,
justify: space-between,
spaced: space-around,
);
justify-content: map-get($options, $align);
}
/*
Set the source order of a block. Items with lower numbers appear first. If multiple items have the same number, the one in the HTML first will appear first.
@group grid
@param {number} $order - Position in source order.
@output An order property.
*/
@mixin grid-order($order: 0) {
order: $order;
}
/*
Collapse a content block by removing the padding.
@group grid
@param {bool} $collapse - Collapses the block if true.
@output A padding value.
@todo No way to reverse collapse using this mixin. Solution:
- If true, add padding: 0;
- If false, add padding: 1rem;
- If null, add nothing, to cut down on CSS output
- Make null the default value
*/
@mixin grid-collapse($collapse: true) {
@if ($collapse) {
padding: 0;
}
}
/*
Constrain the size of a block to the size of the average grid row, and center-align it. This imitates the behavior of ordinary Foundation rows.
@group grid
@param {bool} $container - Adds container styles if true.
@output A maximum width and the good old margin: 0 auto for center alignment.
*/
@mixin grid-container($width: $container-width, $align: center) {
$margins: (
left: 0 auto 0 0,
right: 0 0 0 auto,
center: 0 auto,
);
max-width: $width;
margin: map-get($margins, $align);
}
/*
Add negative margins to a block, equal to the padding of a content block. This aligns the edges of a block nested inside a content block.
@group grid
@param {bool} $nest - Adds negative margins if true.
@output Negative margin values.
*/
@mixin grid-nest($nest: true) {
@if ($nest) {
margin-left: -1rem;
margin-right: -1rem;
}
}
/*
Offset a block by adding a left margin.
@group grid
@param {number | bool} $offset - If false, nothing is output. If a number, offsets the column by the specified number of columns.
@output A left margin based on the number of columns specified, and the global number of columns.
*/
@mixin grid-offset($offset: false) {
@if ($offset != false) {
margin-left: percentage($offset / $total-columns);
}
}
/*
Resets styles set by panels. Use this when a panel transforms into a block on larger screens.
@group grid
@output Resets to transform, position, and a few visual styles.
*/
@mixin grid-panel-reset() {
transform: none;
position: relative;
width: auto;
height: auto;
z-index: auto;
box-shadow: none;
background: transparent;
top: auto;
right: auto;
bottom: auto;
left: auto;
}
/*
Frames are containers that stretch to the full dimmensions of the browser window.
*/
@mixin grid-frame($size: expand, $orientation: horizontal, $wrap: false, $align: left, $order: 0) {
display: flex;
height: 100vh;
position: relative;
overflow: hidden;
@include grid-size($size);
@include grid-orient($orientation);
@include grid-wrap($wrap);
@include grid-align($align);
@include grid-order($order);
}
/*
Groups are collections of content items. They're the "rows" of Foundation for Apps.
*/
@mixin grid-block($size: expand, $orientation: horizontal, $wrap: false, $align: left, $order: 0) {
@include grid-frame($size, $orientation, $wrap, $align, $order);
// Reset the height used by frames
height: auto;
// Blocks will scroll by default if their content overflows
@if ($orientation == vertical) {
overflow-x: auto;
}
@else {
overflow-y: auto;
}
// Add scrolling with inertia
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
/*
Blocks are containers for actual content. They're the "columns" of Foundation for Apps.
*/
@mixin grid-content($size: expand, $offset: null, $order: null) {
// Content blocks are not flex items and have padding
display: block;
padding: 0 $block-padding;
// Add scrolling with inertia
overflow-y: auto;
-webkit-overflow-scrolling: touch;
-ms-overflow-style: -ms-autohiding-scrollbar;
@include grid-size($size);
@if $offset != null { @include grid-offset($offset); }
@if $order != null { @include grid-order($order); }
}
@mixin grid-layout($up) {
flex-flow: row wrap;
overflow: visible;
list-style-type: none;
> li, > div, > section {
padding: 0 1rem 1rem;
flex: 0 0 percentage(1 / $up);
}
}
// CSS Output
// - - - - - - - - - - - - - - - - - - - -
// Shared styles for frames and blocks (parent elements)
%block-core {
// Change the direction children flow
&.vertical { @include grid-orient(vertical); }
@each $size in $breakpoint-classes {
@include breakpoint($size) {
&.#{$size}-vertical { @include grid-orient(vertical); }
&.#{$size}-horizontal { @include grid-orient(horizontal); }
}
}
// Align the children of a grid block
&.align-right { @include grid-align(right); }
&.align-center { @include grid-align(center); }
&.align-justify { @include grid-align(justify); }
&.align-spaced { @include grid-align(spaced); }
// Allow child elements to wrap
&.wrap { @include grid-wrap(true); }
}
// Shared styles for blocks and content blocks (child elements)
%child-core {
// Shrink a flex item so it only takes up the space it needs
&.shrink { @include grid-size(shrink); }
// Prevent an element from scrolling
&.noscroll { overflow: hidden; }
}
@include exports(grid) {
// The core grid elements:
// - Frame
// - Block
// - Content block
// - Container
.grid-frame {
@extend %block-core;
@include grid-frame;
}
.grid-block {
@extend %block-core;
@extend %child-core;
@include grid-block;
}
.grid-content {
@extend %child-core;
@include grid-content;
&.collapse {
padding: 0;
}
// Grids inside content blocks should wrap by default, so they mimic traditional float grids
.grid-block {
margin-left: -($block-padding);
margin-right: -($block-padding);
flex-wrap: wrap;
overflow: visible;
// Reverse the above wrapping behavior
&.nowrap {
@include grid-wrap(false);
}
.grid-content {
overflow: visible;
}
}
}
.grid-container {
@include grid-container;
&.contain-left { @include grid-container($align: left); }
&.contain-right { @include grid-container($align: right); }
}
// Breakpoint classes for blocks
@each $size in $breakpoint-classes {
.#{$size}-grid-block {
@extend %block-core;
@extend %child-core;
@include breakpoint($size) {
@include grid-block;
// Override panel styles
&.panel { @include grid-panel-reset; }
}
}
.#{$size}-grid-content {
@extend %child-core;
@include breakpoint($size) {
@include grid-content;
// Override panel styles
&.panel { @include grid-panel-reset; }
}
}
}
// Sizing and ordering classes
@for $i from 1 through $total-columns {
// Source ordering
.order-#{$i} { @include grid-order($i); }
}
@each $size in $breakpoint-classes {
@for $i from 1 through $total-columns {
@include breakpoint($size) {
// Block sizing
.#{$size}-#{$i} {
@include grid-size($i);
}
// Source ordering
.#{$size}-order-#{$i} {
@include grid-order($i);
}
// Offsets
.#{$size}-offset-#{$i} {
@include grid-offset($i);
}
// Parent sizing (block grids)
.#{$size}-up-#{$i} {
@include grid-layout($i);
}
}
}
}
.grid-content .modal .grid-block {
flex-wrap: nowrap;
}
}
@@ -0,0 +1,134 @@
/*
Label
*/
/// @Foundation.settings
// Label
$label-fontsize: 0.8rem !default;
$label-padding: ($global-padding / 3) ($global-padding / 2) !default;
$label-radius: 0 !default;
$label-background: $primary-color !default;
$label-color: isitlight($primary-color) !default;
$badge-fontsize: 0.8em !default;
$badge-diameter: 1.5rem !default;
$badge-background: $primary-color !default;
$badge-color: #fff !default;
///
%label {
line-height: 1;
white-space: nowrap;
display: inline-block;
cursor: default;
}
@mixin label-layout(
$fontsize: $label-fontsize,
$padding: $label-padding
) {
font-size: $fontsize;
padding: $padding;
}
@mixin label-style(
$background: $label-background,
$color: $label-color,
$radius: $label-radius
) {
background: $background;
border-radius: $radius;
@if $color == auto {
color: isitlight($background);
}
@else {
color: $color;
}
}
@mixin label(
$background: $label-background,
$color: $label-color,
$radius: $label-radius,
$fontsize: $label-fontsize,
$padding: $label-padding
) {
@extend %label;
@include label-layout($fontsize, $padding);
@include label-style($background, $color, $radius);
}
@include exports(label) {
.label {
@include label;
@each $color in map-keys($foundation-colors) {
&.#{$color} {
$color-value: map-get($foundation-colors, $color);
@include label-style($color-value, auto);
}
}
}
}
/*
Badge
*/
%badge {
align-items: center;
justify-content: center;
display: inline-flex;
border-radius: 1000px;
}
@mixin badge-layout(
$fontsize: $badge-fontsize,
$diameter: $badge-diameter
) {
font-size: $fontsize;
width: $diameter;
height: $diameter;
}
@mixin badge-style(
$background: $badge-background,
$color: $badge-font-color
) {
background: $background;
@if $color == auto {
color: isitlight($background);
}
@else {
color: $color;
}
}
@mixin badge(
$background: $badge-background,
$color: $badge-color,
$diameter: $badge-diameter,
$fontsize: $badge-fontsize
) {
@extend %badge;
@include badge-layout($fontsize, $diameter);
@include badge-style($background, $color);
}
@include exports(badge) {
.badge {
@include badge;
&.secondary {
@include badge-style($secondary-color, auto);
}
@each $color in map-keys($foundation-colors) {
&.#{$color} {
$color-value: map-get($foundation-colors, $color);
@include badge-style($color-value, auto);
}
}
}
}
@@ -0,0 +1,19 @@
@mixin inline-list($alignment){
list-style-type: none;
text-align: $alignment;
li, dt, dd {
display: inline-block;
margin-left: -2px;
margin-right: -2px;
}
}
@include exports(list) {
.inline-list {
@include inline-list(left);
li {
margin-right: 1rem;
margin-left: 0;
}
}
}
@@ -0,0 +1,363 @@
/*
MENU BAR
--------
A generic, flexible menu component.
Features:
- Orient horizontally and vertically
- Change orientation at certain breakpoints
- Items with icons above, below, or to the left or right
- Text labels for vertical menus and badges for horizontal menus
*/
/// @Foundation.settings
// Menu Bar
$menubar-fontsize: 1rem !default;
$menubar-background: #fff !default;
$menubar-background-hover: smartscale($menubar-background, 7%) !default;
$menubar-background-active: $menubar-background-hover;
$menubar-color: isitlight($menubar-background) !default;
$menubar-color-hover: $menubar-color !default;
$menubar-color-active: $menubar-color-hover;
$menubar-item-padding: $global-padding !default;
$menubar-icon-size: 25px !default;
$menubar-icon-spacing: $menubar-item-padding !default;
///
// Menu bar container
%menu-bar {
display: flex;
align-items: stretch;
margin: 0;
list-style-type: none;
// Menu item
> li {
// This flex setting makes each item an equal width
flex: 1 0 auto;
align-items: center;
// Link inside menu item
> a {
display: flex;
flex-flow: column nowrap;
align-items: center;
padding: $menubar-item-padding;
font-size: $menubar-fontsize;
line-height: 1;
}
}
}
@mixin menu-bar-layout (
$orientation: horizontal,
$stretch: true
) {
/*
Orientation
*/
@if $orientation == horizontal {
overflow-x: hidden;
flex-flow: row nowrap;
> li > a {
flex-flow: column nowrap;
}
}
@else {
flex-flow: column nowrap;
> li > a {
flex-flow: row nowrap;
}
}
/*
Stretch
*/
> li {
@if $stretch == false {
flex: 0 0 auto;
}
}
}
@mixin menu-bar-style(
$background: $menubar-background,
$background-hover: $menubar-background-hover,
$background-active: $menubar-background-active,
$color: $menubar-color,
$color-hover: $menubar-color-hover,
$color-active: $menubar-color-active,
$autocolor: false
) {
// Autocoloring
@if ($autocolor) {
$background-hover: smartscale($background, 7%);
$background-active: $background-hover;
$color: isitlight($background);
$color-hover: $color;
$color-active: $color;
}
// Container
background: $background;
// Items
> li > a {
color: $color;
&:hover {
background: $background-hover;
color: $color-hover;
}
}
.is-active > a {
background: $background-active;
color: $color-active
}
// Iconic
@if using(iconic) {
.iconic { @include color-icon($color); }
}
}
@mixin menu-bar-icons(
$position: left,
$size: $menubar-icon-size
) {
> li {
// Sizing
> img, > .iconic {
margin: 0;
@if $menubar-icon-size != false {
width: $menubar-icon-size;
height: $menubar-icon-size;
}
}
// Position
@if $position == left {
> a {
flex-flow: row nowrap;
align-items: center;
> img, > .iconic { margin: 0 $menubar-icon-spacing 0 0; }
}
}
@if $position == top {
> a {
flex-flow: column nowrap;
> img, > .iconic { margin: 0 0 $menubar-icon-spacing 0; }
}
}
@if $position == right {
> a {
flex-flow: row-reverse nowrap;
> img, > .iconic { margin: 0 0 0 $menubar-icon-spacing; }
}
}
@if $position == bottom {
> a {
flex-flow: column-reverse nowrap;
> img, > .iconic { margin: $menubar-icon-spacing 0 0 0; }
}
}
}
}
@mixin menu-bar-labels(
$x: right,
$y: center,
$offset: $menubar-item-padding,
$size: 1.2rem,
$background: red,
$color: auto,
$selector: '.menu-bar-label'
) {
> li {
position: relative;
> a {
@if $x == left or $x == right {
padding-#{$x}: $size + $offset * 2;
}
}
}
#{$selector} {
display: block;
font-size: $size * 0.75;
width: $size;
height: $size;
line-height: $size;
text-align: center;
border-radius: 1000px;
background: $background;
color: if($color == auto, isitlight($background), $color);
position: absolute;
pointer-events: none;
@if $x == left or $x == right {
#{$x}: $offset;
}
@if $y == top or $y == bottom {
#{$y}: $offset;
}
@else {
top: 50%;
transform: translateY(-50%);
}
}
}
/*
Set the alignment of menu items (li) within a menu-bar
left: Items align to the left.
right: Items align to the right.
center: Items align to the center.
justify: Items are spaced equally apart so they occupy the space of the entire grid.
spaced: Items are given equal space to their left and right.
@group menu-bar
@param {string} $align - Alignment to use.
@output An appropriate justify-content value.
*/
@mixin menu-bar-align($align: left) {
$options: (
left: flex-start,
right: flex-end,
center: center,
justify: space-between,
spaced: space-around,
);
justify-content: map-get($options, $align);
}
/*
CSS output
*/
@include exports(menu-bar) {
.menu-bar {
@extend %menu-bar;
@include menu-bar-style;
// Positioning
&, &.horizontal { @include menu-bar-layout(horizontal); }
&.vertical { @include menu-bar-layout(vertical); }
// Condensed bar
&.condense {
> li { flex: 0 0 auto; }
}
// Align Menu Items
&.align-right { @include menu-bar-align(right); }
&.align-center { @include menu-bar-align(center); }
&.align-justify { @include menu-bar-align(justify); }
&.align-spaced { @include menu-bar-align(spaced); }
@each $size in $breakpoint-classes {
@include breakpoint($size) {
&.#{$size}-condense { li { flex: 0 0 auto; } }
&.#{$size}-expand { li { flex: 1 0 auto; } }
// Responsive Alignment
&.#{$size}-align-left { @include menu-bar-align(left); }
&.#{$size}-align-right { @include menu-bar-align(right); }
&.#{$size}-align-center { @include menu-bar-align(center); }
&.#{$size}-align-justify { @include menu-bar-align(justify); }
&.#{$size}-align-spaced { @include menu-bar-align(spaced); }
}
}
// Responsive positioning
@each $size in $breakpoint-classes {
@include breakpoint($size) {
&.#{$size}-horizontal {
@include menu-bar-layout(horizontal);
}
&.#{$size}-vertical {
@include menu-bar-layout(vertical);
}
}
}
// Icon positioning
&, &.icon-top { @include menu-bar-icons(top); }
&.icon-right { @include menu-bar-icons(right); }
&.icon-bottom { @include menu-bar-icons(bottom); }
&.icon-left { @include menu-bar-icons(left); }
@each $size in $breakpoint-classes {
@each $pos in (top, right, bottom, left) {
@include breakpoint($size) {
&.#{$size}-icon-#{$pos} { @include menu-bar-icons($pos); }
}
}
}
// Labels
&.label-side { @include menu-bar-labels(right, center); }
&.label-corner { @include menu-bar-labels(right, top); }
// Coloring
&.primary {
@include menu-bar-style($primary-color, $autocolor: true);
}
&.dark {
@include menu-bar-style($dark-color, $autocolor: true);
}
// Title
> li.title {
padding: $menubar-item-padding;
cursor: default;
font-weight: bold;
}
}
// Menu groups
.menu-group {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
@include breakpoint(medium) {
flex-wrap: nowrap;
}
> .menu-group-left, > .menu-group-right {
flex: 1 1 100%;
@include breakpoint(medium) {
flex: 0 0 auto;
}
}
// Menu bar is condensed
.menu-bar {
> li { flex: 0 0 auto; }
margin: 0;
}
// Coloring class cascades down to the menu bar
&.primary {
background-color: $primary-color;
.menu-bar {
@include menu-bar-style($primary-color, $autocolor: true);
}
}
&.dark {
background-color: $dark-color;
.menu-bar {
@include menu-bar-style($dark-color, $autocolor: true);
}
}
}
}
@@ -0,0 +1,126 @@
/*
MODAL
-----
The humble modal hides off-canvas until summoned with an fa-open directive. Modals appear over an overlay that darkens the rest of the page, and have a maxmimum width. You can construct a grid inside a modal, or attach panels to it.
Note that the modal overlay is hardcoded into the CSS, because whether or not you build your modal semantically, the overlay is always required and will always look the same.
*/
/// @Foundation.settings
// Modal
$modal-background: #fff !default;
$modal-border: 0 !default;
$modal-radius: 0px !default;
$modal-shadow: none !default;
$modal-zindex: 1000 !default;
$modal-sizes: (
tiny: 300px,
small: 500px,
medium: 600px,
large: 800px,
) !default;
$modal-overlay-class: 'modal-overlay' !default;
$modal-overlay-background: rgba(#333, 0.7) !default;
///
%modal {
position: relative;
z-index: $modal-zindex + 1;
background: $modal-background;
flex: 0 0 auto;
width: 100%;
height: 100vh;
max-height: 100%;
overflow: hidden;
padding: $global-padding;
@include breakpoint(medium) {
height: auto;
max-width: map-get($modal-sizes, medium);
}
.grid-content, .grid-block {
margin: 0;
}
.close-button, [fa-close] {
z-index: $modal-zindex + 1;
}
}
@mixin modal-dialog() {
height: auto;
}
@mixin modal-layout(
$width: map-get($modal-sizes, medium),
$dialog: false
) {
max-width: $width;
}
@mixin modal-style(
$border: $modal-border,
$radius: $modal-radius,
$shadow: $modal-shadow
) {
@if $border != 0 {
border: $border;
}
@if $radius != 0px {
border-radius: $radius;
}
@if $shadow != none {
box-shadow: $shadow;
}
}
@mixin modal(
$width: map-get($modal-sizes, medium),
$border: $modal-border,
$radius: $modal-radius,
$shadow: $modal-shadow
) {
@extend %modal;
@include modal-layout($width);
@include modal-style($border, $radius, $shadow);
}
@include exports(modal) {
.modal {
@include modal;
@each $size in map-keys($modal-sizes) {
$width: map-get($modal-sizes, $size);
@if $size != medium {
.#{$size} > & { @include modal-layout($width); }
}
}
.dialog > & {
@include modal-dialog;
}
.collapse > & {
padding: 0;
}
}
.#{$modal-overlay-class} {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: $modal-zindex;
display: none;
background-color: $modal-overlay-background;
// Horizontally and vertically center the modal
align-items: center;
justify-content: center;
&.is-active {
display: flex;
}
}
}
@@ -0,0 +1,524 @@
// FOUNDATION MOTION UI
// Table of Contents
//
// 0. Variables
// 1. Base Transitions
// a. Slide
// b. Fade
// c. Hinge
// d. Scale
// e. Spin
// 2. Base Animations
// a. Shake
// b. Spinners
// c. Wiggle
// 3. HTML Attributes
// 0. Variables
// - - - - - - - - - - - - - - - - - - - - - - - - -
/// @Foundation.settings
// Motion UI
// Classes to use when triggering in/out animations
$motion-class: (
in: "ng-enter",
out: "ng-leave",
) !default;
$motion-class-active: (
in: "ng-enter-active",
out: "ng-leave-active",
) !default;
$motion-class-stagger: (
in: "ng-enter-stagger",
out: "ng-leave-stagger",
) !default;
$motion-class-showhide: (
in: "ng-hide-remove",
out: "ng-hide-add",
);
$motion-class-showhide-active: (
in: "ng-hide-remove-active",
out: "ng-hide-add-active",
);
// Set if movement-based transitions should also fade the element in and out
$motion-slide-and-fade: false !default;
$motion-hinge-and-fade: true !default;
$motion-scale-and-fade: true !default;
$motion-spin-and-fade: true !default;
// Default speed for transitions and animations
$motion-duration-default: 500ms !default;
// Slow and fast modifiders
$motion-duration-slow: 750ms !default;
$motion-duration-fast: 250ms !default;
$motion-stagger-duration-default: 150ms !default;
$motion-stagger-duration-short: 50ms !default;
$motion-stagger-duration-long: 300ms !default;
// Default timing function for transitions and animations
$motion-timing-default: ease !default;
// Built-in and custom easing functions
// Every item in this map becomes a CSS class
$motion-timings: (
linear: linear,
ease: ease,
easeIn: ease-in,
easeOut: ease-out,
easeInOut: ease-in-out,
bounceIn: cubic-bezier(0.485, 0.155, 0.240, 1.245),
bounceOut: cubic-bezier(0.485, 0.155, 0.515, 0.845),
bounceInOut: cubic-bezier(0.760, -0.245, 0.240, 1.245),
) !default;
// Default delay for all transitions and animations
$motion-delay-default: 0 !default;
// Short and long delay modifiers
$motion-delay-short: 300ms !default;
$motion-delay-long: 700ms !default;
///
// Looks for a timing function in the list of presets
// If none are found, returns the value as-is.
@function get-timing($timing) {
@if map-has-key($motion-timings, $timing) {
@return map-get($motion-timings, $timing);
}
@else {
@return $timing;
}
}
// Applies transition settings common to all mixins
@mixin transition-basics(
$duration: $motion-duration-default,
$timing: $motion-timing-default,
$delay: $motion-delay-default
) {
transition-duration: $duration;
transition-timing-function: get-timing($timing);
transition-delay: $delay;
}
// Wraps content in an enter/leave class, chained to the parent selector
// Define the initial state of a transition here
@mixin transition-start($dir) {
$sel1: map-get($motion-class, $dir);
$sel2: map-get($motion-class-showhide, $dir);
&.#{$sel1},
&.#{$sel2} {
@content;
}
}
// Wraps content in an enter/leave active class, chained to the matching
// enter/leave class, chained to the parent selector
// Define the end state of a transition here
@mixin transition-end($dir) {
$sel1: map-get($motion-class, $dir);
$sel1A: map-get($motion-class-active, $dir);
$sel2: map-get($motion-class-showhide, $dir);
$sel2A: map-get($motion-class-showhide-active, $dir);
&.#{$sel1}.#{$sel1A},
&.#{$sel2}.#{$sel2A} {
@content;
}
}
@mixin stagger($delay-amount) {
transition-delay: $delay-amount;
// this is to avoid accidental CSS inheritance
transition-duration:0;
}
// 1. Base Transitions
// - - - - - - - - - - - - - - - - - - - - - - - - -
// SLIDE
@mixin slide (
$dir: in,
$from: left,
$fade: $motion-slide-and-fade,
$duration: $motion-duration-default,
$timing: $motion-timing-default,
$delay: $motion-delay-default
) {
$slideDirections: (
top: translateY(-100%),
right: translateX(100%),
bottom: translateY(100%),
left: translateX(-100%),
);
$start: '';
$end: '';
@if $dir == in {
$start: map-get($slideDirections, $from);
$end: translateX(0) translateY(0);
}
@else {
$start: translateX(0) translateY(0);
$end: map-get($slideDirections, $from);
}
// CSS Output
@include transition-start($dir) {
@include transition-basics($duration, $timing, $delay);
transition-property: transform, opacity;
backface-visibility: hidden;
transform: $start;
@if $fade { opacity: if($dir == in, 0, 1); }
}
@include transition-end($dir) {
transform: $end;
@if $fade { opacity: if($dir == in, 1, 0); }
}
}
// FADE
@mixin fade(
$dir: in,
$from: 0,
$to: 1,
$duration: $motion-duration-default,
$timing: $motion-timing-default,
$delay: $motion-delay-default
) {
@include transition-start($dir) {
@include transition-basics($duration, $timing, $delay);
transition-property: opacity;
opacity: $from;
}
@include transition-end($dir) {
opacity: $to;
}
}
// HINGE
@mixin hinge (
$dir: in,
$from: left,
$axis: edge,
$perspective: 2000px,
$turn-origin: from-back,
$fade: $motion-hinge-and-fade,
$duration: $motion-duration-default,
$timing: $motion-timing-default,
$delay: $motion-delay-default
) {
// Rotation directions when hinging from back vs. front
$rotationAmount: 90deg;
$rotationsBack: (
top: rotateX($rotationAmount * -1),
right: rotateY($rotationAmount * -1),
bottom: rotateX($rotationAmount),
left: rotateY($rotationAmount),
);
$rotationsFrom: (
top: rotateX($rotationAmount),
right: rotateY($rotationAmount),
bottom: rotateX($rotationAmount * -1),
left: rotateY($rotationAmount * -1),
);
// Rotation origin
$rotation: '';
@if $turn-origin == from-front {
$rotation: map-get($rotationsFrom, $from);
}
@else if $turn-origin == from-back {
$rotation: map-get($rotationsBack, $from);
}
@else {
@warn "`$turn-origin` must be either `from-back` or `from-front`";
}
// Start and end state
$start: '';
$end: '';
@if $dir == in {
$start: perspective($perspective) $rotation;
$end: rotate(0deg);
}
@else {
$start: rotate(0deg);
$end: perspective($perspective) $rotation;
}
// Turn axis
$origin: '';
@if $axis == edge {
$origin: $from;
}
@else {
$origin: center;
}
@include transition-start($dir) {
@include transition-basics($duration, $timing, $delay);
transition-property: transform, opacity;
transform: $start;
transform-origin: $origin;
@if $fade { opacity: if($dir == in, 0, 1); }
}
@include transition-end($dir) {
transform: $end;
@if $fade { opacity: if($dir == in, 1, 0); }
}
}
// SCALE
@mixin scale(
$dir: in,
$from: 1.5,
$to: 1,
$fade: $motion-scale-and-fade,
$duration: $motion-duration-default,
$timing: $motion-timing-default,
$delay: $motion-delay-default
) {
@include transition-start($dir) {
@include transition-basics($duration, $timing, $delay);
transition-property: transform, property;
transform: scale($from);
@if $fade { opacity: if($dir == in, 0, 1) }
}
@include transition-end($dir) {
transform: scale($to);
@if $fade { opacity: if($dir == in, 1, 0) }
}
}
// SPIN
@mixin spin(
$dir: in,
$amount: 0.75turn,
$ccw: false,
$fade: $motion-spin-and-fade,
$duration: $motion-duration-default,
$timing: $motion-timing-default,
$delay: $motion-delay-default
) {
$amount: turn-to-deg($amount);
$start: 0;
$end: 0;
@if $dir == in {
$start: if($ccw, $amount, $amount * -1);
$end: 0;
}
@else {
$start: 0;
$end: if($ccw, $amount * -1, $amount);
}
@include transition-start($dir) {
transition-property: transform, opacity;
transform: rotate($start);
@if $fade { opacity: if($dir == in, 0, 1); }
}
@include transition-end($dir) {
transform: rotate($end);
@if $fade { opacity: if($dir == in, 1, 0); }
}
}
// 2. Base Animations
// - - - - - - - - - - - - - - - - - - - - - - - - -
// SHAKE
@keyframes shake {
0%, 10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90% {
transform: translateX(7%);
}
5%, 15%, 25%, 35%, 45%, 55%, 65%, 75%, 85%, 95% {
transform: translateX(-7%);
}
100% { transform: translateX(0); }
}
// SPINNERS
@keyframes spin-cw {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes spin-ccw {
0% { transform: rotate(0deg); }
100% { transform: rotate(-360deg); }
}
// WIGGLE
@keyframes wiggle {
40%, 50%, 60% {
transform: rotate(7deg);
}
35%, 45%, 55%, 65% {
transform: rotate(-7deg);
}
0%, 30%, 70%, 100% { transform: rotate(0); }
}
@mixin animation(
$animation,
$duration: $motion-duration-default,
$timing: $motion-timing-default,
$delay: $motion-delay-default,
$iterations: null
) {
animation-name: $animation;
animation-duration: $duration;
animation-timing-function: $timing;
backface-visibility: hidden;
transform: translate3d(0,0,0);
@if $delay != null {
animation-delay: $delay;
}
@if $iterations != null {
animation-iteration-count: $iterations;
}
@if $animation == null {
@warn "Please include an animation name";
}
}
// 3. HTML Exports
// - - - - - - - - - - - - - - - - - - - - - - - - -
@include exports(motion) {
/*
Transitions
*/
// Slide
.slideInDown { @include slide($from: top); }
.slideInLeft { @include slide($from: right); }
.slideInUp { @include slide($from: bottom); }
.slideInRight { @include slide($from: left); }
.slideOutBottom { @include slide($dir: out, $from: bottom); }
.slideOutRight { @include slide($dir: out, $from: right); }
.slideOutUp { @include slide($dir: out, $from: top); }
.slideOutLeft { @include slide($dir: out, $from: left); }
// Fade
.fadeIn { @include fade(in, 0, 1); }
.fadeOut { @include fade(out, 1, 0); }
// Hinge
.hingeInFromTop { @include hinge($dir: in, $from: top); }
.hingeInFromRight { @include hinge($dir: in, $from: right); }
.hingeInFromBottom { @include hinge($dir: in, $from: bottom); }
.hingeInFromLeft { @include hinge($dir: in, $from: left); }
.hingeInFromMiddleX { @include hinge($dir: in, $from: top, $axis: center); }
.hingeInFromMiddleY { @include hinge($dir: in, $from: right, $axis: center); }
.hingeOutFromTop { @include hinge($dir: out, $from: top); }
.hingeOutFromRight { @include hinge($dir: out, $from: right); }
.hingeOutFromBottom { @include hinge($dir: out, $from: bottom); }
.hingeOutFromLeft { @include hinge($dir: out, $from: left); }
.hingeOutFromMiddleX { @include hinge($dir: out, $from: top, $axis: center); }
.hingeOutFromMiddleY { @include hinge($dir: out, $from: right, $axis: center); }
// Scale
.zoomIn { @include scale(in, 1.5, 1); }
.zoomOut { @include scale(out, 0.5, 1); }
// Spin
.spinIn { @include spin(in, 0.75turn); }
.spinOut { @include spin(out, 0.75turn); }
.spinInCCW { @include spin(in, 0.75turn, true); }
.spinOutCCW { @include spin(out, 0.75turn, true); }
/*
Transition modifiers
*/
// Duration
.slow { transition-duration: $motion-duration-slow !important; }
.fast { transition-duration: $motion-duration-fast !important; }
// Easing
@each $easing in map-keys($motion-timings) {
.#{$easing} {
transition-timing-function: map-get($motion-timings, $easing) !important;
}
}
// Delay
.delay { transition-delay: $motion-delay-short !important; }
.long-delay { transition-delay: $motion-delay-long !important; }
/*
Animations
*/
.shake { @include animation(shake); }
.spin-cw { @include animation(spin-cw); }
.spin-ccw { @include animation(spin-ccw); }
.wiggle { @include animation(wiggle); }
/*
Animation modifiers
*/
.shake,
.spin-cw,
.spin-ccw,
.wiggle {
// Repeat
&.infinite { animation-iteration-count: infinite; }
// Easing
@each $timing in map-keys($motion-timings) {
&.#{$timing} {
animation-timing-function: map-get($motion-timings, $timing) !important;
}
}
// Duration
&.slow { animation-duration: $motion-duration-slow !important; }
&.fast { animation-duration: $motion-duration-fast !important; }
// Delay
&.delay { animation-delay: $motion-delay-short !important; }
&.long-delay { animation-delay: $motion-delay-long !important; }
}
.stagger { @include stagger($motion-stagger-duration-default); }
.stort-stagger { @include stagger($motion-stagger-duration-default); }
.long-stagger { @include stagger($motion-stagger-duration-default); }
}
// View animation classes
// - - - - - - - - - - - - - - - - - - - -
// Applied to the immediate parent of the animating views
.position-absolute {
overflow: hidden;
position: relative;
}
// Applied to the animating views
.ui-animation {
&.ng-enter-active, &.ng-leave-active {
position: absolute !important;
backface-visibility: hidden;
-webkit-transform-style: preserve-3d;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
}
@@ -0,0 +1,207 @@
/*
NOTIFICATION
------------
An alert that pins to the corner of the screen when triggered by JavaScript. It can be set to disappear after a certain period of time, or to stay put until the user clicks on it. A custom action can be asigned to a notification as well.
Optionally, the notifications directive can also tap into the browser's native notification support, if it exists.
*/
/// @Foundation.settings
// Notification
$notification-default-position: right top !default;
$notification-width: rem-calc(400) !default;
$notification-offset: $global-padding !default;
$notification-background: $primary-color !default;
$notification-color: white !default;
$notification-padding: $global-padding !default;
$notification-radius: 4px !default;
$notification-icon-size: 60px !default;
$notification-icon-margin: $global-padding !default;
$notification-icon-align: top !default;
///
%notification {
z-index: 1000;
display: flex;
position: relative;
margin-top: .5rem;
margin-bottom: .5rem;
display: none;
h1 {
font-size: 1.25em;
margin: 0;
}
p {
margin: 0;
}
// Placeholder animation
// transition: opacity 1s ease-out;
&.is-active {
display: flex;
}
.close-button {
color: white;
}
}
%notification-container {
z-index: 3000;
position: fixed;
display: flex;
flex-direction: column;
}
@mixin notification-layout(
$x: nth($notification-default-position, 1),
$y: nth($notification-default-position, 2),
$size: $notification-width,
$offset: $notification-offset
) {
width: $size;
@if $x == right {
right: $offset;
}
@else if $x == left {
left: $offset;
}
@else if $x == middle {
left: 50%;
margin-left: -($size / 2);
}
@if $y == top {
top: $offset;
}
@else if $y == bottom {
top: auto;
bottom: $offset;
}
// On small screens, notifications are full width but maintain their vertical orientation
@include breakpoint(small only) {
width: auto;
left: $offset;
right: $offset;
margin-left: 0;
}
}
@mixin notification-style(
$background: $notification-background,
$color: $notification-color,
$padding: $notification-padding,
$radius: $notification-radius
) {
background: $background;
padding: $padding;
border-radius: $radius;
&, h1, h2, h3, h4, h5, h6 {
color: $color;
}
}
@mixin notification(
$background: $notification-background,
$color: $notification-color,
$padding: $notification-padding,
$radius: $notification-radius
) {
@extend %notification;
@include notification-style($background, $color, $padding, $radius);
}
@mixin notification-container(
$x: nth($notification-default-position, 1),
$y: nth($notification-default-position, 2),
$size: $notification-width,
$offset: $notification-offset
) {
@extend %notification-container;
@include notification-layout($x, $y, $size, $offset);
}
@mixin notification-icon(
$size: $notification-icon-size,
$margin: $notification-icon-margin,
$align: $notification-icon-align
) {
$alignments: (
top: flex-start,
middle: middle,
bottom: flex-end,
);
flex: 0 0 $size;
margin-right: $global-padding;
align-self: map-get($alignments, $align);
img {
width: 100%;
height: auto;
}
}
/*
CSS Output
*/
@include exports(notification) {
.notification {
@include notification;
&.success { @include notification-style($success-color) }
&.warning { @include notification-style($warning-color) }
&.alert { @include notification-style($alert-color) }
&.dark { @include notification-style($dark-color, #fff) }
}
.static-notification {
@include notification;
position: fixed !important;
&.top-right { @include notification-layout(right, top); }
&.top-left { @include notification-layout(left, top); }
&.top-middle { @include notification-layout(middle, top); }
&.bottom-right { @include notification-layout(right, bottom); }
&.bottom-left { @include notification-layout(left, bottom); }
&.bottom-middle { @include notification-layout(middle, bottom); }
&.success { @include notification-style($success-color) }
&.warning { @include notification-style($warning-color) }
&.alert { @include notification-style($alert-color) }
&.dark { @include notification-style($dark-color, #fff) }
}
.notification-container {
@include notification-container;
&.top-right { @include notification-layout(right, top); }
&.top-left { @include notification-layout(left, top); }
&.top-middle { @include notification-layout(middle, top); }
&.bottom-right { @include notification-layout(right, bottom); }
&.bottom-left { @include notification-layout(left, bottom); }
&.bottom-middle { @include notification-layout(middle, bottom); }
}
.notification-icon {
@include notification-icon;
}
.notification-content {
flex: 1;
}
}
@@ -0,0 +1,169 @@
/*
Off-canvas menu
---------------
A generic container that stays fixed to the left, top, right, or bottom of the screen, and is summoned when needed. When an off-canvas panel is open, the app frame shifts over to reveal the menu.
*/
/// @Foundation.settings
// Off-canvas
$offcanvas-size-horizontal: 250px !default;
$offcanvas-size-vertical: 250px !default;
$offcanvas-background: #fff !default;
$offcanvas-color: isitlight($offcanvas-background) !default;
$offcanvas-padding: 0 !default;
$offcanvas-shadow: 3px 0 10px rgba(black, 0.25) !default;
$offcanvas-animation-speed: 0.25s !default;
$offcanvas-frame-selector: '.grid-frame' !default;
///
%off-canvas {
position: fixed;
overflow: auto;
-webkit-overflow-scrolling: touch;
transition: transform $offcanvas-animation-speed ease-out;
z-index: 2;
// Active state
&.is-active {
transform: translate(0,0) !important;
}
// Frame styles
& ~ #{$offcanvas-frame-selector} {
transform: translate(0,0,0);
transition: transform 0.25s ease-out;
backface-visibility: hidden;
background: white;
}
}
@mixin off-canvas-detached {
z-index: 0;
box-shadow: none;
&, &.is-active {
transform: none;
}
& ~ #{$offcanvas-frame-selector} {
z-index: 1;
box-shadow: 0 0 15px rgba(0,0,0,0.5);
}
}
@mixin off-canvas-layout(
$position: left,
$size: default,
$shadow: $offcanvas-shadow
) {
/*
Get shadow values for later use
*/
$shadow-length: '';
$shadow-size: '';
$shadow-color: '';
@if hasvalue($shadow) {
$shadow-length: get-shadow-value($shadow, x);
$shadow-size: get-shadow-value($shadow, size);
$shadow-color: get-shadow-value($shadow, color);
}
/*
Sizing
*/
@if $position == left or $position == right {
@if $size == default {
$size: $offcanvas-size-horizontal;
}
width: $size;
height: 100%;
}
@else {
@if $size == default {
$size: $offcanvas-size-vertical;
}
height: $size;
width: 100%;
}
/*
Positioning
*/
@if $position == left {
top: 0;
left: 0;
@if hasvalue($shadow) { box-shadow: inset (-$shadow-length) 0 $shadow-size $shadow-color; }
transform: translateX(-100%);
&.is-active {
& ~ #{$offcanvas-frame-selector} { transform: translateX($size) !important; }
}
}
@else if $position == right {
left: auto;
top: 0;
right: 0;
@if hasvalue($shadow) { box-shadow: inset $shadow-length 0 $shadow-size $shadow-color; }
transform: translateX(100%);
&.is-active {
& ~ #{$offcanvas-frame-selector} { transform: translateX(-$size) !important; }
}
}
@else if $position == top {
top: 0;
left: 0;
transform: translateY(-100%);
@if hasvalue($shadow) { box-shadow: inset 0 (-$shadow-length) $shadow-size $shadow-color; }
&.is-active {
& ~ #{$offcanvas-frame-selector} { transform: translateY($size) !important; }
}
}
@else if $position == bottom {
top: auto;
bottom: 0;
left: 0;
transform: translateY(100%);
@if hasvalue($shadow) { box-shadow: inset 0 $shadow-length $shadow-size $shadow-color; }
&.is-active {
& ~ #{$offcanvas-frame-selector} { transform: translateY(-$size) !important; }
}
}
}
@mixin off-canvas-style(
$background: $offcanvas-background,
$color: $offcanvas-color,
$padding: $offcanvas-padding
) {
background: $background;
@if $color == auto {
color: isitlight($background, #000, #fff);
}
@else {
color: $color;
}
@if hasvalue($padding) {
padding: $padding;
}
}
@include exports(off-canvas) {
.off-canvas {
@extend %off-canvas;
@include off-canvas-layout;
@include off-canvas-style;
&.top { @include off-canvas-layout(top); }
&.right { @include off-canvas-layout(right); }
&.bottom { @include off-canvas-layout(bottom); }
&.left { @include off-canvas-layout(left); }
&.detached { @include off-canvas-detached; }
&.primary { @include off-canvas-style($primary-color, auto); }
&.dark { @include off-canvas-style($dark-color, auto); }
}
}
@@ -0,0 +1,134 @@
/*
PANEL
-----
The friendly panel is an all-purpose container for hiding content off-screen.
Features:
- Position at top, right, bottom, or left
- Anchor to grid block or window
- Define max width or height
- Transform into grid block depending on screen size
*/
/// @Foundation.settings
// Panel
$panel-size-horizontal: 300px !default;
$panel-size-vertical: 300px !default;
$panel-padding: 0 !default;
$panel-background: #fff !default;
$panel-shadow: 3px 0 10px rgba(black, 0.25) !default;
// DEPRECATED: these variables will be removed in a future version.
$panel-animation-speed: 0.25s !default;
///
%panel-base {
display: block;
position: absolute;
z-index: 100;
overflow-y: auto;
display: none;
&.is-active {
display: block;
}
}
@mixin panel-layout(
$position: left,
$size: default,
$shadow: $panel-shadow
) {
@if $size == default {
@if $position == left or $position == right {
$size: $panel-size-horizontal;
}
@if $position == top or $position == bottom {
$size: $panel-size-vertical;
}
}
/*
Direction
*/
@if $position == top {
top: 0;
left: 0;
width: 100%;
}
@else if $position == right {
top: 0;
right: 0;
height: 100%;
}
@else if $position == bottom {
bottom: 0;
left: 0;
width: 100%;
}
@else if $position == left {
top: 0;
left: 0;
height: 100%;
}
/*
Sizing
*/
// Horizontal panels are always all the way tall and have a set width
@if $position == left or $position == right {
@if unit($size) == '%' {
width: $size;
}
@else {
width: 100%;
@include breakpoint($size) {
width: $size;
}
}
}
// (For now) vertical panels don't change size
@if $position == top or $position == bottom {
height: $size;
}
/*
Shadows
*/
$shadow-distance: get-shadow-value($shadow, x);
$shadow-size: get-shadow-value($shadow, size);
$shadow-color: get-shadow-value($shadow, color);
&.is-active {
@if $position == left { box-shadow: $shadow-distance 0 $shadow-size $shadow-color; }
@else if $position == right { box-shadow: (-$shadow-distance) 0 $shadow-size $shadow-color; }
@else if $position == top { box-shadow: 0 $shadow-distance $shadow-size $shadow-color; }
@else if $position == bottom { box-shadow: 2px (-$shadow-distance) $shadow-size $shadow-color; }
}
}
@mixin panel-style(
$padding: $panel-padding,
$background: $panel-background
) {
/*
Basic styles
*/
padding: $padding;
background: $background;
}
@include exports(panel) {
.panel {
@extend %panel-base;
@include panel-style;
}
.panel-top { @include panel-layout(top); }
.panel-right { @include panel-layout(right); }
.panel-bottom { @include panel-layout(bottom); }
.panel-left { @include panel-layout(left); }
.panel-fixed { position: fixed; }
}
@@ -0,0 +1,68 @@
/*
POPUP
-----
A floating container that can anchor to any other on-screen element, and contain any content, including grid blocks or panels.
*/
/// @Foundation.settings
// Popup
$popup-width: rem-calc(300) !default;
$popup-background: #fff !default;
$popup-border: 0 !default;
$popup-radius: 0 !default;
$popup-shadow: 0 0 10px rgba(#000, 0.25) !default;
///
%popup {
position: absolute;
z-index: 1000;
opacity: 0;
overflow: hidden;
transition: opacity 0.25s ease-out;
pointer-events: none;
&.tether-enabled {
opacity: 1;
pointer-events: auto;
}
}
@mixin popup-layout(
$width: $popup-width
) {
width: $popup-width;
}
@mixin popup-style(
$background: $popup-background,
$color: #000,
$radius: $popup-radius,
$shadow: $popup-shadow,
$border: $popup-border
) {
background: $background;
border-radius: $radius;
box-shadow: $shadow;
border: $border;
}
@mixin popup(
$width: $popup-width,
$background: $popup-background,
$radius: $popup-radius,
$shadow: $popup-shadow,
$border: $popup-border
) {
@extend %popup;
@include popup-layout($width);
@include popup-style($background, isitlight($background), $radius, $shadow, $border);
}
@include exports(popup) {
.popup {
@include popup;
&.dark { @include popup-style($dark-color, #fff); }
&.primary { @include popup-style($primary-color, isitlight($primary-color)); }
}
}
@@ -0,0 +1,130 @@
/*
SWITCH
------
*/
/// @Foundation.settings
// Switch
$switch-width: rem-calc(50) !default;
$switch-height: rem-calc(32) !default;
$switch-background: #ccc !default;
$switch-background-active: $primary-color !default;
$switch-border: 0 !default;
$switch-radius: 9999px !default;
$switch-animation-speed: 0.15s !default;
$switch-paddle-color: white !default;
$switch-paddle-offset: 4px !default;
///
%switch {
position: relative;
overflow: hidden;
display: inline-block;
> input {
position: absolute;
left: -9999px;
outline: none;
}
> label {
-ms-touch-action: manipulation;
touch-action: manipulation;
display: block;
width: 100%;
height: 100%;
cursor: pointer;
margin: 0;
// Paddle
&::after {
content: '';
display: block;
position: absolute;
top: 0;
left: 0;
}
}
}
/*
Defines the dimmensions of the switch.
$width - width of the switch.
$height - height of the switch.
*/
@mixin switch-layout(
$width: $switch-width,
$height: $switch-height
) {
width: $width;
height: $height;
> label {
&::after {
width: $height;
height: $height;
}
}
input:checked + label {
&::after {
left: $width - $height;
}
}
}
@mixin switch-style(
$background: $switch-background,
$background-active: $switch-background-active,
$border: $switch-border,
$radius: $switch-radius,
$paddle-color: $switch-paddle-color,
$paddle-offset: $switch-paddle-offset,
$animation-speed: $switch-animation-speed
) {
@if hasvalue($border) {
border: $border;
}
border-radius: $radius;
> label {
background: $background;
&::after {
background: $paddle-color;
border-radius: $radius;
transition: left $animation-speed ease-out;
@if hasvalue($paddle-offset) {
border: $paddle-offset solid $background
}
}
}
input:checked + label {
background: $background-active;
margin: 0;
&::after {
@if hasvalue($paddle-offset) {
border-color: $background-active;
}
}
}
}
@mixin switch() {
@extend %switch;
@include switch-layout;
@include switch-style;
}
@include exports(switch) {
.switch {
@include switch;
&.small { @include switch-layout(rem-calc(40), rem-calc(26)); }
&.large { @include switch-layout(rem-calc(60), rem-calc(38)); }
}
}
@@ -0,0 +1,100 @@
/*
TABS
----
*/
/// @Foundation.settings
// Tabs
$tabstrip-background: transparent !default;
$tab-title-background: $gray-light !default;
$tab-title-background-hover: smartscale($tab-title-background, 5%) !default;
$tab-title-background-active: smartscale($tab-title-background, 3%) !default;
$tab-title-color: isitlight($tab-title-background) !default;
$tab-title-color-active: $tab-title-color !default;
$tab-title-padding: $global-padding !default;
$tab-content-padding: $global-padding !default;
///
@mixin tabstrip(
$orientation: horizontal,
$background: $tabstrip-background
) {
/*
Container styles
*/
display: flex;
background: $background;
@if $orientation == vertical {
flex-flow: column nowrap;
}
@else {
flex-flow: row wrap;
}
}
@mixin tabstrip-item(
$background: $tab-title-background,
$background-hover: $tab-title-background-hover,
$background-active: $tab-title-background-active,
$color: $tab-title-color,
$color-active: $tab-title-color-active,
$padding: $tab-title-padding
) {
background: $background;
padding: $padding;
line-height: 1;
margin: 0;
flex: 0 1 auto;
cursor: pointer;
color: $color;
&.is-active {
background: $background-active;
color: $color-active;
&:hover {
background: $background-hover;
}
}
&:hover {
background: $background-hover;
}
}
@mixin tab-content(
$padding: $tab-content-padding
) {
padding: $padding;
}
@mixin tab-content-item {
display: none;
&.is-active {
display: block;
}
}
@include exports(tabs) {
.tabs {
@include tabstrip(horizontal);
&.vertical {
@include tabstrip(vertical);
}
.tab-item {
@include tabstrip-item;
}
}
.tab-contents {
@include tab-content;
.tab-content {
@include tab-content-item;
}
}
}
@@ -0,0 +1,135 @@
/*
TITLE BAR
---------
A navigational component which can display the current screen the user is on, along with additional controls or menu items.
The title bar includes classes to create center, left, and right sections, which can be used in any combination. However, in the markup, the sections must come in this order:
- Center
- Left
- Right
*/
/// @Foundation.settings
// Title Bar
$titlebar-center-width: 50% !default;
$titlebar-side-width: (100% - $titlebar-center-width) / 2 !default;
$titlebar-background: #eee !default;
$titlebar-color: #000 !default;
$titlebar-border: 1px solid #ccc !default;
$titlebar-padding: $global-padding !default;
$titlebar-item-classes: (
center: 'center',
left: 'left',
right: 'right',
title: 'title',
) !default;
///
%title-bar {
$center: map-get($titlebar-item-classes, center);
$left: map-get($titlebar-item-classes, left);
$right: map-get($titlebar-item-classes, right);
$title: map-get($titlebar-item-classes, title);
display: flex;
flex: 0 0 auto;
align-items: center;
justify-content: flex-start;
overflow: visible;
// Denotes the title of the bar
.#{$title} {
font-weight: bold;
}
// Denotes left, right, and center sections of the bar
.#{$left}, .#{$center}, .#{$right} {
display: block;
white-space: nowrap;
overflow: visible;
// If only one section is in use, stretch it all the way out
&:first-child:last-child {
flex: 1;
margin: 0;
}
}
// Left always comes first, then center, then right
// The left and right sections have the same width
.#{$left} {
order: 1;
flex: 0 0 $titlebar-side-width;
}
.#{$center} {
order: 2;
flex: 0 0 $titlebar-center-width;
text-align: center;
}
.#{$right} {
order: 3;
flex: 0 0 $titlebar-side-width;
text-align: right;
}
// If only left and right are in use, stretch them both out equally
.#{$left}:first-child {
flex: 1 1 auto;
}
.#{$left}:first-child + .#{$right}:last-child {
flex: 1 1 auto;
}
// If only center and right are in use, shift the center section into the right position
.#{$center}:first-child:not(:last-child) {
margin-left: $titlebar-side-width;
}
// If only center and left are in use, override the above style
.#{$center} + .#{$left} {
margin-right: -($titlebar-side-width);
}
}
@mixin title-bar-style(
$background: $titlebar-background,
$color: $titlebar-color,
$border: $titlebar-border,
$padding: $titlebar-padding
) {
background: $background;
color: $color;
padding: $padding;
border-bottom: $border;
}
@mixin title-bar(
$background: $titlebar-background,
$color: $titlebar-color,
$border: $titlebar-border,
$padding: $titlebar-padding
) {
@extend %title-bar;
@include title-bar-style($background, $color, $border, $padding);
}
@include exports(title-bar) {
.title-bar {
@include title-bar;
&.primary {
@include title-bar-style($primary-color, isitlight($primary-color));
a, a:hover { color: isitlight($primary-color); }
@if using(iconic) { .iconic { @include color-icon(isitlight($primary-color)); } }
}
&.dark {
@include title-bar-style($dark-color, #fff);
a, a:hover { color: #fff; }
@if using(iconic) { .iconic { @include color-icon(#fff); } }
}
}
.title-bar-bottom {
border-bottom: 0;
border-top: $titlebar-border;
}
}
@@ -0,0 +1,345 @@
/*
TYPOGRAPHY
----------
Includes typographic resets for many common elements, and a few helper classes.
- Headers
- Subheaders
- Lead paragraphs
- Ordered/unordered lists
- Code samples
- Anchors
- Dividers
- Blockquotes
- Acronyms
*/
/// @Foundation.settings
// Typography
// We use these to control header font styles
$header-font-family: $body-font-family !default;
$header-font-weight: $font-weight-normal !default;
$header-font-style: $font-weight-normal !default;
$header-font-color: #222 !default;
$header-line-height: 1.4 !default;
$header-top-margin: .2rem !default;
$header-bottom-margin: .5rem !default;
$header-text-rendering: optimizeLegibility !default;
// We use these to control header font sizes
$h1-font-size: rem-calc(44) !default;
$h2-font-size: rem-calc(37) !default;
$h3-font-size: rem-calc(27) !default;
$h4-font-size: rem-calc(23) !default;
$h5-font-size: rem-calc(18) !default;
$h6-font-size: 1rem !default;
// We use these to control header size reduction on small screens
$h1-font-reduction: rem-calc(10) !default;
$h2-font-reduction: rem-calc(10) !default;
$h3-font-reduction: rem-calc(5) !default;
$h4-font-reduction: rem-calc(5) !default;
$h5-font-reduction: 0 !default;
$h6-font-reduction: 0 !default;
// These control how subheaders are styled.
$subheader-line-height: 1.4 !default;
$subheader-font-color: scale-color($header-font-color, $lightness: 35%) !default;
$subheader-font-weight: $font-weight-normal !default;
$subheader-top-margin: .2rem !default;
$subheader-bottom-margin: .5rem !default;
// A general <small> styling
$small-font-size: 60% !default;
$small-font-color: scale-color($header-font-color, $lightness: 35%) !default;
// We use these to style paragraphs
$paragraph-font-family: inherit !default;
$paragraph-font-weight: $font-weight-normal !default;
$paragraph-font-size: 1rem !default;
$paragraph-line-height: 1.6 !default;
$paragraph-margin-bottom: rem-calc(20) !default;
$paragraph-aside-font-size: rem-calc(14) !default;
$paragraph-aside-line-height: 1.35 !default;
$paragraph-aside-font-style: italic !default;
$paragraph-text-rendering: optimizeLegibility !default;
// We use these to style <code> tags
$code-color: grayscale($primary-color) !default;
$code-font-family: Consolas, 'Liberation Mono', Courier, monospace !default;
$code-font-weight: $font-weight-normal !default;
$code-background-color: scale-color($secondary-color, $lightness: 70%) !default;
$code-border-size: 1px !default;
$code-border-style: solid !default;
$code-border-color: scale-color($code-background-color, $lightness: -10%) !default;
$code-padding: rem-calc(2) rem-calc(5) rem-calc(1) !default;
// We use these to style anchors
$anchor-text-decoration: none !default;
$anchor-text-decoration-hover: none !default;
$anchor-font-color: $primary-color !default;
$anchor-font-color-hover: scale-color($anchor-font-color, $lightness: -14%) !default;
// We use these to style the <hr> element
$hr-border-width: 1px !default;
$hr-border-style: solid !default;
$hr-border-color: #ddd !default;
$hr-margin: rem-calc(20) !default;
// We use these to style lists
$list-font-family: $paragraph-font-family !default;
$list-font-size: $paragraph-font-size !default;
$list-line-height: $paragraph-line-height !default;
$list-margin-bottom: $paragraph-margin-bottom !default;
$list-style-position: outside !default;
$list-side-margin: 1.1rem !default;
$list-ordered-side-margin: 1.4rem !default;
$list-side-margin-no-bullet: 0 !default;
$list-nested-margin: rem-calc(20) !default;
$definition-list-header-weight: $font-weight-bold !default;
$definition-list-header-margin-bottom: .3rem !default;
$definition-list-margin-bottom: rem-calc(12) !default;
// We use these to style blockquotes
$blockquote-font-color: scale-color($header-font-color, $lightness: 35%) !default;
$blockquote-padding: rem-calc(9 20 0 19) !default;
$blockquote-border: 1px solid #ddd !default;
$blockquote-cite-font-size: rem-calc(13) !default;
$blockquote-cite-font-color: scale-color($header-font-color, $lightness: 23%) !default;
$blockquote-cite-link-color: $blockquote-cite-font-color !default;
// Acronym styles
$acronym-underline: 1px dotted #ddd !default;
///
@mixin lead {
font-size: $paragraph-font-size + rem-calc(3.5);
line-height: 1.6;
}
@mixin subheader {
line-height: $subheader-line-height;
color: $subheader-font-color;
font-weight: $subheader-font-weight;
margin-top: $subheader-top-margin;
margin-bottom: $subheader-bottom-margin;
}
@include exports(typography) {
/* Typography resets */
div,
dl,
dt,
dd,
ul,
ol,
li,
h1,
h2,
h3,
h4,
h5,
h6,
pre,
form,
p,
blockquote,
th,
td {
margin:0;
padding:0;
}
/* Default Link Styles */
a {
color: $anchor-font-color;
text-decoration: $anchor-text-decoration;
line-height: inherit;
&[ui-sref] {
cursor: pointer;
}
&:hover,
&:focus {
color: $anchor-font-color-hover;
@if $anchor-text-decoration-hover != $anchor-text-decoration {
text-decoration: $anchor-text-decoration-hover;
}
}
img { border:none; }
}
/* Default paragraph styles */
p {
font-family: $paragraph-font-family;
font-weight: $paragraph-font-weight;
font-size: $paragraph-font-size;
line-height: $paragraph-line-height;
margin-bottom: $paragraph-margin-bottom;
text-rendering: $paragraph-text-rendering;
&.lead { @include lead; }
& aside {
font-size: $paragraph-aside-font-size;
line-height: $paragraph-aside-line-height;
font-style: $paragraph-aside-font-style;
}
}
/* Default header styles */
h1, h2, h3, h4, h5, h6 {
font-family: $header-font-family;
font-weight: $header-font-weight;
font-style: $header-font-style;
color: $header-font-color;
text-rendering: $header-text-rendering;
margin-top: $header-top-margin;
margin-bottom: $header-bottom-margin;
line-height: $header-line-height;
small {
font-size: $small-font-size;
color: $small-font-color;
line-height: 0;
}
}
h1 { font-size: $h1-font-size - $h1-font-reduction; }
h2 { font-size: $h2-font-size - $h2-font-reduction; }
h3 { font-size: $h3-font-size - $h3-font-reduction; }
h4 { font-size: $h4-font-size - $h4-font-reduction; }
h5 { font-size: $h5-font-size - $h5-font-reduction; }
h6 { font-size: $h6-font-size - $h6-font-reduction; }
.subheader { @include subheader; }
hr {
border: $hr-border-style $hr-border-color;
border-width: $hr-border-width 0 0;
clear: both;
margin: $hr-margin 0 ($hr-margin - rem-calc($hr-border-width));
height: 0;
}
/* Helpful Typography Defaults */
em,
i {
font-style: italic;
line-height: inherit;
}
strong,
b {
font-weight: $font-weight-bold;
line-height: inherit;
}
small {
font-size: $small-font-size;
color: $small-font-color;
line-height: inherit;
}
code {
font-family: $code-font-family;
font-weight: $code-font-weight;
color: $code-color;
background-color: $code-background-color;
border-width: $code-border-size;
border-style: $code-border-style;
border-color: $code-border-color;
padding: $code-padding;
}
/* Lists */
ul,
ol,
dl {
font-size: $list-font-size;
line-height: $list-line-height;
margin-bottom: $list-margin-bottom;
list-style-position: $list-style-position;
font-family: $list-font-family;
}
/* Lists */
ul, ol {
margin-left: $list-side-margin;
li {
ul,
ol {
margin-left: $list-nested-margin;
margin-bottom: 0;
}
}
}
/* Lists without bullets */
ul.no-bullet {
&, li ul, li ol {
list-style-type: none;
}
margin-left: $list-side-margin-no-bullet;
}
/* Definition Lists */
dl {
dt {
margin-bottom: $definition-list-header-margin-bottom;
font-weight: $definition-list-header-weight;
}
dd { margin-bottom: $definition-list-margin-bottom; }
}
/* Abbreviations */
abbr,
acronym {
text-transform: uppercase;
font-size: 90%;
color: $body-font-color;
border-bottom: $acronym-underline;
cursor: help;
}
abbr {
text-transform: none;
}
/* Blockquotes */
blockquote {
margin: 0 0 $paragraph-margin-bottom;
padding: $blockquote-padding;
border-left: $blockquote-border;
cite {
display: block;
font-size: $blockquote-cite-font-size;
color: $blockquote-cite-font-color;
&:before {
content: "\2014 \0020";
}
a,
a:visited {
color: $blockquote-cite-link-color;
}
}
}
blockquote,
blockquote p {
line-height: $paragraph-line-height;
color: $blockquote-font-color;
}
@include breakpoint(medium) {
h1,h2,h3,h4,h5,h6 { line-height: $header-line-height; }
h1 { font-size: $h1-font-size; }
h2 { font-size: $h2-font-size; }
h3 { font-size: $h3-font-size; }
h4 { font-size: $h4-font-size; }
h5 { font-size: $h5-font-size; }
h6 { font-size: $h6-font-size; }
}
}
@@ -0,0 +1,160 @@
/*
UTILITIES
---------
Responsive helper classes to assist you in quickly doing basic formatting and layout.
Features:
- Vertical alignment
- Visibility
- Text alignment
- Floating
*/
$block-selector: '[class*="grid-block"]';
@mixin show-for($size, $prop: block) {
&:not(.ng-hide) {
display: none !important;
@include breakpoint($size) {
display: $prop !important;
}
}
}
@mixin show-for-only($size, $prop: block) {
&:not(.ng-hide) {
display: none !important;
@include breakpoint($size only) {
display: $prop !important;
}
}
}
@mixin hide-for($size, $prop: block) {
&:not(.ng-hide) {
display: $prop !important;
@include breakpoint($size) {
display: none !important;
}
}
}
@mixin hide-for-only($size, $prop: block) {
&:not(.ng-hide) {
display: $prop !important;
@include breakpoint($size only) {
display: none !important;
}
}
}
@include exports(utilities) {
// Vertical alignment
.v-align {
display: flex;
align-items: center;
justify-content: space-between;
$align-values: (
'top': flex-start,
'center': center,
'bottom': flex-end,
);
@each $orient in (top, center, bottom) {
.align-#{$orient} {
align-self: map-get($align-values, $orient);
}
}
@each $size in $breakpoint-classes {
@each $orient in (top, center, bottom) {
@include breakpoint($size) {
.#{$size}-align-#{$orient} {
align-self: map-get($align-values, $orient);
}
}
}
}
}
// Visibility
.hide { display: none !important; }
.invisible { visibility: hidden; }
@each $size in $breakpoint-classes {
.hide-for-#{$size} {
@include hide-for($size);
&#{$block-selector} { @include hide-for($size, flex); }
}
.show-for-#{$size} {
@include show-for($size);
&#{$block-selector} { @include show-for($size, flex); }
}
.hide-for-#{$size}-only {
@include hide-for-only($size);
&#{$block-selector} { @include hide-for-only($size, flex); }
}
.show-for-#{$size}-only {
@include show-for-only($size);
&#{$block-selector} { @include show-for-only($size, flex); }
}
}
@each $orientation in (portrait, landscape) {
.hide-for-#{$orientation} {
@include breakpoint($orientation) {
display: none !important;
&#{$block-selector} { display: flex !important; }
}
}
.show-for-#{$orientation} {
display: none !important;
@include breakpoint($orientation) {
display: block !important;
&#{$block-selector} { display: flex !important; }
}
}
}
/*
Text alignment
*/
@each $align in (left, right, center, justify) {
.text-#{$align} {
text-align: $align;
}
@each $size in $breakpoint-classes {
@include breakpoint($size) {
.#{$size}-text-#{$align} {
text-align: $align;
}
}
@include breakpoint($size only) {
.#{$size}-only-text-#{$align} {
text-align: $align;
}
}
}
}
/*
Floating
*/
.clearfix { @include clearfix; }
@each $float in (left, right, none) {
.float-#{$float} {
float: #{$float};
}
}
}
+49
View File
@@ -0,0 +1,49 @@
// Foundation for Apps
// by ZURB
// foundation.zurb.com
// Licensed under MIT Open Source
$foundation-version: '1.1.0';
// Make sure the charset is set appropriately
@charset "UTF-8";
// Libraries (let's make Normalize an external dependency eventually)
@import
"vendor/normalize";
// Helpers
@import
"helpers/functions",
"helpers/mixins",
"helpers/breakpoints",
"helpers/images";
// Global styles
@import
"global";
// Components
@import
"components/action-sheet",
"components/block-list",
"components/button",
"components/button-group",
"components/card",
"components/extras",
"components/forms",
"components/grid",
"components/title-bar",
"components/label",
"components/list",
"components/menu-bar",
"components/modal",
"components/motion",
"components/notification",
"components/off-canvas",
"components/popup",
"components/switch",
"components/tabs",
"components/accordion",
"components/typography",
"components/utilities";
@@ -0,0 +1,154 @@
// Foundation for Apps
//
// BREAKPOINTS
// -----------
// Foundation for Apps has three core breakpoints: small (> 0), medium (>= 640), and large (>= 1024).
// There are two additional breakpoints, xlarge, and xxlarge, which (by default) do not output as sizing classes.
// Access named breakpoints using the mixin breakpoint($size), where $size is a breakpoint value.
// You can also pass an em, rem, or pixel value into this mixin to generate an em-based media query.
// Create new named breakpoints using the $breakpoints map. Change which named breakpoints get their own classes by modifying the $breakpoint-classes map.
// NOTE: If you change the $breakpoints map, know that all values must be ordered by width, smallest width first. So 0 is always your first value.
// 1. Variables
// - - - - - - - - - - - - - - -
/// @Foundation.settings
// Breakpoints
// These are our named breakpoints. You can use them in our breakpoint function like this: @include breakpoint(medium) { // Medium and larger styles }
$breakpoints: (
small: rem-calc(0),
medium: rem-calc(640),
large: rem-calc(1200),
xlarge: rem-calc(1440),
xxlarge: rem-calc(1920),
) !default;
// All of the names in this list will be output as classes in your CSS, like small-12, medium-6, and so on.
$breakpoint-classes: (small medium large) !default;
///
// 2. Mixins
// - - - - - - - - - - - - - - -
/// Wraps a media query around the content you put inside the mixin. This mixin accepts a number of values:
/// - If a string is passed, the mixin will look for it in the $breakpoints map, and use a media query there.
/// - If a pixel value is passed, it will be converted to an em value using $rem-base.
/// - If a rem value is passed, the unit will be changed to em.
/// - If an em value is passed, the value will be used as-is.
///
/// @param {mixed} $val - Breakpoint name or px/em/rem value to process.
///
/// @output If the breakpoint is "0px and larger", outputs the content. Otherwise, outputs the content wrapped in a media query.
@mixin breakpoint($val: small) {
// Size or keyword
$bp: nth($val, 1);
// Value for max-width media queries
$bpMax: 0;
// Direction of media query (up, down, or only)
$dir: if(length($val) > 1, nth($val, 2), up);
// Eventual output
$str: 'only screen';
// Is it a named media query?
$named: false;
// Orientation media queries have a unique syntax
@if $bp == 'landscape' or $bp == 'portrait' {
$str: $str + ' and (orientation: #{$bp})';
}
@else {
// Try to pull a named breakpoint out of the $breakpoints map
@if type-of($bp) == 'string' {
@if map-has-key($breakpoints, $bp) {
@if $dir == 'only' {
$next-bp: map-next($breakpoints, $bp);
@if $next-bp == null {
$bpMax: null;
}
@else {
$bpMax: $next-bp - (1/16);
}
}
$bp: map-get($breakpoints, $bp);
$named: true;
}
@else {
$bp: 0;
}
}
// Pixel and unitless values are converted to rems
@if unit($bp) == 'px' or unit($bp) == '' {
$bp: rem-calc($bp);
}
// Finally, the rem value is turned into an em value
$bp: strip-unit($bp) * 1em;
// Skip media query creation if the input is "0 up" or "0 down"
@if $bp > 0 or $dir == 'only' {
// And lo, a media query was born
@if $dir == 'only' {
@if $named == true {
$str: $str + ' and (min-width: #{$bp})';
@if $bpMax != null {
$str: $str + ' and (max-width: #{$bpMax})';
}
}
@else {
@debug 'ERROR: Only named media queries can have an "only" range.';
}
}
@else if $dir == 'down' {
$max: $bp - (1/16);
$str: $str + ' and (max-width: #{$max})';
}
@else {
$str: $str + ' and (min-width: #{$bp})';
}
}
}
// Output
@if $bp == 0em and $dir != 'only' {
@content;
}
@else {
@media #{$str} {
@content;
}
}
}
/// Prefixes selector $class with breakpoint keywords, allowing you to create a batch of breakpoint classes with one chunk of code. If you want to skip a breakpoint (like small, because mobile first and all that), add values to the $omit parameter.
///
/// @param {string} $class - Class to prefix with the breakpoint name and a hyphen.
/// @param {list} $omit - Named breakpoints to skip. No class will be added with breakpoints in this list.
@mixin each-breakpoint($class, $omit: ()) {
// Iterate through breakpoint classes
@each $size in $breakpoint-classes {
// Only do something if the breakpoint is not in $omit
@if index($omit, $size) == null {
$val: map-get($breakpoints, $size);
// Prefix $class with $size and a hyphen
.#{$size + '-' + $class} {
@include breakpoint($size) {
@content;
}
}
}
}
}
// 3. CSS Output
// - - - - - - - - - - - - - - -
// Meta styles are included in all builds, as they are a dependancy of the Javascript.
// Used to provide media query values for javascript components.
// Forward slash placed around everything to convince PhantomJS to read the value.
meta.foundation-version {
font-family: "#{$foundation-version}";
}
meta.foundation-mq {
font-family: "#{map-serialize($breakpoints)}";
}
@@ -0,0 +1,343 @@
// Foundation for Apps ALPHA
// by ZURB
// foundation.zurb.com
// Licensed under MIT Open Source
$include-css: () !default;
$modules: () !default;
$rem-base: 16px !default;
/// Checks if a module is in use.
@function using($name) {
// Import from global scope
$include-css: $include-css !global;
$module-key: map-get($include-css, $name);
@if $module-key == true or $module-key == null {
@return true;
}
@else {
@return false;
}
}
/// Checks if a module's CSS has already been exported.
@function imported($name) {
// Import from global scope
$modules: $modules !global;
// Check if the module is already on the imported list
@if type-of(index($modules, $name)) == 'number' {
@return true;
}
@else {
@return false;
}
}
/// Outputs the chunk of content passed if component $name hasn't yet been output.
/// This prevents code duplication by keeping track of which components have already been output.
///
/// @param {string} $name - Name of component to output
///
/// @output The content passed, if the component has not yet been exported.
@mixin exports($name) {
// Check if the module has already been imported
@if not(imported($name)) {
// Check if the module should be used
@if using($name) {
$modules: append($modules, $name) !global;
@content;
}
}
}
/// Map Serialize
/// Converts a Sass map to a URL-encoded string, like this: `key1=value1&key2=value2`. We use this function to encode the media queries in the `$breakpoints` variable, so it can be transferred to our JavaScript for use there.
///
/// @param {map} $map - Map to convert.
///
/// @return A string with a map converted to a string.
@function map-serialize($map) {
$str: '';
@each $key, $value in $map {
$str: $str + $key + '=' + $value + '&';
}
$str: str-slice($str, 1, -2);
@return $str;
}
/// Map Next
/// Find the next key in a map.
///
/// @param {map} $map - Map to traverse.
/// @param {mixed} $key - Key to use as a starting point.
///
/// @return The value for the key after `$key` if `$key` was found. If `$key` was not found, or `$key` was the last value in the map, returns null.
@function map-next($map, $key) {
// Store the values of the map as a list, so we can access them with nth
$values: map-values($map);
// Ghetto for loop
$i: 1;
$found: false;
@each $val in map-keys($map) {
@if $found == false {
@if ($key == $val) {
$found: true;
}
$i: $i + 1;
}
}
// If the key doesn't exist, or it's the last key in the map, return null
@if $i > length($map) {
@return null;
}
// Otherwise return the value
@else {
@return nth($values, $i);
}
}
/// Is It Light?
/// Checks the lightness of $color, and if it passes the $threshold of lightness, it returns the `$yes` color. Otherwise, it returns the `$no` color. Use this function to dynamically output a foreground color based on a given background color.
///
/// @param {color} $color - Color to check the lightness of.
/// @param {color} $yes - Color to return if $color is light.
/// @param {color} $no - Color to return if $color is dark.
/// @param {percentage} $threshold - Threshold of lightness to check against.
///
/// @return The $yes color or $no color.
@function isitlight($color, $yes: #000, $no: #fff, $threshold: 60%) {
@if (lightness($color) > $threshold) {
@return $yes;
}
@else {
@return $no;
}
}
/// Smart Scale
/// Scales a color to be lighter if it's light, or darker if it's dark. Use this function to "fade" a color appropriate to its lightness.
///
/// @param {color} $color - Color to scale.
/// @param {percentage} $scale - Amount to scale up or down.
/// @param {percentage} $threshold - Threshold of lightness to check against.
///
/// @return A scaled color.
@function smartscale($color, $scale: 5%, $threshold: 60%) {
@if lightness($color) > $threshold {
$scale: -$scale;
}
@return scale-color($color, $lightness: $scale);
}
/// Has Value
/// Returns true if a value is not 0, null, or none. Use this function to check for values like `border: 0` or `box-shadow: none`.
///
/// @param $val - Value to check.
///
/// @return True if `$val` is not 0, null, or none.
@function hasvalue($val) {
@if $val == null or $val == none {
@return false;
}
@if type-of($val) == 'number' and strip-unit($val) == 0 {
@return false;
}
@return true;
}
/// Get Side
/// Determine a top/right/bottom/right value on a padding, margin, etc. property, no matter how many values were passed in. Use this function if you need to know the specific side of a value, but don't know if the value is using shorthand.
///
/// @param {list|number} $val - Value to analyze. Should be a shorthand sizing property, e.g. "1em 2em 1em"
/// @param {keyword} $side - Side to return. Should be top, right, bottom, or left.
///
/// @return A single value based on `$val` and `$side`.
@function get-side($val, $side) {
$length: length($val);
@if $length == 1 {
@return $val;
}
@if $length == 2 {
@return map-get((
top: nth($val, 1),
bottom: nth($val, 1),
left: nth($val, 2),
right: nth($val, 2),
), $side);
}
@if $length == 3 {
@return map-get((
top: nth($val, 1),
left: nth($val, 2),
right: nth($val, 2),
bottom: nth($val, 3),
), $side);
}
@if $length == 4 {
@return map-get((
top: nth($val, 1),
right: nth($val, 2),
bottom: nth($val, 3),
left: nth($val, 4),
), $side);
}
}
/// Get Border Value
/// Given border $val, find a specific element of the border, which is $elem. The possible values for $elem are width, style, and color.
///
/// @param {list} $val - Border value to find a value in.
/// @param {keyword} $elem - Border component to extract.
///
/// @param If the value exists, returns the value. If the value is not in the border definition, the function will return a 0px width, solid style, or black border.
@function get-border-value($val, $elem) {
// Find the width, style, or color and return it
@each $v in $val {
$type: type-of($v);
@if $elem == width and $type == 'number' {
@return $v;
}
@if $elem == style and $type == 'string' {
@return $v;
}
@if $elem == color and $type == 'color' {
@return $v;
}
}
// Defaults
$defaults: (
width: 0,
style: solid,
color: black,
);
@return map-get($defaults, $elem);
}
/// Get Shadow Value
/// Given shadow value $val, find a specific element of the shadow, which is $elem. The possible values for $elem are x, y, size, spread, color, and inset.
///
/// @param {list} $val - Shadow value to find a value in.
/// @param {keyword} $elem - Shadow component to extract.
///
/// @return If the value exists, returns the value. If the value is not set, returns false. If `$elem` is "inset", returns true, otherwise false.
@function get-shadow-value($val, $elem) {
// Return "none" if there's no shadow
@if $val == none {
@return none;
}
// Inset and color are always at the beginning and end
@if $elem == inset {
@return nth($val, 1) == inset;
}
@if $elem == color {
@if type-of(nth($val, -1)) == color {
@return nth($val, -1);
}
@else {
@return black;
}
}
// The rest of the values are located perilously in the middle
$values: ();
@each $v in $val {
@if type-of($v) == 'number' {
$values: append($values, $v);
}
}
@if $elem == x {
@if length($values) >= 1 {
@return nth($values, 1);
}
@else {
@return 0;
}
}
@else if $elem == y {
@if length($values) >= 2 {
@return nth($values, 2);
}
@else {
@return 0;
}
}
@else if $elem == size {
@if length($values) >= 3 {
@return nth($values, 3);
}
@else {
@return 0;
}
}
@else if $elem == spread {
@if length($values) >= 4 {
@return nth($values, 4);
}
@else {
@return 0;
}
}
@else {
@return false;
}
}
/// Strip Unit
/// Removes the unit (e.g. px, em, rem) from a value, returning the number only.
///
/// @param {number} $num - Number to strip unit from.
///
/// @return The same number, sans unit.
@function strip-unit($num) {
@return $num / ($num * 0 + 1);
}
/// Turn to Degrees
/// Converts a turn unit to the equivalent unit in degrees. 1turn is equal to 360 degrees. Not all browsers support turn, so this function allows us to use turns while outputting a value that all browsers understand.
///
/// @param {number} $value - Turn value to convert.
///
/// @return The same value, but in degrees.
@function turn-to-deg($value) {
@return strip-unit($value) * 360deg;
}
/// Convert to Rem
/// Converts a pixel value to matching rem value. *Any* value passed, regardless of unit, is assumed to be a pixel value. By default, the base pixel value used to calculate the rem value is taken from the `$rem-base` variable.
///
/// @param {number} $value - Pixel value to convert.
///
/// @return A number in rems, calculated based on the given value and the base pixel value.
@function convert-to-rem($value, $base-value: $rem-base) {
$value: strip-unit($value) / strip-unit($base-value) * 1rem;
@if ($value == 0rem) { $value: 0; } // Turn 0rem into 0
@return $value;
}
/// Rem Calculator
/// Converts one or more pixel values into matching rem values. This function works a lot like `convert-to-rem`, except it can convert more than one value at once, which is useful when setting multiple values on a `margin` or `padding` property.
///
/// @param {number|list} $values - One or more values to convert. Be sure to separate them with spaces and not commas. If you need to convert a comma-separated list, wrap the list in parentheses.
///
/// @return A list of converted values.
@function rem-calc($values, $base-value: null) {
@if $base-value == null {
$base-value: $rem-base;
}
$max: length($values);
@if $max == 1 { @return convert-to-rem(nth($values, 1), $base-value); }
$remValues: ();
@for $i from 1 through $max {
$remValues: append($remValues, convert-to-rem(nth($values, $i), $base-value));
}
@return $remValues;
}
@@ -0,0 +1,19 @@
@function image-triangle($color: #000) {
$color: rgb(red($color), green($color), blue($color));
@return 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="32" height="24" viewBox="0 0 32 24"><polygon points="0,0 32,0 16,24" style="fill: #{$color}"></polygon></svg>';
}
@mixin image-checkmark($color: #000) {
$color: rgb(red($color), green($color), blue($color));
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="32" height="32" viewBox="0 0 32 32"><path fill="#{$color}" d="M16 0c-8.837 0-16 7.163-16 16s7.163 16 16 16 16-7.163 16-16-7.163-16-16-16zm6.906 8.875l2.219 2.031-12.063 13.281-6.188-6.188 2.125-2.125 3.938 3.938 9.969-10.938z"/></svg>');
// IE10 fallback, since it doesn't support SVG data URLs
@media screen and (min-width:0\0) {
@if lightness($color) < 60% {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdlJREFUeNrMl0FugzAQRY3TRZeoFyhVL0BOkGTXJezaHZwguUnECaCrdFd6gqQnCN11Uyk5QekNOlONJWMVGMCgfGlkEIY3HnsG2xFM3d96PjQB2AJsWdPtAPYOln+dTwXnuw4DHEGzBvNFN6EDCTiS9XIAwB40acNoucKoxODIie0AwAOCu8KOSnIiNx/MakK+A7sW9oTferxx3fP3T1nURoBG/irGVahHwjHm/Ggx7E3TMVdrQmoP0gngghhpZQ3QvG/EdPLUelARWI8Aycjq9Md0qMIdbcNhjmOKLoY7quk3l1Rebeqg4AwFkmq7LWGOh1pmNY0etZAWSq0OX8HoS4JvWuCopbSY26EGR/CW86K0BF+pwkLwlPuyHJhOCl5oe4ZtF++vOqST+GdOYwO+71pN2VNAjmQGPCe42weuHDg0PI8olUwnYrXTGQJH9gxq8l1LKvrQx4O6/YY32Kp/ugb3ey7gZ4xAzuhYiYTxB/UHZFAuaREVXZ2g6yFlvEC2yoKEmbsRZYNgVLk2JeaOaG+xLHN+WCszDWMqLGOrJFa1DlApjSdwoHJGqGzLIb0+cas0wh5Bh780ngswx8GJD7h8sHg2wLA/mfDLPZpdxOF0quP5rwADAAFIzSRvu1m5AAAAAElFTkSuQmCC');
}
@else {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAT9JREFUeNrMV4sRgyAMDU7gCI6AE7QjMILdoCO4Cd2g3aB2Ah2hG7Qb0ODRO2r98Anqu8txKvISII/AwBFKKY6NQDugHSe6NWgPtBtjrAMKIHGF1ip/6H+qGOIC7a7ioccofMkF2kvRQY8lfKY8FSqXyFPjZyaYvebYtGg5pMUbrcQseeqHzPogVyAHwyHXXPfZ/cCMA3rqOXGkF9NObbwOl6HsFS5BdNKaXTnTj2dGXinRYGQnx74CiNTOlt/cMfpeJSEh+dnlJyCU2iIkq4CInIemtIsDcmYth+Tc9xCDyHQSMeReDow4UVnv89Dj2yUNx5wYkreB+6dPw9pH2QbOxJBr1D5SLEccuEZmEP8O1Po64aByi8IVehxLAvL/8oz4TFjefHspyTYvSvdVlu/iYrKLq9mal1O29fX8I8AANpIQzC0hTdEAAAAASUVORK5CYII=');
}
}
}
@@ -0,0 +1,123 @@
// Foundation for Apps
//
// Mixins
// ------
// The framework comes with a number of mixins that help you easily create common small components,
// like triangles and menu icons.
/// CSS Triangle
/// Creates a CSS triangle, which can be used for dropdown arrows, popup tails, and more. Use this mixin inside a `&::before` or `&::after` selector, to attach the triangle to an existing element.
///
/// @param {number} $triangle-size - Width of the triangle.
/// @param {color} $triangle-color - Color of the triangle.
/// @param {keyword} $triangle-direction - Direction the triangle points. Can be `top`, `right`, `bottom`, or `left`.
@mixin css-triangle($triangle-size, $triangle-color, $triangle-direction) {
content: "";
display: block;
width: 0;
height: 0;
border: inset $triangle-size;
@if ($triangle-direction == top) {
border-color: $triangle-color transparent transparent transparent;
border-top-style: solid;
}
@if ($triangle-direction == bottom) {
border-color: transparent transparent $triangle-color transparent;
border-bottom-style: solid;
}
@if ($triangle-direction == left) {
border-color: transparent transparent transparent $triangle-color;
border-left-style: solid;
}
@if ($triangle-direction == right) {
border-color: transparent $triangle-color transparent transparent;
border-right-style: solid;
}
}
// @mixins
//
/// Hamburger
/// Creates a three-line menu icon, affectionately referred to as the "hamburger icon".
///
/// @param {number} $width - Width of the icon, in rem units.
/// @param {number|boolean} $left - Left offset of the icon. Set to `false` to center the icon horizontally.
/// @param {number|boolean} $top - Top offset of the icon. Set to `false` to center the icon vertically.
/// @param {number} $thickness - Height of each line in the icon.
/// @param {number} $gap - Amount of space between each line.
/// @param {color} $color - Color of the lines.
/// @param {color} $hover-color - Color of the lines on hover.
@mixin hamburger($width, $left, $top, $thickness, $gap, $color, $hover-color, $offcanvas) {
span::after {
content: "";
position: absolute;
display: block;
height: 0;
@if $offcanvas {
@if $top {
top: $top;
}
@else {
top: 50%;
margin-top: -$width/2;
}
@if $left {
left: $left;
}
@else {
left: ($tabbar-menu-icon-width - $width)/2;
}
}
@else {
top: 50%;
margin-top: -$width/2;
#{$opposite-direction}: $topbar-link-padding;
}
box-shadow:
0 0px 0 $thickness $color,
0 $gap + $thickness 0 $thickness $color,
0 (2 * $gap + 2*$thickness) 0 $thickness $color;
width: $width;
}
span:hover:after {
box-shadow:
0 0px 0 $thickness $hover-color,
0 $gap + $thickness 0 $thickness $hover-color,
0 (2 * $gap + 2*$thickness) 0 $thickness $hover-color;
}
}
/// Clearfix
/// Uses the micro clearfix hack popularized by Nicolas Gallagher. Include this mixin on a container if its children are all floated, to give the container a proper height.
///
/// @see http://nicolasgallagher.com/micro-clearfix-hack/
@mixin clearfix {
&:before, &:after { content: " "; display: table; }
&:after { clear: both; }
}
/// Invisible Element
/// Makes an element visually hidden, but accessible.
///
/// @see http://snook.ca/archives/html_and_css/hiding-content-for-accessibility
@mixin element-invisible {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px, 1px, 1px, 1px);
}
/// Invisible Element Off
/// Reverses the CSS output by the `element-invisible()` mixin.
@mixin element-invisible-off {
position: static !important;
height: auto;
width: auto;
overflow: visible;
clip: auto;
}
$text-input-selectors: 'input[type="text"], input[type="password"], input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="month"], input[type="week"], input[type="email"], input[type="number"], input[type="search"], input[type="tel"], input[type="time"], input[type="url"], input[type="color"], textarea';
@@ -0,0 +1,425 @@
/*! normalize.css v3.0.1 | MIT License | git.io/normalize */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS text size adjust after orientation change, without disabling
* user zoom.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11 and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
display: block;
}
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
audio,
canvas,
progress,
video {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
*/
[hidden],
template {
display: none;
}
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background: transparent;
}
/**
* Improve readability when focused and also mouse hovered in all browsers.
*/
a:active,
a:hover {
outline: 0;
}
/* Text-level semantics
========================================================================== */
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b,
strong {
font-weight: bold;
}
/**
* Address styling not present in Safari and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9/10.
*/
img {
border: 0;
}
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden;
}
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
figure {
margin: 1em 40px;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto;
}
/**
* Address odd `em`-unit font size rendering in all browsers.
*/
code,
kbd,
pre,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button,
input,
optgroup,
select,
textarea {
color: inherit; /* 1 */
font: inherit; /* 2 */
margin: 0; /* 3 */
}
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal;
}
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome
* (include `-moz` to future-proof).
*/
input[type="search"] {
-webkit-appearance: textfield; /* 1 */
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box; /* 2 */
box-sizing: content-box;
}
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto;
}
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
optgroup {
font-weight: bold;
}
/* Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}
+4 -1
View File
@@ -36,7 +36,10 @@ module WorkPackages
attribute :subject
attribute :description
attribute :status_id
attribute :status_id,
writeable: ->(*) {
!model.closed_version_and_status?
}
attribute :type_id
attribute :priority_id
attribute :category_id
+6 -2
View File
@@ -73,13 +73,17 @@ class AdminController < ApplicationController
def info
@db_adapter_name = ActiveRecord::Base.connection.adapter_name
repository_writable = File.writable?(OpenProject::Configuration.attachments_storage_path)
@checklist = [
[:text_default_administrator_account_changed, User.default_admin_account_changed?],
[:text_file_repository_writable, repository_writable],
[:text_database_allows_tsv, OpenProject::Database.allows_tsv?]
]
# Add local directory test if we're not using fog
if OpenProject::Configuration.file_storage?
repository_writable = File.writable?(OpenProject::Configuration.attachments_storage_path)
@checklist << [:text_file_repository_writable, repository_writable]
end
if OpenProject::Database.allows_tsv?
@checklist += plaintext_extraction_checks
end
-96
View File
@@ -1,96 +0,0 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2018 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2017 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See docs/COPYRIGHT.rdoc for more details.
#++
class AttachmentsController < ApplicationController
before_action :find_project
before_action :file_readable, :read_authorize, except: :destroy
before_action :delete_authorize, only: :destroy
def download
url = @attachment.external_url
if url
redirect_to url.to_s
else
serve_attachment @attachment
end
end
def destroy
# Make sure association callbacks are called
@attachment.container.attachments.delete(@attachment)
redirect_to url_for(destroy_response_url(@attachment.container))
end
def fulltext
render plain: @attachment.fulltext.to_s
end
private
def find_project
@attachment = Attachment.find(params[:id])
# Show 404 if the filename in the url is wrong
raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename
@project = @attachment.project
rescue ActiveRecord::RecordNotFound
render_404
end
# Checks that the file exists and is readable
def file_readable
@attachment.readable? ? true : render_404
end
def read_authorize
@attachment.visible? ? true : deny_access
end
def delete_authorize
@attachment.deletable? ? true : deny_access
end
def destroy_response_url(container)
url_for(container.is_a?(WikiPage) ? [@project, container.wiki] : container)
end
def serve_attachment(attachment)
if attachment.container.is_a?(Version) || attachment.container.is_a?(Project)
attachment.increment_download
end
# browsers should not try to guess the content-type
response.headers['X-Content-Type-Options'] = 'nosniff'
send_file attachment.diskfile, filename: filename_for_content_disposition(attachment.filename),
type: attachment.content_type,
disposition: attachment.content_disposition
end
end
+5 -11
View File
@@ -35,8 +35,9 @@ class HighlightingController < ApplicationController
response.content_type = Mime[:css]
request.format = :css
if stale?(last_modified: @last_modified_times.max, etag: cache_key, public: true)
OpenProject::Cache.fetch(@last_modified_times.max) do
expires_in 1.year, public: true, must_revalidate: false
if stale?(last_modified: Time.zone.parse(@max_updated_at), etag: @highlight_version_tag, public: true)
OpenProject::Cache.fetch('highlighting/styles', @highlight_version_tag) do
render template: 'highlighting/styles', formats: [:css]
end
end
@@ -44,15 +45,8 @@ class HighlightingController < ApplicationController
private
def cache_key
OpenProject::Cache::CacheKey.expand @last_modified_times
end
def determine_freshness
@last_modified_times = [
Status.maximum(:updated_at),
IssuePriority.maximum(:updated_at),
Type.maximum(:updated_at)
].compact
@max_updated_at = helpers.highlight_css_updated_at || Time.now.iso8601
@highlight_version_tag = helpers.highlight_css_version_tag(@max_updated_at)
end
end
-16
View File
@@ -53,8 +53,6 @@ class WikiController < ApplicationController
history
diff
annotate
add_attachment
list_attachments
destroy]
before_action :build_wiki_page_and_content, only: %i[new create]
@@ -345,20 +343,6 @@ class WikiController < ApplicationController
end
end
def add_attachment
return render_403 unless editable?
@page.attach_files(permitted_params.attachments.to_h)
@page.save
redirect_to action: 'show', id: @page, project_id: @project
end
def list_attachments
respond_to do |format|
format.json { render 'common/list_attachments', locals: { attachments: @page.attachments } }
format.html
end
end
def current_menu_item_sym(page)
page = page_for_menu_item(page)
+4
View File
@@ -3,6 +3,10 @@ module AdditionalUrlHelpers
module_function
def fixed_home_url
home_url(script_name: OpenProject::Configuration.rails_relative_url_root)
end
def add_params_to_uri(uri, args = {})
uri = URI.parse uri
query = URI.decode_www_form String(uri.query)
+9
View File
@@ -0,0 +1,9 @@
module HighlightingHelper
def highlight_css_version_tag(max_updated_at = highlight_css_updated_at)
OpenProject::Cache::CacheKey.expand max_updated_at
end
def highlight_css_updated_at
ApplicationRecord.most_recently_changed Status, IssuePriority, Type
end
end
+27
View File
@@ -1,3 +1,30 @@
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
##
# Get the newest recently changed resource for the given record classes
#
# e.g., +most_recently_changed(WorkPackage, Type, Status)+
#
# Returns the timestamp of the most recently updated value
def self.most_recently_changed(*record_classes)
queries = record_classes.map do |clz|
column_name = clz.send(:timestamp_attributes_for_update_in_model)&.first || 'updated_at'
"(SELECT MAX(#{column_name}) AS max_updated_at FROM #{clz.table_name})"
end
.join(" UNION ")
union_query = <<~SQL
SELECT MAX(union_query.max_updated_at)
FROM (#{queries})
AS union_query
SQL
ActiveRecord::Base
.connection
.select_all(union_query)
.rows
&.first # first result row
&.first # max column
end
end
+2 -6
View File
@@ -53,7 +53,7 @@ class CustomAction < ActiveRecord::Base
ret
end
def reload
def reload(*args)
@conditions = nil
super
@@ -113,11 +113,7 @@ class CustomAction < ActiveRecord::Base
availables.map do |available|
existing = actual.detect { |a| a.key == available.key }
if existing
existing
else
available.new
end
existing || available.new
end
end
+10 -3
View File
@@ -30,8 +30,15 @@
# Configures a Query on the Query model. This allows to
# e.g get all queries that belong to a specific project or
# all projects that are global
module Queries::Queries
Queries::Register.filter Queries::Queries::QueryQuery, Queries::Queries::Filters::ProjectFilter
Queries::Register.filter Queries::Queries::QueryQuery, Queries::Queries::Filters::ProjectIdentifierFilter
Queries::Register.filter Queries::Queries::QueryQuery, Queries::Queries::Filters::HiddenFilter
filters_ns = Queries::Queries::Filters
query_ns = Queries::Queries::QueryQuery
register = Queries::Register
register.filter query_ns, filters_ns::ProjectFilter
register.filter query_ns, filters_ns::ProjectIdentifierFilter
register.filter query_ns, filters_ns::HiddenFilter
register.filter query_ns, filters_ns::UpdatedAtFilter
register.filter query_ns, filters_ns::IdFilter
end
@@ -0,0 +1,35 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2018 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2017 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See docs/COPYRIGHT.rdoc for more details.
#++
class Queries::Queries::Filters::IdFilter < Queries::Queries::Filters::QueryFilter
def type
:integer
end
end
@@ -0,0 +1,35 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2018 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2017 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See docs/COPYRIGHT.rdoc for more details.
#++
class Queries::Queries::Filters::UpdatedAtFilter < Queries::Queries::Filters::QueryFilter
def type
:datetime_past
end
end
+4 -3
View File
@@ -31,12 +31,12 @@
class Status < ActiveRecord::Base
extend Pagination::Model
default_scope { order('position ASC') }
default_scope { order_by_position }
before_destroy :check_integrity
has_many :workflows, foreign_key: 'old_status_id'
acts_as_list
belongs_to :color, class_name: 'Color', foreign_key: 'color_id'
belongs_to :color, class_name: 'Color', foreign_key: 'color_id'
before_destroy :delete_workflows
@@ -57,7 +57,7 @@ class Status < ActiveRecord::Base
end
def self.where_default
where(['is_default=?', true])
where(is_default: true)
end
# Update all the +Issues+ setting their done_ratio to the value of their +Status+
@@ -107,6 +107,7 @@ class Status < ActiveRecord::Base
def is_readonly
return false unless can_readonly?
super
end
alias :is_readonly? :is_readonly
+8 -3
View File
@@ -165,20 +165,25 @@ module Type::AttributeGroups
end
end
##
# Get the default attribute groups for this type.
# If it has activated custom fields through +custom_field_ids=+,
# it will put them into the other group.
def work_package_attributes_by_default_group_key
active_cfs = active_custom_field_attributes
work_package_attributes
.keys
.reject { |key| CustomField.custom_field_attribute?(key) && !active_cfs.include?(key) }
.select { |key| default_attribute?(active_cfs, key) }
.group_by { |key| default_group_key(key.to_sym) }
end
##
# Custom fields should not get included into the default form configuration.
# This method might get patched by modules.
def default_attribute?(active_cfs, key)
!(CustomField.custom_field_attribute?(key) && !active_cfs.include?(key))
end
def to_attribute_group_class(groups)
groups.map do |group|
attributes = group[1]
+14 -5
View File
@@ -246,11 +246,14 @@ class WorkPackage < ActiveRecord::Base
end
# Users/groups the work_package can be assigned to
extend Forwardable
def_delegator :project, :possible_assignees, :assignable_assignees
def assignable_assignees
project.possible_assignees
end
# Users the work_package can be assigned to
def_delegator :project, :possible_responsibles, :assignable_responsibles
def assignable_responsibles
project.possible_responsibles
end
# Versions that the work_package can be assigned to
# A work_package can be assigned to:
@@ -279,13 +282,17 @@ class WorkPackage < ActiveRecord::Base
status.present? && status.is_readonly?
end
def closed_version_and_status?
fixed_version&.closed? && status.is_closed?
end
# Returns true if the work_package is overdue
def overdue?
!due_date.nil? && (due_date < Date.today) && !closed?
end
def milestone?
type && type.is_milestone?
type&.is_milestone?
end
alias_method :is_milestone?, :milestone?
@@ -295,10 +302,12 @@ class WorkPackage < ActiveRecord::Base
current_status = Status.where(id: status_id)
return current_status if closed_version_and_status?
statuses = new_statuses_allowed_by_workflow_to(user)
.or(current_status)
statuses = statuses.or(Status.where(id: Status.default.id)) if include_default
statuses = statuses.or(Status.where_default) if include_default
statuses = statuses.where(is_closed: false) if blocked?
statuses.order_by_position
+9 -9
View File
@@ -30,7 +30,7 @@ module BasicData
class WorkflowSeeder < Seeder
def seed_data!
colors = Color.all
colors = colors.map { |c| { c.name => c.id } }.reduce({}, :merge)
colors = colors.map { |c| { c.name => c.id } }.reduce({}, :merge)
if WorkPackage.where(type_id: nil).any? || Journal::WorkPackageJournal.where(type_id: nil).any?
# Fixes work packages that do not have a type yet. They receive the standard type.
@@ -76,18 +76,18 @@ module BasicData
status_seeder_class.new.seed!
# Workflow - Each type has its own workflow
workflows.each { |type_id, statuses_for_type|
statuses_for_type.each { |old_status|
statuses_for_type.each { |new_status|
[manager.id, member.id].each { |role_id|
workflows.each do |type_id, statuses_for_type|
statuses_for_type.each do |old_status|
statuses_for_type.each do |new_status|
[manager.id, member.id].each do |role_id|
Workflow.create type_id: type_id,
role_id: role_id,
old_status_id: old_status.id,
new_status_id: new_status.id
}
}
}
}
end
end
end
end
end
end
+1 -1
View File
@@ -116,7 +116,7 @@ module DemoData
Member.create!(
project: project,
user: user,
principal: user,
roles: [role]
)
end
+5 -1
View File
@@ -34,6 +34,10 @@ module DemoData
@url_helpers ||= OpenProject::StaticRouting::StaticRouter.new.url_helpers
end
def api_url_helpers
API::V3::Utilities::PathHelper::ApiV3Path
end
def with_references(str, project)
res = link_work_packages str, project
res = link_queries res, project
@@ -74,7 +78,7 @@ module DemoData
if match.include?(".id")
attachment.id
else
url_helpers.attachment_path id: attachment.id
api_url_helpers.attachment_content attachment.id
end
end
end
-1
View File
@@ -75,7 +75,6 @@ class BaseTypeService
errors: errors,
result: type)
rescue => e
binding.pry
ServiceResult.new(success: false).tap do |result|
result.errors.add(:base, e.message)
end
+3 -1
View File
@@ -58,7 +58,9 @@ module FileUploader
end
def readable?
file && File.readable?(local_file)
return false unless file && local_file
File.readable?(local_file)
end
# store! nil's the cache_id after it finishes so we need to remember it for deletion
+4 -1
View File
@@ -67,6 +67,9 @@ See docs/COPYRIGHT.rdoc for more details.
<%# Include CLI assets (development) or prod build assets %>
<%= include_frontend_assets %>
<%# Render CSS highlighting %>
<%= stylesheet_link_tag "/highlighting/styles/#{highlight_css_version_tag}", skip_pipeline: true %>
<%= javascript_include_tag 'application' %>
<%= javascript_include_tag "locales/#{I18n.locale}" %>
<!-- Text formatting specific includes -->
@@ -122,7 +125,7 @@ See docs/COPYRIGHT.rdoc for more details.
</a>
<%= render_top_menu_left %>
<div id="logo" class="hidden-for-mobile">
<%= link_to(I18n.t('label_home'), home_url, class: 'home-link') %>
<%= link_to(I18n.t('label_home'), fixed_home_url, class: 'home-link') %>
</div>
<%= call_hook :view_layouts_base_top_menu %>
<div class="top-menu-items-right">
+39 -27
View File
@@ -27,7 +27,7 @@
"check_name": "RegexDoS",
"message": "Model attribute used in regular expression",
"file": "app/models/mail_handler.rb",
"line": 309,
"line": 307,
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
"code": "/^(#{\"#{attr.to_s.humanize}|#{all_attribute_translations(user.language)[attr]}|#{all_attribute_translations(Setting.default_language)[attr]}\"})[ \\t]*:[ \\t]*(#{\".+\"})\\s*$/i",
"render_path": null,
@@ -130,7 +130,19 @@
"line": 32,
"link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/",
"code": "render(partial => Redmine::Plugin.find(params[:id]).settings[:partial], { :locals => ({ :settings => Setting[\"plugin_#{Redmine::Plugin.find(params[:id]).id}\"] }) })",
"render_path": [{"type":"controller","class":"SettingsController","method":"plugin","line":71,"file":"app/controllers/settings_controller.rb","rendered":{"name":"settings/plugin","file":"/home/oliver/openproject/dev/app/views/settings/plugin.html.erb"}}],
"render_path": [
{
"type": "controller",
"class": "SettingsController",
"method": "plugin",
"line": 71,
"file": "app/controllers/settings_controller.rb",
"rendered": {
"name": "settings/plugin",
"file": "app/views/settings/plugin.html.erb"
}
}
],
"location": {
"type": "template",
"template": "settings/plugin"
@@ -159,6 +171,26 @@
"confidence": "Weak",
"note": "version_projection is static"
},
{
"warning_type": "SQL Injection",
"warning_code": 0,
"fingerprint": "9482cd863a566bce3c2fb623ba0fcb66c6850f2a2b1b9d3e0c25875a99376d1a",
"check_name": "SQL",
"message": "Possible SQL injection",
"file": "app/models/application_record.rb",
"line": 25,
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
"code": "ActiveRecord::Base.connection.select_all(\" SELECT MAX(union_query.max_updated_at)\\n FROM (#{record_classes.map do\n column_name = (clz.timestamp_attributes_for_update_in_model.first or \"updated_at\")\n\"(SELECT MAX(#{(clz.timestamp_attributes_for_update_in_model.first or \"updated_at\")}) AS max_updated_at FROM #{clz.table_name})\"\n end.join(\" UNION \")})\\n AS union_query\\n\")",
"render_path": null,
"location": {
"type": "method",
"class": "ApplicationRecord",
"method": "ApplicationRecord.most_recently_changed"
},
"user_input": "record_classes.map do\n column_name = (clz.timestamp_attributes_for_update_in_model.first or \"updated_at\")\n\"(SELECT MAX(#{(clz.timestamp_attributes_for_update_in_model.first or \"updated_at\")}) AS max_updated_at FROM #{clz.table_name})\"\n end.join(\" UNION \")",
"confidence": "Medium",
"note": "Fixed internal references to columns and tables"
},
{
"warning_type": "SQL Injection",
"warning_code": 0,
@@ -166,7 +198,7 @@
"check_name": "SQL",
"message": "Possible SQL injection",
"file": "app/models/journal/aggregated_journal.rb",
"line": 411,
"line": 383,
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
"code": "self.class.query_aggregated_journals(:journable => journable).where(\"#{self.class.version_projection} > ?\", version)",
"render_path": null,
@@ -206,7 +238,7 @@
"check_name": "SQL",
"message": "Possible SQL injection",
"file": "app/models/work_package.rb",
"line": 520,
"line": 529,
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
"code": "ActiveRecord::Base.connection.select_all(\"select s.id as status_id,\\n s.is_closed as closed,\\n i.project_id as project_id,\\n count(i.id) as total\\n from\\n #{WorkPackage.table_name} i, #{Status.table_name} s\\n where\\n i.status_id=s.id\\n and i.project_id IN (#{project.descendants.active.map(&:id).join(\",\")})\\n group by s.id, s.is_closed, i.project_id\")",
"render_path": null,
@@ -259,26 +291,6 @@
"confidence": "Medium",
"note": "Never called with user input"
},
{
"warning_type": "Redirect",
"warning_code": 18,
"fingerprint": "cae51bc9c805a05a1490141ea53bb88e0a97d626336975aec5f0d36ade8493d5",
"check_name": "Redirect",
"message": "Possible unprotected redirect",
"file": "app/controllers/attachments_controller.rb",
"line": 39,
"link": "https://brakemanscanner.org/docs/warning_types/redirect/",
"code": "redirect_to(Attachment.find(params[:id]).external_url.to_s)",
"render_path": null,
"location": {
"type": "method",
"class": "AttachmentsController",
"method": "download"
},
"user_input": "Attachment.find(params[:id]).external_url.to_s",
"confidence": "High",
"note": "external_url does not take in user input. Only user-provided ID is used to find attachment"
},
{
"warning_type": "SQL Injection",
"warning_code": 0,
@@ -286,7 +298,7 @@
"check_name": "SQL",
"message": "Possible SQL injection",
"file": "app/models/work_package.rb",
"line": 616,
"line": 625,
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
"code": "where(\"id IN (SELECT common_id FROM (#{[Relation.hierarchy.where(:from_id => Relation.where(:to => work_packages).hierarchy_or_follows.select(:from_id)).select(\"to_id common_id\"), Relation.where(:to => work_packages).hierarchy_or_follows.select(\"from_id common_id\")].map(&:to_sql).join(\" UNION \")}) following_relations)\")",
"render_path": null,
@@ -340,6 +352,6 @@
"note": "Static SQL built from `project_condition`"
}
],
"updated": "2019-04-30 09:36:52 +0200",
"brakeman_version": "4.5.0"
"updated": "2019-06-28 07:49:05 +0200",
"brakeman_version": "4.5.1"
}
+1 -1
View File
@@ -30,4 +30,4 @@ if defined?(LivingStyleGuide)
LivingStyleGuide.default_options[:scss_template] = OpenProject::LivingStyleGuide::Template
end
Rails.application.config.sass.load_paths << Rails.root.join('frontend', 'node_modules', 'foundation-apps', 'scss')
Rails.application.config.sass.load_paths << Rails.root.join('app', 'assets', 'stylesheets', 'vendor', 'foundation-apps', 'scss')
File diff suppressed because it is too large Load Diff
+2158 -2515
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2054 -2442
View File
File diff suppressed because it is too large Load Diff
+2078 -2526
View File
File diff suppressed because it is too large Load Diff
+2103 -2495
View File
File diff suppressed because it is too large Load Diff
+2061 -2445
View File
File diff suppressed because it is too large Load Diff
+2082 -2571
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2077 -2564
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2050 -2421
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2076 -2574
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2089 -2491
View File
File diff suppressed because it is too large Load Diff
+2055 -2464
View File
File diff suppressed because it is too large Load Diff
+2044 -2449
View File
File diff suppressed because it is too large Load Diff
+2065 -2554
View File
File diff suppressed because it is too large Load Diff
+1978 -2102
View File
File diff suppressed because it is too large Load Diff
-920
View File
@@ -1,920 +0,0 @@
---
af:
js:
ajax:
hide: Versteek
loading: Loading ...
attachments:
draggable_hint: 'Drag on editor field to inline image or reference attachment.
Closed editor fields will be opened while you keep dragging.
'
autocomplete_select:
placeholder:
multi: Add "%{name}"
single: Select "%{name}"
remove: Remove %{name}
active: Active %{label} %{name}
close_popup_title: Close popup
close_filter_title: Close filter
close_form_title: Close form
card:
add_new: Add new card
highlighting:
inline: 'Highlight inline:'
entire_card_by: Entire card by
remove_from_list: Remove card from list
clipboard:
browser_error: Your browser doesn't support copying to clipboard. Please copy
the selected text manually.
copied_successful: Sucessfully copied to clipboard!
button_add_watcher: Voeg kyker by
button_back: Terug
button_back_to_list_view: Back to list view
button_cancel: Kanselleer
button_close: Close
button_check_all: Kontroleer almal
button_configure-form: Configure form
button_confirm: Confirm
button_continue: Continue
button_copy: Kopieer
button_custom-fields: Pasgemaakte velde
button_delete: Skrap
button_delete_watcher: Delete watcher
button_details_view: Details view
button_duplicate: Dupliseer
button_edit: Redigeer
button_filter: Filtreer
button_advanced_filter: Advanced filter
button_list_view: List view
button_show_view: Fullscreen view
button_log_time: Log tyd
button_more: Meer
button_move: Skuif
button_open_details: Open details view
button_close_details: Close details view
button_open_fullscreen: Maak volkermmodus oop
button_quote: Haal aan
button_save: Stoor
button_settings: Instellings
button_uncheck_all: Ontmerk almal
button_update: Opdateer
button_export-pdf: Download PDF
button_export-atom: Download Atom
calendar:
title: Kalender
too_many: There are more work packages (%{count}) than can be displayed by the
calendar (%{max}). Add filters to focus on the relevant ones.
description_available_columns: Kolomme beskikbaar
description_current_position: 'You are here: '
description_select_work_package: 'Kies werkspakket #%{id}'
description_selected_columns: Geselekteerde kolomme
description_subwork_package: 'Kind van werkspakket #%{id}'
editor:
preview: Toggle preview mode
source_code: Toggle Markdown source mode
error_saving_failed: 'Saving the document failed with the following error: %{error}'
error_initialization_failed: Failed to initialize CKEditor!
mode:
manual: Switch to Markdown source
wysiwyg: Switch to WYSIWYG editor
macro:
child_pages:
button: Links to child pages
include_parent: Include parent
text: "[Placeholder] Links to child pages of"
page: Wiki bladsy
this_page: this page
hint: 'Leave this field empty to list all child pages of the current page.
If you want to reference a different page, provide its title or slug.
'
code_block:
button: Insert code snippet
title: Insert / edit Code snippet
language: Formatting language
language_hint: Enter the formatting language that will be used for highlighting
(if supported).
dropdown:
macros: Macros
chose_macro: Chose macro
toc: Table of contents
toolbar_help: Click to select widget and show the toolbar. Double-click to
edit widget
wiki_page_include:
button: Include content of another wiki page
text: "[Placeholder] Included wiki page of"
page: Wiki bladsy
not_set: "(Page not yet set)"
hint: |
Include the content of another wiki page by specifying its title or slug.
You can include the wiki page of another project by separating them with a colon like the following example.
work_package_button:
button: Insert create work package button
type: Work package type
button_style: Use button style
button_style_hint: 'Optional: Check to make macro appear as a button, not
as a link.'
without_type: Create work package
with_type: 'Create work package (Type: %{typename})'
embedded_table:
button: Embed work package table
text: "[Placeholder] Embedded work package table"
embedded_calendar:
text: "[Placeholder] Embedded calendar"
custom_actions:
date:
specific: 'on'
current_date: Current date
error:
internal: An internal error has occurred.
cannot_save_changes_with_message: 'Cannot save your changes due to the following
error: %{error}'
query_saving: The view could not be saved.
embedded_table_loading: 'The embedded view could not be loaded: %{message}'
filter:
description:
text_open_filter: Open this filter with 'ALT' and arrow keys.
text_close_filter: To select an entry leave the focus for example by pressing
enter. To leave without filter select the first (empty) entry.
noneElement: "(none)"
time_zone_converted:
two_values: "%{from} - %{to} in your local time."
only_start: From %{from} in your local time.
only_end: Till %{to} in your local time.
value_spacer: "-"
sorting:
criteria:
one: First sorting criteria
two: Second sorting criteria
three: Third sorting criteria
upsale_for_more: For more advanced filters, check out the
upsale_link: Enterprise Edition.
general_text_no: nee
general_text_yes: ja
general_text_No: Nee
general_text_Yes: Ja
grid:
add_modal:
choose_widget: Choose widget
widgets:
documents:
title: Documents
no_results: No documents yet.
news:
title: Nuus
at: at
no_results: Nothing new to report.
time_entries_current_user:
title: Spent time (last 7 days)
no_results: No time entries for the last 7 days.
work_packages_accountable:
title: Work packages I am accountable for
work_packages_assigned:
title: Werkspakkette aan my toegeken
work_packages_created:
title: Work packages created by me
work_packages_watched:
title: Work packages watched by me
work_packages_table:
title: Werkspakkete
work_packages_calendar:
title: Kalender
homescreen:
blocks:
new_features:
text_new_features: Read about new features and product updates.
current_new_feature_html: 'OpenProject contains a new <b>Boards view</b>
for Agile project management. </br> To activate this new feature for your
existing projects, please do the following steps: <ul><li>Activate the
module Boards within existing projects'' settings.</li> <li>Configure
your Boards in a project.</li> <li>Verify roles and permissions</li></ul>'
image_alt_text: Board teaser image
learn_about: Learn more about Agile Boards
label_activate: Activate
label_activity_no: Activity entry number %{activityNo}
label_activity_with_comment_no: Activity entry number %{activityNo}. Has a user
comment.
label_add_column_after: Add column after
label_add_column_before: Add column before
label_add_columns: Add columns
label_add_comment: Add comment
label_add_comment_title: Comment and type @ to notify other people
label_add_row_after: Add row after
label_add_row_before: Add row before
label_add_selected_columns: Voeg geselekteerde kolomme by
label_added_by: added by
label_added_time_by: Added by %{author} %{age}
label_ago: dae gelede
label_all: alle
label_all_work_packages: all work packages
label_and: and
label_ascending: Stygende
label_author: 'Author: %{user}'
label_between: between
label_board: Board
label_board_locked: Gesluit
label_board_plural: Boards
label_board_sticky: Klewerig
label_create: Skep
label_create_work_package: Create new work package
label_created_by: Created by
label_date: Datum
label_date_with_format: 'Tik die %{date_attribute} in die volgende formaat: %{format}'
label_deactivate: Deactivate
label_descending: Dalende
label_description: Beskrywing
label_cancel_comment: Kanselleer aanmerking
label_closed_work_packages: gesluit
label_collapse: Vou in
label_collapsed: collapsed
label_collapse_all: Vou almal op
label_comment: Opmerking
label_committed_at: "%{committed_revision_link} at %{date}"
label_committed_link: committed revision %{revision_identifier}
label_contains: bevat
label_created_on: created on
label_edit_comment: Edit this comment
label_edit_status: Edit the status of the work package
label_equals: is
label_expand: Expand
label_expanded: expanded
label_expand_all: Vou almal uit
label_expand_project_menu: Expand project menu
label_export: Export
label_filename: Lêer
label_filesize: Grootte
label_greater_or_equal: ">="
label_group_by: Groepeer volgens
label_hide_attributes: Wys minder
label_hide_column: Hide column
label_hide_project_menu: Collapse project menu
label_in: in
label_in_less_than: in minder as
label_in_more_than: in meer as
label_latest_activity: Latest activity
label_last_updated_on: Last updated on
label_less_or_equal: "<="
label_less_than_ago: minder as dae gelede
label_loading: Laai tans...
label_me: ek
label_menu_collapse: collapse
label_menu_expand: expand
label_more_than_ago: meer as dae gelede
label_my_page: My bladsy
label_next: Volgende
label_no_color: No color
label_no_data: Geen data om te wys
label_no_due_date: no end date
label_no_start_date: no start date
label_none: geen
label_not_contains: bevat nie
label_not_equals: is nie
label_on: 'on'
label_open_menu: Maak kieslys oop
label_open_context_menu: Open context menu
label_open_work_packages: maak oop
label_password: Wagwoord
label_previous: Vorige
label_per_page: 'Per page:'
label_please_wait: Please wait
label_visibility_settings: Visibility settings
label_quote_comment: Quote this comment
label_reset: Herstel
label_remove_column: Remove column
label_remove_columns: Remove selected columns
label_remove_row: Remove row
label_save_as: Save as
label_select_watcher: Select a watcher...
label_selected_filter_list: Selected filters
label_show_attributes: Show all attributes
label_show_in_menu: Show view in menu
label_sort_by: Sort by
label_sorted_by: sorted by
label_sort_higher: Move up
label_sort_lower: Skuif af
label_sorting: Sorting
label_star_query: Favored
label_press_enter_to_save: Press enter to save.
label_public_query: Openbaar
label_sum_for: Sum for
label_subject: Onderwerp
label_this_week: vandeesweek
label_today: vandag
label_up: Up
label_activity_show_only_comments: Show activities with comments only
label_activity_show_all: Show all activities
label_total_progress: "%{percent}% Total progress"
label_total_amount: 'Total: %{amount}'
label_updated_on: updated on
label_warning: Warning
label_work_package: Werkspakket
label_work_package_plural: Werkspakkete
label_watch: Hou dop
label_watch_work_package: Watch work package
label_watcher_added_successfully: Watcher successfully added!
label_watcher_deleted_successfully: Watcher successfully deleted!
label_work_package_details_you_are_here: You're on the %{tab} tab for %{type}
%{subject}.
label_unwatch: Hou op dophou
label_unwatch_work_package: Unwatch work package
label_uploaded_by: Uploaded by
label_default_queries: Default views
label_starred_queries: Favorite views
label_global_queries: Public views
label_custom_queries: Private views
label_columns: Kolomme
label_attachments: Lêers
label_drop_files: Drop files here
label_drop_files_hint: or click to add files
label_drop_folders_hint: You cannot upload folders as an attachment. Please select
single files.
label_add_attachments: Add attachments
label_formattable_attachment_hint: Attach and link files by dropping on this field,
or pasting from the clipboard.
label_remove_file: Delete %{fileName}
label_remove_watcher: Remove watcher %{name}
label_remove_all_files: Delete all files
label_add_description: Add a description for %{file}
label_upload_notification: Uploading files...
label_work_package_upload_notification: 'Uploading files for Work package #%{id}:
%{subject}'
label_wp_id_added_by: "#%{id} added by %{author}"
label_files_to_upload: 'These files will be uploaded:'
label_rejected_files: 'These files cannot be uploaded:'
label_rejected_files_reason: These files cannot be uploaded as their size is greater
than %{maximumFilesize}
label_wait: Please wait for configuration...
label_upload_counter: "%{done} of %{count} files finished"
label_validation_error: 'The work package could not be saved due to the following
errors:'
help_texts:
show_modal: Show attribute help text entry
onboarding:
buttons:
skip: Skip
next: Volgende
got_it: Got it
steps:
help_menu: In the <b>Help</b> menu you will find a user guide and additional
help resources. <br> Enjoy your work with OpenProject!
members: Invite new <b>Members</b> to join your project.
project_selection: Please click on one of the projects with useful demo data
to get started. <br> The <b>Demo project</b> suits best for classical project
management, while the <b>Scrum project</b> is better for Agile project management.
sidebar_arrow: With the arrow you can navigate back to the project's <b>Main
menu</b>.
welcome: Take a three minutes introduction tour to learn the most <b>important
features</b>. <br> We recommend completing the steps until the end. You
can restart the tour any time.
wiki: Within the <b>Wiki</b> you can document and share knowledge together
with your team.
backlogs:
overview: Manage your work in the <b>Backlogs</b> view. <br> On the right
you have the Product Backlog or a Bug Backlog, on the left you will have
the respective sprints. Here you can create <b>epics, user stories, and
bugs</b>, prioritize via drag'n'drop and add them to a sprint.
task_board_arrow: To see your <b>Task board</b>, open the Sprint drop-down...
task_board_select: "... and select the <b>Task board</b> entry."
task_board: The <b>Task board</b> visualizes the progress for this sprint.
Add new tasks or impediments with the + icon next to a user story. Via
drag'n'drop you can update the status.
boards:
overview: Manage your work within an intuitive <b>Boards</b> view.
lists: You can create multiple lists (columns) within one Board view, e.g.
to create a KANBAN board.
add: Click the + will <b>add a new card</b> to the list within a Board.
drag: Drag & Drop your cards within a list to re-order, or to another list.
A double click will open the details view.
wp:
toggler: Now let's have a look at the <b>Work package</b> section, which
gives you a more detailed view of your work.
list: This is the <b>Work package</b> list with the important work within
your project, such as tasks, features, milestones, bugs, and more. <br>
You can create or edit a work package directly within this list. To see
its details you can double click on a row.
full_view: Within the <b>Work package details</b> you find all relevant
information, such as description, status and priority, activities, dependencies
or comments.
back_button: With the arrow you can navigate back to the work package list.
create_button: The <b>Create</b> button will add a new work package to your
project.
timeline_button: You can activate the <b>Gantt chart</b> to create a timeline
for your project.
timeline: Here you can edit your project plan. Create new phases, milestones,
and add dependencies. All team members can see and update the latest plan
at any time.
password_confirmation:
field_description: You need to enter your account password to confirm this change.
title: Confirm your password to continue
pagination:
no_other_page: You are on the only page.
pages:
next: Forward to the next page
previous: Back to the previous page
placeholders:
default: "-"
subject: Enter subject here
selection: Kies asseblief
relation_description: Click to add description for this relation
project:
required_outside_context: 'Please choose a project to create the work package
in to see all attributes. You can only select projects which have the type
above activated.
'
context: Project context
work_package_belongs_to: This work package belongs to project %{projectname}.
click_to_switch_context: Open this work package in that project.
autocompleter:
label: Project autocompletion
text_are_you_sure: Are you sure?
types:
attribute_groups:
error_duplicate_group_name: The name %{group} is used more than once. Group
names must be unique.
error_no_table_configured: Please configure a table for %{group}.
reset_title: Reset form configuration
confirm_reset: 'Warning: Are you sure you want to reset the form configuration?
This will reset the attributes to their default group and disable ALL custom
fields.
'
upgrade_to_ee: Upgrade to Enterprise Edition
upgrade_to_ee_text: Wow! If you need this feature you are a super pro! Would
you mind supporting us OpenSource developers by becoming an Enterprise Edition
client?
more_information: More information
nevermind: Nevermind
filter_types:
parent: being child of
precedes: preceding
follows: following
relates: relating to
duplicates: duplicating
duplicated: gedupliseer deur
blocks: blocking
blocked: geblokkeer deur
partof: being part of
includes: including
requires: requiring
required: required by
time_entry:
activity: Aktiwiteit
comment: Opmerking
hours: Ure
watchers:
label_loading: loading watchers...
label_error_loading: An error occurred while loading the watchers
label_search_watchers: Search watchers
label_add: Voeg dophouers by
label_discard: Discard selection
typeahead_placeholder: Search for possible watchers
relation_labels:
parent: Ouer
children: Children
relates: Related To
duplicates: Duplicates
duplicated: Duplicated by
blocks: Blocks
blocked: Blocked by
precedes: Precedes
follows: Follows
includes: Includes
partof: Part of
requires: Requires
required: Required by
relation_type: relation type
relations_hierarchy:
parent_headline: Ouer
hierarchy_headline: Hierarchy
children_headline: Children
relation_buttons:
set_parent: Set parent
change_parent: Change parent
remove_parent: Remove parent
group_by_wp_type: Group by work package type
group_by_relation_type: Group by relation type
add_parent: Add existing parent
add_new_child: Create new child
create_new: Create new
add_existing: Add existing
add_existing_child: Add existing child
remove_child: Remove child
add_new_relation: Create new relation
add_existing_relation: Add existing relation
update_description: Set or update description of this relation
toggle_description: Toggle relation description
update_relation: Klik om die verhoudingtipe te verander
add_follower: Add follower
add_predecessor: Add predecessor
remove: Remove relation
save: Save relation
abort: Abort
relations_autocomplete:
placeholder: Type to search
parent_placeholder: Choose new parent or press escape to cancel.
repositories:
select_tag: Select tag
select_branch: Select branch
field_value_enter_prompt: Enter a value for '%{field}'
select2:
input_too_short:
one: Please enter one more character
other: Please enter {{count}} more characters
zero: Please enter more characters
load_more: Loading more results ...
no_matches: No matches found
searching: Searching ...
selection_too_big:
one: You can only select one item
other: You can only select {{limit}} items
zero: You cannot select any items
project_menu_details: Besonderhede
sort:
sorted_asc: 'Ascending sort applied, '
sorted_dsc: 'Descending sort applied, '
sorted_no: 'No sort applied, '
sorting_disabled: sorting is disabled
activate_asc: activate to apply an ascending sort
activate_dsc: activate to apply a descending sort
activate_no: activate to remove the sort
text_work_packages_destroy_confirmation: Are you sure you want to delete the selected
work package(s)?
text_query_destroy_confirmation: Are you sure you want to delete the selected
view?
text_attachment_destroy_confirmation: Are you sure you want to delete the attachment?
timelines:
quarter_label: Q%{quarter_number}
gantt_chart: Gantt chart
labels:
title: Label configuration
bar: Bar labels
left: Left
right: Right
farRight: Far right
showNone: "-- No label --"
description: 'Select the attributes you want to be shown in the respective
positions of the Gantt chart at all times. Note that when hovering an element,
its date labels will be shown instead of these attributes.
'
button_activate: Show Gantt chart
button_deactivate: Hide Gantt chart
cancel: Kanselleer
change: Change in planning
due_date: Finish date
empty: "(empty)"
error: An error has occurred.
errors:
not_implemented: The timeline could not be rendered because it uses a feature
that is not yet implemented.
report_comparison: The timeline could not render the configured comparisons.
Please check the appropriate section in the configuration, resetting it
can help solve this problem.
report_epicfail: The timeline could not be loaded due to an unexpected error.
report_timeout: The timeline could not be loaded in a reasonable amount of
time.
filter:
grouping_other: Ander
noneSelection: "(none)"
name: Naam
outline: Reset Outline
outlines:
aggregation: Show aggregations only
level1: Expand level 1
level2: Expand level 2
level3: Expand level 3
level4: Expand level 4
level5: Expand level 5
all: Show all
project_status: Projek status
really_close_dialog: Do you really want to close the dialog and lose the entered
data?
responsible: Verantwoordelik
save: Stoor
start_date: Begindatum
tooManyProjects: More than %{count} Projects. Please use a better filter!
selection_mode:
notification: Click on any highlighted work package to create the relation.
Press escape to cancel.
zoom:
in: Zoom in
out: Zoom out
auto: Auto zoom
days: Days
weeks: Weeks
months: Months
quarters: Quarters
years: Years
slider: Zoom slider
description: 'Select the initial zoom level that should be shown when autozoom
is not available.
'
tl_toolbar:
zooms: Zoom level
outlines: Hierarchy level
upsale:
ee_only: Enterprise Edition only feature
wiki_formatting:
strong: Strong
italic: Italic
underline: Underline
deleted: Deleted
code: Inline Code
heading1: Heading 1
heading2: Heading 2
heading3: Heading 3
unordered_list: Unordered List
ordered_list: Ordered List
quote: Haal aan
unquote: Unquote
preformatted_text: Preformatted Text
wiki_link: Link to a Wiki page
image: Image
work_packages:
bulk_actions:
move: Bulk move
edit: Bulk edit
copy: Bulk copy
delete: Bulk delete
button_clear: Verwyder
comment_added: The comment was successfully added.
comment_send_failed: An error has occurred. Could not submit the comment.
comment_updated: The comment was successfully updated.
confirm_edit_cancel: Are you sure you want to cancel editing the work package?
description_filter: Filtreer
description_enter_text: Tik teks
description_options_hide: Hide options
description_options_show: Show options
error:
update_conflict_refresh: Click here to refresh the work package and update
to the newest version.
edit_prohibited: Redigering van %{attribute} is geblokkeer vir hierdie werkspakket.
Hierdie eienskap is of afgelei van verhoudings (bv., kinders) of andersins
nie veranderbaar nie.
format:
date: "%{attribute} is no valid date - YYYY-MM-DD expected."
general: An error has occurred.
edit_attribute: "%{attribute} - Edit"
key_value: "%{key}: %{value}"
label_enable_multi_select: Enable multiselect
label_disable_multi_select: Disable multiselect
label_filter_add: Voeg filter by
label_filter_by_text: Filter by text
label_options: Opsies
label_column_multiselect: 'Combined dropdown field: Select with arrow keys,
confirm selection with enter, delete with backspace'
message_error_during_bulk_delete: An error occurred while trying to delete work
packages.
message_successful_bulk_delete: Successfully deleted work packages.
message_successful_show_in_fullscreen: Klik hier om hierdie werkspakket in volskermmodus
oop te maak.
message_view_spent_time: Show spent time for this work package
message_work_package_read_only: Work package is locked in this status. No attribute
other than status can be altered.
no_value: No value
placeholder_filter_by_text: Subject, description, comments, ...
inline_create:
title: Klik hier om 'n nuwe werkspakket by hierdie lys te voeg
create:
title: Nuwe werkspakket
header: New %{type}
header_no_type: New work package (Type not yet set)
header_with_parent: 'New %{type} (Child of %{parent_type} #%{id})'
button: Skep
copy:
title: Copy work package
hierarchy:
show: Show hierarchy mode
hide: Hide hierarchy mode
toggle_button: Click to toggle hierarchy mode.
leaf: Work package leaf at level %{level}.
children_collapsed: Hierarchy level %{level}, collapsed. Click to show the
filtered children
children_expanded: Hierarchy level %{level}, expanded. Click to collapse the
filtered children
faulty_query:
title: Work packages could not be loaded.
description: Your view is erroneous and could not be processed.
no_results:
title: Geen werkspakkette om te wys.
description: Geen geskep óf alle werkspakkette is uitgefiltreer.
property_groups:
details: Besonderhede
people: People
estimatesAndTime: Estimates & Time
other: Ander
properties:
assignee: Gedelegeerde
author: Outeur
createdAt: Geskep op
description: Beskrywing
date: Datum
dueDate: Finish date
estimatedTime: Geraamde tyd
spentTime: Tyd gespandeer
category: Kategorie
percentageDone: Percentage done
priority: Prioriteit
projectName: Projek
responsible: Verantwoordelik
startDate: Begindatum
status: Status
subject: Onderwerp
title: Titel
type: Soort
updatedAt: Opgedateer op
versionName: Weergawe
version: Weergawe
default_queries:
latest_activity: Latest activity
created_by_me: Created by me
assigned_to_me: Assigned to me
recently_created: Recently created
all_open: All open
summary: Opsomming
jump_marks:
pagination: Jump to table pagination
label_pagination: Click here to skip over the work packages table and go to
pagination
content: Jump to content
label_content: Click here to skip over the menu and go to the content
placeholders:
default: "-"
description: Click to enter description...
query:
column_names: Kolomme
group_by: Groepeer resultate by
group: Groepeer volgens
group_by_disabled_by_hierarchy: Group by is disabled due to the hierarchy
mode being active.
hierarchy_disabled_by_group_by: Hierarchy mode is disabled due to results
being grouped by %{column}.
sort_ascending: Sort ascending
sort_descending: Sort descending
move_column_left: Move column left
move_column_right: Move column right
hide_column: Hide column
insert_columns: Insert columns ...
filters: Filtreerders
display_sums: Vertoon totale
confirm_edit_cancel: Are you sure you want to cancel editing the name of this
view? Title will be set back to previous value.
click_to_edit_query_name: Click to edit title of this view.
rename_query_placeholder: Name of this view
errors:
unretrievable_query: Unable to retrieve view from URL
not_found: There is no such view
duplicate_query_title: Name of this view already exists. Change anyway?
text_no_results: No matching views were found.
table:
configure_button: Configure work package table
summary: Table with rows of work package and columns of work package attributes.
text_inline_edit: Most cells of this table are buttons that activate inline-editing
functionality of that attribute.
text_sort_hint: With the links in the table headers you can sort, group, reorder,
remove and add table columns.
text_select_hint: Select boxes should be opened with 'ALT' and arrow keys.
table_configuration:
button: Configure this work package table
choose_display_mode: Display work packages as
modal_title: Work package table configuration
embedded_tab_disabled: This configuration tab is not available for the embedded
view you're editing.
default: default
display_settings: Display settings
default_mode: Flat list
hierarchy_mode: Hierarchy
hierarchy_hint: All filtered table results will be augmented with their ancestors.
Hierarchies can be expanded and collapsed.
display_sums_hint: Display sums of all summable attributes in a row below
the table results.
show_timeline_hint: Show an interactive gantt chart on the right side of the
table. You can change its width by dragging the divider between table and
gantt chart.
highlighting: Highlighting
highlighting_mode:
description: Highlight with color
none: No highlighting
inline: Highlighted attribute(s)
inline_all: All attributes
entire_row_by: Entire row by
status: Status
priority: Prioriteit
type: Soort
columns_help_text: Use the input above to add or remove columns to your table
view. You can drag and drop the columns to reorder them.
upsale:
attribute_highlighting: Need certain work packages to stand out from the
mass?
relation_columns: Need to see relations in the work package list?
check_out_link: Check out the Enterprise Edition.
relation_filters:
first_part: Show all work packages
second_part: the current work package
tabs:
overview: Oorsig
activity: Aktiwiteit
relations: Relations
watchers: Dophouers
attachments: Aanhegsels
time_relative:
days: dae
weeks: weeks
months: months
toolbar:
settings:
configure_view: Configure view ...
columns: Columns ...
sort_by: Sort by ...
group_by: Group by ...
display_sums: Display sums
display_hierarchy: Display hierarchy
hide_hierarchy: Hide hierarchy
hide_sums: Hide sums
save: Stoor
save_as: Save as ...
export: Export ...
visibility_settings: Visibility settings ...
page_settings: Rename view ...
delete: Skrap
filter: Filtreer
unselected_title: Werkspakket
search_query_label: Search saved views
search_query_title: Click to search saved views
placeholder_query_title: Set a title for this view
modals:
label_settings: Rename view
label_name: Naam
label_delete_page: Delete current page
button_apply: Pas toe
button_save: Stoor
button_submit: Dien in
button_cancel: Kanselleer
form_submit:
title: Confirm to continue
text: Are you sure you want to perform this action?
destroy_work_package:
title: Confirm deletion of %{label}
text: Are you sure you want to delete the following %{label} ?
has_children: 'The work package has %{childUnits}:'
confirm_deletion_children: I acknowledge that ALL descendants of the listed
work packages will be recursively removed.
deletes_children: All child work packages and their descendants will also
be recursively deleted.
notice_no_results_to_display: No visible results to display.
notice_successful_create: Successful creation.
notice_successful_delete: Successful deletion.
notice_successful_update: Successful update.
notice_bad_request: Bad Request.
relations:
empty: No relation exists
remove: Remove relation
inplace:
button_edit: "%{attribute}: Edit"
button_save: "%{attribute}: Save"
button_cancel: "%{attribute}: Cancel"
button_save_all: Stoor
button_cancel_all: Kanselleer
link_formatting_help: Text formatting help
btn_preview_enable: Voorskou
btn_preview_disable: Disable preview
null_value_label: No value
clear_value_label: "-"
errors:
required: "%{field} cannot be empty"
number: "%{field} is not a valid number"
maxlength: "%{field} kan nie meer as %{maxLength} syfer(s) bevat nie"
minlength: "%{field} kan nie minder as %{minLength} syfer(s) bevat nie"
messages_on_field: 'This field is invalid: %{messages}'
error_could_not_resolve_version_name: Couldn't resolve version name
error_could_not_resolve_user_name: Couldn't resolve user name
error_attachment_upload: 'File failed to upload: %{error}'
error_attachment_upload_permission: You don't have the permission to upload files
on this resource.
units:
workPackage:
one: work package
other: work packages
child_work_packages:
one: one child work package
other: "%{count} work package children"
hour:
one: 1 hour
other: "%{count} hours"
zero: 0 hours
zen_mode:
button_activate: Activate zen mode
button_deactivate: Deactivate zen mode
global_search:
all_projects: In all projects
search: Search
close_search: Close search
current_project: In this project
current_project_and_all_descendants: In this project + subprojects
title:
all_projects: all projects
project_and_subprojects: and all subprojects
search_for: Search for
File diff suppressed because it is too large Load Diff
-922
View File
@@ -1,922 +0,0 @@
---
az:
js:
ajax:
hide: Hide
loading: Yüklənir ...
attachments:
draggable_hint: 'Drag on editor field to inline image or reference attachment.
Closed editor fields will be opened while you keep dragging.
'
autocomplete_select:
placeholder:
multi: Add "%{name}"
single: Select "%{name}"
remove: Remove %{name}
active: Active %{label} %{name}
close_popup_title: Açılan pəncərəni bağla
close_filter_title: Close filter
close_form_title: Close form
card:
add_new: Add new card
highlighting:
inline: 'Highlight inline:'
entire_card_by: Entire card by
remove_from_list: Remove card from list
clipboard:
browser_error: Your browser doesn't support copying to clipboard. Please copy
the selected text manually.
copied_successful: Sucessfully copied to clipboard!
button_add_watcher: Add watcher
button_back: Back
button_back_to_list_view: Back to list view
button_cancel: Cancel
button_close: Close
button_check_all: Check all
button_configure-form: Configure form
button_confirm: Confirm
button_continue: Continue
button_copy: Copy
button_custom-fields: Custom fields
button_delete: Delete
button_delete_watcher: İzləyicini sil
button_details_view: Təfsilat baxışı
button_duplicate: Duplicate
button_edit: Edit
button_filter: Filter
button_advanced_filter: Advanced filter
button_list_view: Siyahı baxışı
button_show_view: Fullscreen view
button_log_time: Log time
button_more: More
button_move: Move
button_open_details: Təfsilat baxışını
button_close_details: Close details view
button_open_fullscreen: Open fullscreen view
button_quote: Quote
button_save: Save
button_settings: Settings
button_uncheck_all: Uncheck all
button_update: Update
button_export-pdf: Download PDF
button_export-atom: Download Atom
calendar:
title: Calendar
too_many: There are more work packages (%{count}) than can be displayed by the
calendar (%{max}). Add filters to focus on the relevant ones.
description_available_columns: Available Columns
description_current_position: 'You are here: '
description_select_work_package: 'Select work package #%{id}'
description_selected_columns: Selected Columns
description_subwork_package: 'Child of work package #%{id}'
editor:
preview: Toggle preview mode
source_code: Toggle Markdown source mode
error_saving_failed: 'Saving the document failed with the following error: %{error}'
error_initialization_failed: Failed to initialize CKEditor!
mode:
manual: Switch to Markdown source
wysiwyg: Switch to WYSIWYG editor
macro:
child_pages:
button: Links to child pages
include_parent: Include parent
text: "[Placeholder] Links to child pages of"
page: Wiki page
this_page: this page
hint: 'Leave this field empty to list all child pages of the current page.
If you want to reference a different page, provide its title or slug.
'
code_block:
button: Insert code snippet
title: Insert / edit Code snippet
language: Formatting language
language_hint: Enter the formatting language that will be used for highlighting
(if supported).
dropdown:
macros: Macros
chose_macro: Chose macro
toc: Table of contents
toolbar_help: Click to select widget and show the toolbar. Double-click to
edit widget
wiki_page_include:
button: Include content of another wiki page
text: "[Placeholder] Included wiki page of"
page: Wiki page
not_set: "(Page not yet set)"
hint: |
Include the content of another wiki page by specifying its title or slug.
You can include the wiki page of another project by separating them with a colon like the following example.
work_package_button:
button: Insert create work package button
type: Work package type
button_style: Use button style
button_style_hint: 'Optional: Check to make macro appear as a button, not
as a link.'
without_type: Create work package
with_type: 'Create work package (Type: %{typename})'
embedded_table:
button: Embed work package table
text: "[Placeholder] Embedded work package table"
embedded_calendar:
text: "[Placeholder] Embedded calendar"
custom_actions:
date:
specific: 'on'
current_date: Current date
error:
internal: An internal error has occurred.
cannot_save_changes_with_message: 'Cannot save your changes due to the following
error: %{error}'
query_saving: The view could not be saved.
embedded_table_loading: 'The embedded view could not be loaded: %{message}'
filter:
description:
text_open_filter: Open this filter with 'ALT' and arrow keys.
text_close_filter: To select an entry leave the focus for example by pressing
enter. To leave without filter select the first (empty) entry.
noneElement: "(none)"
time_zone_converted:
two_values: "%{from} - %{to} in your local time."
only_start: From %{from} in your local time.
only_end: Till %{to} in your local time.
value_spacer: "-"
sorting:
criteria:
one: First sorting criteria
two: Second sorting criteria
three: Third sorting criteria
upsale_for_more: For more advanced filters, check out the
upsale_link: Enterprise Edition.
general_text_no: 'no'
general_text_yes: 'yes'
general_text_No: 'No'
general_text_Yes: 'Yes'
grid:
add_modal:
choose_widget: Choose widget
widgets:
documents:
title: Documents
no_results: No documents yet.
news:
title: News
at: at
no_results: Nothing new to report.
time_entries_current_user:
title: Spent time (last 7 days)
no_results: No time entries for the last 7 days.
work_packages_accountable:
title: Work packages I am accountable for
work_packages_assigned:
title: Work packages assigned to me
work_packages_created:
title: Work packages created by me
work_packages_watched:
title: Work packages watched by me
work_packages_table:
title: Work packages
work_packages_calendar:
title: Calendar
homescreen:
blocks:
new_features:
text_new_features: Read about new features and product updates.
current_new_feature_html: 'OpenProject contains a new <b>Boards view</b>
for Agile project management. </br> To activate this new feature for your
existing projects, please do the following steps: <ul><li>Activate the
module Boards within existing projects'' settings.</li> <li>Configure
your Boards in a project.</li> <li>Verify roles and permissions</li></ul>'
image_alt_text: Board teaser image
learn_about: Learn more about Agile Boards
label_activate: Activate
label_activity_no: Activity entry number %{activityNo}
label_activity_with_comment_no: Activity entry number %{activityNo}. Has a user
comment.
label_add_column_after: Add column after
label_add_column_before: Add column before
label_add_columns: Add columns
label_add_comment: Rəy bildir
label_add_comment_title: Comment and type @ to notify other people
label_add_row_after: Add row after
label_add_row_before: Add row before
label_add_selected_columns: Add selected columns
label_added_by: əlavə edən
label_added_time_by: "%{author} %{age} tərəfindən əlavə edildi"
label_ago: days ago
label_all: all
label_all_work_packages: bütün iş paketləri
label_and: and
label_ascending: Ascending
label_author: 'Author: %{user}'
label_between: between
label_board: Board
label_board_locked: Locked
label_board_plural: Boards
label_board_sticky: Sticky
label_create: Create
label_create_work_package: Create new work package
label_created_by: Created by
label_date: Date
label_date_with_format: 'Enter the %{date_attribute} using the following format:
%{format}'
label_deactivate: Söndür
label_descending: Descending
label_description: Description
label_cancel_comment: Cancel comment
label_closed_work_packages: closed
label_collapse: Collapse
label_collapsed: collapsed
label_collapse_all: Collapse all
label_comment: Comment
label_committed_at: "%{committed_revision_link} at %{date}"
label_committed_link: committed revision %{revision_identifier}
label_contains: contains
label_created_on: created on
label_edit_comment: Edit this comment
label_edit_status: Edit the status of the work package
label_equals: is
label_expand: Genişləndir
label_expanded: genişləndirilmiş
label_expand_all: Expand all
label_expand_project_menu: Expand project menu
label_export: İxrac et
label_filename: File
label_filesize: Size
label_greater_or_equal: ">="
label_group_by: Group by
label_hide_attributes: Show less
label_hide_column: Sütunu gizlət
label_hide_project_menu: Collapse project menu
label_in: in
label_in_less_than: in less than
label_in_more_than: in more than
label_latest_activity: Latest activity
label_last_updated_on: Son yenilənmə
label_less_or_equal: "<="
label_less_than_ago: less than days ago
label_loading: Loading...
label_me: me
label_menu_collapse: collapse
label_menu_expand: genişləndir
label_more_than_ago: more than days ago
label_my_page: My page
label_next: Next
label_no_color: No color
label_no_data: No data to display
label_no_due_date: bitmə tarixi yoxdur
label_no_start_date: başlama tarixi yoxdur
label_none: none
label_not_contains: doesn't contain
label_not_equals: is not
label_on: 'on'
label_open_menu: Open menu
label_open_context_menu: Open context menu
label_open_work_packages: open
label_password: Password
label_previous: Previous
label_per_page: 'Səhifə başına:'
label_please_wait: Please wait
label_visibility_settings: Visibility settings
label_quote_comment: Quote this comment
label_reset: Reset
label_remove_column: Remove column
label_remove_columns: Remove selected columns
label_remove_row: Remove row
label_save_as: Fərqli saxla
label_select_watcher: İzləyici seç...
label_selected_filter_list: Seçilmiş filtrlər
label_show_attributes: Show all attributes
label_show_in_menu: Show view in menu
label_sort_by: Sort by
label_sorted_by: sıralama
label_sort_higher: Move up
label_sort_lower: Move down
label_sorting: Sıralama
label_star_query: Favored
label_press_enter_to_save: Press enter to save.
label_public_query: Public
label_sum_for: Sum for
label_subject: Subject
label_this_week: this week
label_today: today
label_up: Up
label_activity_show_only_comments: Show activities with comments only
label_activity_show_all: Show all activities
label_total_progress: "%{percent}% Total progress"
label_total_amount: 'Total: %{amount}'
label_updated_on: updated on
label_warning: Warning
label_work_package: Work package
label_work_package_plural: Work packages
label_watch: Watch
label_watch_work_package: Watch work package
label_watcher_added_successfully: Watcher successfully added!
label_watcher_deleted_successfully: Watcher successfully deleted!
label_work_package_details_you_are_here: You're on the %{tab} tab for %{type}
%{subject}.
label_unwatch: Unwatch
label_unwatch_work_package: Unwatch work package
label_uploaded_by: Uploaded by
label_default_queries: Default views
label_starred_queries: Favorite views
label_global_queries: Public views
label_custom_queries: Private views
label_columns: Columns
label_attachments: Files
label_drop_files: Drop files here
label_drop_files_hint: or click to add files
label_drop_folders_hint: You cannot upload folders as an attachment. Please select
single files.
label_add_attachments: Add attachments
label_formattable_attachment_hint: Attach and link files by dropping on this field,
or pasting from the clipboard.
label_remove_file: Delete %{fileName}
label_remove_watcher: Remove watcher %{name}
label_remove_all_files: Delete all files
label_add_description: Add a description for %{file}
label_upload_notification: Uploading files...
label_work_package_upload_notification: 'Uploading files for Work package #%{id}:
%{subject}'
label_wp_id_added_by: "#%{id} added by %{author}"
label_files_to_upload: 'These files will be uploaded:'
label_rejected_files: 'These files cannot be uploaded:'
label_rejected_files_reason: These files cannot be uploaded as their size is greater
than %{maximumFilesize}
label_wait: Please wait for configuration...
label_upload_counter: "%{done} of %{count} files finished"
label_validation_error: 'The work package could not be saved due to the following
errors:'
help_texts:
show_modal: Show attribute help text entry
onboarding:
buttons:
skip: Skip
next: Next
got_it: Got it
steps:
help_menu: In the <b>Help</b> menu you will find a user guide and additional
help resources. <br> Enjoy your work with OpenProject!
members: Invite new <b>Members</b> to join your project.
project_selection: Please click on one of the projects with useful demo data
to get started. <br> The <b>Demo project</b> suits best for classical project
management, while the <b>Scrum project</b> is better for Agile project management.
sidebar_arrow: With the arrow you can navigate back to the project's <b>Main
menu</b>.
welcome: Take a three minutes introduction tour to learn the most <b>important
features</b>. <br> We recommend completing the steps until the end. You
can restart the tour any time.
wiki: Within the <b>Wiki</b> you can document and share knowledge together
with your team.
backlogs:
overview: Manage your work in the <b>Backlogs</b> view. <br> On the right
you have the Product Backlog or a Bug Backlog, on the left you will have
the respective sprints. Here you can create <b>epics, user stories, and
bugs</b>, prioritize via drag'n'drop and add them to a sprint.
task_board_arrow: To see your <b>Task board</b>, open the Sprint drop-down...
task_board_select: "... and select the <b>Task board</b> entry."
task_board: The <b>Task board</b> visualizes the progress for this sprint.
Add new tasks or impediments with the + icon next to a user story. Via
drag'n'drop you can update the status.
boards:
overview: Manage your work within an intuitive <b>Boards</b> view.
lists: You can create multiple lists (columns) within one Board view, e.g.
to create a KANBAN board.
add: Click the + will <b>add a new card</b> to the list within a Board.
drag: Drag & Drop your cards within a list to re-order, or to another list.
A double click will open the details view.
wp:
toggler: Now let's have a look at the <b>Work package</b> section, which
gives you a more detailed view of your work.
list: This is the <b>Work package</b> list with the important work within
your project, such as tasks, features, milestones, bugs, and more. <br>
You can create or edit a work package directly within this list. To see
its details you can double click on a row.
full_view: Within the <b>Work package details</b> you find all relevant
information, such as description, status and priority, activities, dependencies
or comments.
back_button: With the arrow you can navigate back to the work package list.
create_button: The <b>Create</b> button will add a new work package to your
project.
timeline_button: You can activate the <b>Gantt chart</b> to create a timeline
for your project.
timeline: Here you can edit your project plan. Create new phases, milestones,
and add dependencies. All team members can see and update the latest plan
at any time.
password_confirmation:
field_description: You need to enter your account password to confirm this change.
title: Confirm your password to continue
pagination:
no_other_page: You are on the only page.
pages:
next: Forward to the next page
previous: Back to the previous page
placeholders:
default: "-"
subject: Enter subject here
selection: Please select
relation_description: Click to add description for this relation
project:
required_outside_context: 'Please choose a project to create the work package
in to see all attributes. You can only select projects which have the type
above activated.
'
context: Project context
work_package_belongs_to: This work package belongs to project %{projectname}.
click_to_switch_context: Open this work package in that project.
autocompleter:
label: Project autocompletion
text_are_you_sure: Are you sure?
types:
attribute_groups:
error_duplicate_group_name: The name %{group} is used more than once. Group
names must be unique.
error_no_table_configured: Please configure a table for %{group}.
reset_title: Reset form configuration
confirm_reset: 'Warning: Are you sure you want to reset the form configuration?
This will reset the attributes to their default group and disable ALL custom
fields.
'
upgrade_to_ee: Upgrade to Enterprise Edition
upgrade_to_ee_text: Wow! If you need this feature you are a super pro! Would
you mind supporting us OpenSource developers by becoming an Enterprise Edition
client?
more_information: More information
nevermind: Nevermind
filter_types:
parent: being child of
precedes: preceding
follows: following
relates: relating to
duplicates: duplicating
duplicated: duplicated by
blocks: blocking
blocked: blocked by
partof: being part of
includes: including
requires: requiring
required: required by
time_entry:
activity: Activity
comment: Comment
hours: Hours
watchers:
label_loading: loading watchers...
label_error_loading: An error occurred while loading the watchers
label_search_watchers: Search watchers
label_add: Add watchers
label_discard: Discard selection
typeahead_placeholder: Search for possible watchers
relation_labels:
parent: Parent
children: Children
relates: Related To
duplicates: Duplicates
duplicated: Duplicated by
blocks: Blocks
blocked: Blocked by
precedes: Precedes
follows: Follows
includes: Includes
partof: Part of
requires: Requires
required: Required by
relation_type: relation type
relations_hierarchy:
parent_headline: Parent
hierarchy_headline: Hierarchy
children_headline: Children
relation_buttons:
set_parent: Set parent
change_parent: Change parent
remove_parent: Remove parent
group_by_wp_type: Group by work package type
group_by_relation_type: Group by relation type
add_parent: Add existing parent
add_new_child: Create new child
create_new: Create new
add_existing: Add existing
add_existing_child: Add existing child
remove_child: Remove child
add_new_relation: Create new relation
add_existing_relation: Add existing relation
update_description: Set or update description of this relation
toggle_description: Toggle relation description
update_relation: Click to change the relation type
add_follower: Add follower
add_predecessor: Add predecessor
remove: Remove relation
save: Save relation
abort: Abort
relations_autocomplete:
placeholder: Type to search
parent_placeholder: Choose new parent or press escape to cancel.
repositories:
select_tag: Select tag
select_branch: Select branch
field_value_enter_prompt: Enter a value for '%{field}'
select2:
input_too_short:
one: Please enter one more character
other: Please enter {{count}} more characters
zero: Please enter more characters
load_more: Loading more results ...
no_matches: No matches found
searching: Searching ...
selection_too_big:
one: You can only select one item
other: You can only select {{limit}} items
zero: You cannot select any items
project_menu_details: Details
sort:
sorted_asc: 'Ascending sort applied, '
sorted_dsc: 'Descending sort applied, '
sorted_no: 'No sort applied, '
sorting_disabled: sorting is disabled
activate_asc: activate to apply an ascending sort
activate_dsc: activate to apply a descending sort
activate_no: activate to remove the sort
text_work_packages_destroy_confirmation: Are you sure you want to delete the selected
work package(s)?
text_query_destroy_confirmation: Are you sure you want to delete the selected
view?
text_attachment_destroy_confirmation: Are you sure you want to delete the attachment?
timelines:
quarter_label: Q%{quarter_number}
gantt_chart: Gantt chart
labels:
title: Label configuration
bar: Bar labels
left: Left
right: Right
farRight: Far right
showNone: "-- No label --"
description: 'Select the attributes you want to be shown in the respective
positions of the Gantt chart at all times. Note that when hovering an element,
its date labels will be shown instead of these attributes.
'
button_activate: Show Gantt chart
button_deactivate: Hide Gantt chart
cancel: Cancel
change: Change in planning
due_date: Finish date
empty: "(empty)"
error: An error has occurred.
errors:
not_implemented: The timeline could not be rendered because it uses a feature
that is not yet implemented.
report_comparison: The timeline could not render the configured comparisons.
Please check the appropriate section in the configuration, resetting it
can help solve this problem.
report_epicfail: The timeline could not be loaded due to an unexpected error.
report_timeout: The timeline could not be loaded in a reasonable amount of
time.
filter:
grouping_other: Other
noneSelection: "(none)"
name: Name
outline: Reset Outline
outlines:
aggregation: Show aggregations only
level1: Expand level 1
level2: Expand level 2
level3: Expand level 3
level4: Expand level 4
level5: Expand level 5
all: Show all
project_status: Project status
really_close_dialog: Do you really want to close the dialog and lose the entered
data?
responsible: Responsible
save: Save
start_date: Start date
tooManyProjects: More than %{count} Projects. Please use a better filter!
selection_mode:
notification: Click on any highlighted work package to create the relation.
Press escape to cancel.
zoom:
in: Zoom in
out: Zoom out
auto: Auto zoom
days: Days
weeks: Weeks
months: Months
quarters: Quarters
years: Years
slider: Zoom slider
description: 'Select the initial zoom level that should be shown when autozoom
is not available.
'
tl_toolbar:
zooms: Zoom level
outlines: Hierarchy level
upsale:
ee_only: Enterprise Edition only feature
wiki_formatting:
strong: Strong
italic: Italic
underline: Underline
deleted: Deleted
code: Inline Code
heading1: Heading 1
heading2: Heading 2
heading3: Heading 3
unordered_list: Unordered List
ordered_list: Ordered List
quote: Quote
unquote: Unquote
preformatted_text: Preformatted Text
wiki_link: Link to a Wiki page
image: Image
work_packages:
bulk_actions:
move: Bulk move
edit: Bulk edit
copy: Bulk copy
delete: Bulk delete
button_clear: Clear
comment_added: The comment was successfully added.
comment_send_failed: An error has occurred. Could not submit the comment.
comment_updated: The comment was successfully updated.
confirm_edit_cancel: Are you sure you want to cancel editing the work package?
description_filter: Filter
description_enter_text: Enter text
description_options_hide: Hide options
description_options_show: Show options
error:
update_conflict_refresh: Click here to refresh the work package and update
to the newest version.
edit_prohibited: Editing %{attribute} is blocked for this work package. Either
this attribute is derived from relations (e.g, children) or otherwise not
configurable.
format:
date: "%{attribute} is no valid date - YYYY-MM-DD expected."
general: An error has occurred.
edit_attribute: "%{attribute} - Edit"
key_value: "%{key}: %{value}"
label_enable_multi_select: Enable multiselect
label_disable_multi_select: Disable multiselect
label_filter_add: Add filter
label_filter_by_text: Filter by text
label_options: Options
label_column_multiselect: 'Combined dropdown field: Select with arrow keys,
confirm selection with enter, delete with backspace'
message_error_during_bulk_delete: An error occurred while trying to delete work
packages.
message_successful_bulk_delete: Successfully deleted work packages.
message_successful_show_in_fullscreen: Click here to open this work package
in fullscreen view.
message_view_spent_time: Show spent time for this work package
message_work_package_read_only: Work package is locked in this status. No attribute
other than status can be altered.
no_value: No value
placeholder_filter_by_text: Subject, description, comments, ...
inline_create:
title: Click here to add a new work package to this list
create:
title: New work package
header: New %{type}
header_no_type: New work package (Type not yet set)
header_with_parent: 'New %{type} (Child of %{parent_type} #%{id})'
button: Create
copy:
title: Copy work package
hierarchy:
show: Show hierarchy mode
hide: Hide hierarchy mode
toggle_button: Click to toggle hierarchy mode.
leaf: Work package leaf at level %{level}.
children_collapsed: Hierarchy level %{level}, collapsed. Click to show the
filtered children
children_expanded: Hierarchy level %{level}, expanded. Click to collapse the
filtered children
faulty_query:
title: Work packages could not be loaded.
description: Your view is erroneous and could not be processed.
no_results:
title: No work packages to display.
description: Either none have been created or all work packages are filtered
out.
property_groups:
details: Details
people: People
estimatesAndTime: Estimates & Time
other: Other
properties:
assignee: Assignee
author: Author
createdAt: Created on
description: Description
date: Date
dueDate: Finish date
estimatedTime: Estimated time
spentTime: Spent time
category: Category
percentageDone: Percentage done
priority: Priority
projectName: Project
responsible: Responsible
startDate: Start date
status: Status
subject: Subject
title: Title
type: Type
updatedAt: Updated on
versionName: Version
version: Version
default_queries:
latest_activity: Latest activity
created_by_me: Created by me
assigned_to_me: Assigned to me
recently_created: Recently created
all_open: All open
summary: Summary
jump_marks:
pagination: Jump to table pagination
label_pagination: Click here to skip over the work packages table and go to
pagination
content: Jump to content
label_content: Click here to skip over the menu and go to the content
placeholders:
default: "-"
description: Click to enter description...
query:
column_names: Columns
group_by: Group results by
group: Group by
group_by_disabled_by_hierarchy: Group by is disabled due to the hierarchy
mode being active.
hierarchy_disabled_by_group_by: Hierarchy mode is disabled due to results
being grouped by %{column}.
sort_ascending: Sort ascending
sort_descending: Sort descending
move_column_left: Move column left
move_column_right: Move column right
hide_column: Sütunu gizlət
insert_columns: Insert columns ...
filters: Filters
display_sums: Display Sums
confirm_edit_cancel: Are you sure you want to cancel editing the name of this
view? Title will be set back to previous value.
click_to_edit_query_name: Click to edit title of this view.
rename_query_placeholder: Name of this view
errors:
unretrievable_query: Unable to retrieve view from URL
not_found: There is no such view
duplicate_query_title: Name of this view already exists. Change anyway?
text_no_results: No matching views were found.
table:
configure_button: Configure work package table
summary: Table with rows of work package and columns of work package attributes.
text_inline_edit: Most cells of this table are buttons that activate inline-editing
functionality of that attribute.
text_sort_hint: With the links in the table headers you can sort, group, reorder,
remove and add table columns.
text_select_hint: Select boxes should be opened with 'ALT' and arrow keys.
table_configuration:
button: Configure this work package table
choose_display_mode: Display work packages as
modal_title: Work package table configuration
embedded_tab_disabled: This configuration tab is not available for the embedded
view you're editing.
default: default
display_settings: Display settings
default_mode: Flat list
hierarchy_mode: Hierarchy
hierarchy_hint: All filtered table results will be augmented with their ancestors.
Hierarchies can be expanded and collapsed.
display_sums_hint: Display sums of all summable attributes in a row below
the table results.
show_timeline_hint: Show an interactive gantt chart on the right side of the
table. You can change its width by dragging the divider between table and
gantt chart.
highlighting: Highlighting
highlighting_mode:
description: Highlight with color
none: No highlighting
inline: Highlighted attribute(s)
inline_all: All attributes
entire_row_by: Entire row by
status: Status
priority: Priority
type: Type
columns_help_text: Use the input above to add or remove columns to your table
view. You can drag and drop the columns to reorder them.
upsale:
attribute_highlighting: Need certain work packages to stand out from the
mass?
relation_columns: Need to see relations in the work package list?
check_out_link: Check out the Enterprise Edition.
relation_filters:
first_part: Show all work packages
second_part: the current work package
tabs:
overview: Overview
activity: Activity
relations: Relations
watchers: Watchers
attachments: Attachments
time_relative:
days: days
weeks: weeks
months: months
toolbar:
settings:
configure_view: Configure view ...
columns: Columns ...
sort_by: Sort by ...
group_by: Group by ...
display_sums: Display sums
display_hierarchy: Display hierarchy
hide_hierarchy: Hide hierarchy
hide_sums: Hide sums
save: Save
save_as: Save as ...
export: Export ...
visibility_settings: Visibility settings ...
page_settings: Rename view ...
delete: Delete
filter: Filter
unselected_title: Work package
search_query_label: Search saved views
search_query_title: Click to search saved views
placeholder_query_title: Set a title for this view
modals:
label_settings: Rename view
label_name: Name
label_delete_page: Delete current page
button_apply: Apply
button_save: Save
button_submit: Submit
button_cancel: Cancel
form_submit:
title: Confirm to continue
text: Are you sure you want to perform this action?
destroy_work_package:
title: Confirm deletion of %{label}
text: Are you sure you want to delete the following %{label} ?
has_children: 'The work package has %{childUnits}:'
confirm_deletion_children: I acknowledge that ALL descendants of the listed
work packages will be recursively removed.
deletes_children: All child work packages and their descendants will also
be recursively deleted.
notice_no_results_to_display: No visible results to display.
notice_successful_create: Successful creation.
notice_successful_delete: Successful deletion.
notice_successful_update: Successful update.
notice_bad_request: Bad Request.
relations:
empty: No relation exists
remove: Remove relation
inplace:
button_edit: "%{attribute}: Edit"
button_save: "%{attribute}: Save"
button_cancel: "%{attribute}: Cancel"
button_save_all: Save
button_cancel_all: Cancel
link_formatting_help: Text formatting help
btn_preview_enable: Preview
btn_preview_disable: Disable preview
null_value_label: No value
clear_value_label: "-"
errors:
required: "%{field} cannot be empty"
number: "%{field} is not a valid number"
maxlength: "%{field} cannot contain more than %{maxLength} digit(s)"
minlength: "%{field} cannot contain less than %{minLength} digit(s)"
messages_on_field: 'This field is invalid: %{messages}'
error_could_not_resolve_version_name: Couldn't resolve version name
error_could_not_resolve_user_name: Couldn't resolve user name
error_attachment_upload: 'File failed to upload: %{error}'
error_attachment_upload_permission: You don't have the permission to upload files
on this resource.
units:
workPackage:
one: work package
other: work packages
child_work_packages:
one: one child work package
other: "%{count} work package children"
hour:
one: 1 hour
other: "%{count} hours"
zero: 0 hours
zen_mode:
button_activate: Activate zen mode
button_deactivate: Deactivate zen mode
global_search:
all_projects: In all projects
search: Search
close_search: Close search
current_project: In this project
current_project_and_all_descendants: In this project + subprojects
title:
all_projects: all projects
project_and_subprojects: and all subprojects
search_for: Search for
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More