Review and integrate Time Conductor Vue style conversion (#2180)

Styling updates for Vue version of Time Conductor
This commit is contained in:
Charles Hacskaylo 2018-10-02 17:31:45 -07:00 committed by Andrew Henry
parent e6e5b6a64a
commit 56b9708ab7
18 changed files with 1108 additions and 389 deletions

View File

@ -56,7 +56,7 @@ define([
};
DurationFormat.prototype.validate = function (text) {
return moment.utc(text, DATE_FORMATS).isValid();
return moment.utc(text, DATE_FORMATS, true).isValid();
};
return DurationFormat;

View File

@ -29,6 +29,7 @@ define([
var DATE_FORMAT = "YYYY-MM-DD HH:mm:ss.SSS",
DATE_FORMATS = [
DATE_FORMAT,
DATE_FORMAT + "Z",
"YYYY-MM-DD HH:mm:ss",
"YYYY-MM-DD HH:mm",
"YYYY-MM-DD"
@ -74,7 +75,7 @@ define([
};
UTCTimeFormat.prototype.validate = function (text) {
return moment.utc(text, DATE_FORMATS).isValid();
return moment.utc(text, DATE_FORMATS, true).isValid();
};
return UTCTimeFormat;

View File

@ -22,7 +22,7 @@
</div>
<div class="c-grid-item__controls">
<div class="icon-people" title='Shared'></div>
<div class="c-icon-button icon-info c-info-button" title='More Info'></div>
<div class="c-click-icon icon-info c-info-button" title='More Info'></div>
<div class="icon-pointer-right c-pointer-icon"></div>
</div>
</div>

View File

@ -28,7 +28,7 @@
</div>
<div class="c-ne__local-controls--hidden">
<a class="c-icon-button icon-trash"
<a class="c-click-icon icon-trash"
title="Delete this entry"
v-on:click="deleteEntry"></a>
</div>

View File

@ -20,106 +20,211 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<!-- Parent holder for time conductor. follow-mode | fixed-mode -->
<div class="l-flex-row l-time-conductor"
:class="[isFixed ? 'fixed-mode' : 'realtime-mode', panning ? 'status-panning' : '']">
<div class="flex-elem holder time-conductor-icon">
<div class="hand-little"></div>
<div class="hand-big"></div>
</div>
<div class="c-conductor"
:class="[isFixed ? 'is-fixed-mode' : 'is-realtime-mode', panning ? 'status-panning' : '']">
<form class="u-contents" ref="conductorForm"
@submit="isFixed ? setBoundsFromView($event) : setOffsetsFromView($event)">
<div class="flex-elem holder grows l-flex-col l-time-conductor-inner">
<!-- Holds inputs and ticks -->
<div class="l-time-conductor-inputs-and-ticks l-row-elem flex-elem no-margin">
<form class="l-time-conductor-inputs-holder" ref="conductorForm"
@submit="isFixed ? setBoundsFromView($event) : setOffsetsFromView($event)">
<span class="l-time-range-w start-w">
<span class="l-time-conductor-inputs">
<span class="l-time-range-input-w start-date">
<span class="title"></span>
<span class="time-range-input">
<input type="text" autocorrect="off" spellcheck="false"
ref="startDate"
v-model="formattedBounds.start"
@keyup="validateBounds('start', $event.target)"
@blur="setBoundsFromView()">
<date-picker :default-date-time="formattedBounds.start" :formatter="timeFormatter" @date-selected="startDateSelected"></date-picker>
</span>
</span>
<span class="l-time-range-input-w time-delta start-delta"
:class="{'hide': isFixed}">
-
<span class="s-input-inline hrs-min-input">
<input type="text" autocorrect="off" spellcheck="false"
v-model="offsets.start"
@keyup="validateOffsets($event)"
@blur="setOffsetsFromView()">
</span>
</span>
</span>
</span>
<span class="l-time-range-w end-w">
<span class="l-time-conductor-inputs">
<span class="l-time-range-input-w end-date">
<span class="title"></span>
<span class="time-range-input">
<input type="text" autocorrect="off" spellcheck="false"
v-model="formattedBounds.end"
:disabled="!isFixed"
ref="endDate"
@keyup="validateBounds('end', $event.target)"
@blur="setBoundsFromView()">
<date-picker :default-date-time="formattedBounds.end" :formatter="timeFormatter" @date-selected="endDateSelected"></date-picker>
</span>
</span>
<span class="l-time-range-input-w time-delta end-delta"
:class="{'hide': isFixed}">
+
<span class="s-input-inline hrs-min-input">
<input type="text" autocorrect="off" spellcheck="false"
v-model="offsets.end"
@keyup="validateOffsets($event)"
@blur="setOffsetsFromView()">
</span>
</span>
</span>
</span>
<input type="submit" class="invisible">
</form>
<conductor-axis class="mobile-hide" :bounds="rawBounds" @panZoom="setViewFromBounds"></conductor-axis>
</div>
<ConductorModeIcon class="c-conductor__mode-icon"></ConductorModeIcon>
<!-- Holds time system and session selectors, and zoom control -->
<div class="l-time-conductor-controls l-row-elem l-flex-row flex-elem">
<ConductorMode></ConductorMode>
<ConductorTimeSystem></ConductorTimeSystem>
<!-- Zoom control -->
<div v-if="isUTCBased && isFixed"
class="l-time-conductor-zoom-w grows flex-elem l-flex-row">
{{currentZoomText}}
<span class="time-conductor-zoom-current-range flex-elem flex-fixed holder">{{timeUnits}}</span>
<input class="time-conductor-zoom flex-elem" type="range"
v-model="currentZoom"
@change="setBoundsFromView()"
min="0.01"
step="0.01"
max="0.99" />
<div class="c-conductor__start-input">
<!-- Start input and controls -->
<div class="c-ctrl-wrapper c-conductor-input c-conductor__start__fixed"
v-if="isFixed">
<!-- Fixed input -->
<div class="c-conductor__start__fixed__label">Start</div>
<input class="c-input--datetime"
type="text" autocorrect="off" spellcheck="false"
ref="startDate"
v-model="formattedBounds.start"
@change="validateBounds('start', $event.target); setBoundsFromView()" />
<date-picker
:default-date-time="formattedBounds.start"
:formatter="timeFormatter"
@date-selected="startDateSelected"></date-picker>
</div>
<div class="c-ctrl-wrapper c-conductor-input c-conductor__start__delta"
v-if="!isFixed">
<!-- RT input -->
<div class="c-direction-indicator icon-minus"></div>
<input class="c-input--hrs-min-sec"
type="text" autocorrect="off"
spellcheck="false"
v-model="offsets.start"
@change="validateOffsets($event); setOffsetsFromView()">
</div>
</div>
</div>
<div class="c-conductor__end-input">
<!-- End input and controls -->
<div class="c-ctrl-wrapper c-conductor-input c-conductor__end__fixed"
v-if="isFixed">
<!-- Fixed input -->
<div class="c-conductor__end__fixed__label">End</div>
<input class="c-input--datetime"
type="text" autocorrect="off" spellcheck="false"
v-model="formattedBounds.end"
:disabled="!isFixed"
ref="endDate"
@change="validateBounds('end', $event.target); setBoundsFromView()">
<date-picker
class="c-ctrl-wrapper--menus-left"
:default-date-time="formattedBounds.end"
:formatter="timeFormatter"
@date-selected="endDateSelected"></date-picker>
</div>
<div class="c-ctrl-wrapper c-conductor-input c-conductor__end__delta"
v-if="!isFixed">
<!-- RT input -->
<div class="c-direction-indicator icon-plus"></div>
<input class="c-input--hrs-min-sec"
type="text"
autocorrect="off"
spellcheck="false"
v-model="offsets.end"
@change="validateOffsets($event); setOffsetsFromView()">
</div>
</div>
<conductor-axis
class="c-conductor__ticks"
:bounds="rawBounds"
@panAxis="setViewFromBounds"></conductor-axis>
<div class="c-conductor__controls">
<!-- Mode, time system menu buttons and duration slider -->
<ConductorMode class="c-conductor__mode-select"></ConductorMode>
<ConductorTimeSystem class="c-conductor__time-system-select"></ConductorTimeSystem>
</div>
<input type="submit" class="invisible">
</form>
</div>
</div>
</template>
<style lang="scss">
@import "~styles/sass-base";
.l-time-conductor-inputs input:invalid {
border: 1px solid $colorFormInvalid !important;
/*********************************************** CONDUCTOR LAYOUT */
.c-conductor {
display: grid;
grid-column-gap: $interiorMargin;
grid-row-gap: $interiorMargin;
align-items: center;
grid-template-rows: 1fr 1fr;
grid-template-columns: 20px auto 1fr auto;
grid-template-areas:
"tc-mode-icon tc-start tc-ticks tc-end"
"tc-controls tc-controls tc-controls tc-controls";
.c-conductor__end-input {
justify-content: flex-end;
}
body.phone.portrait & {
&.is-fixed-mode {
grid-row-gap: $interiorMargin;
grid-template-rows: auto auto auto;
grid-template-columns: 20px auto;
grid-template-areas:
"tc-mode-icon tc-start"
"tc-mode-icon tc-end"
"tc-mode-icon tc-controls";
.c-conductor {
&__mode-icon {
grid-row: 1;
}
&__ticks,
&__zoom {
display: none;
}
&-input [class*='__label'] {
// Start and end are in separate columns; make the labels line up
width: 40px;
}
&__end-input {
justify-content: flex-start;
}
}
}
}
&__mode-icon {
grid-area: tc-mode-icon;
}
&__start-input,
&__end-input {
display: flex;
}
&__start-input {
grid-area: tc-start;
}
&__end-input {
grid-area: tc-end;
display: flex;
}
&__ticks {
grid-area: tc-ticks;
}
&__controls {
grid-area: tc-controls;
display: flex;
align-items: center;
> * + * {
margin-left: $interiorMargin;
}
}
[class*='__delta'] {
&:before {
content: $glyph-icon-clock;
font-family: symbolsfont;
}
}
}
.l-time-conductor-zoom-w {
text-transform: capitalize;
.c-conductor-input {
color: $colorInputFg;
display: flex;
align-items: center;
justify-content: flex-start;
> * + * {
margin-left: $interiorMarginSm;
}
&:before {
// Realtime-mode clock icon symbol
margin-right: $interiorMarginSm;
}
.c-direction-indicator {
// Holds realtime-mode + and - symbols
font-size: 0.7em;
}
input:invalid {
background: rgba($colorFormInvalid, 0.3);
}
}
.is-realtime-mode {
.c-conductor-input {
&:before {
color: $colorTime;
}
}
}
</style>
@ -129,14 +234,13 @@ import ConductorMode from './ConductorMode.vue';
import ConductorTimeSystem from './ConductorTimeSystem.vue';
import DatePicker from './DatePicker.vue';
import ConductorAxis from './ConductorAxis.vue';
import ConductorModeIcon from './ConductorModeIcon.vue';
const DEFAULT_DURATION_FORMATTER = 'duration';
const SECONDS = 1000;
const DAYS = 24 * 60 * 60 * SECONDS;
const YEARS = 365 * DAYS;
const MAX_ZOOM_OUT = 10 * YEARS;
const MAX_ZOOM_IN = 5 * SECONDS;
const RESIZE_POLL_INTERVAL = 200;
export default {
@ -145,7 +249,8 @@ export default {
ConductorMode,
ConductorTimeSystem,
DatePicker,
ConductorAxis
ConductorAxis,
ConductorModeIcon
},
data() {
let bounds = this.openmct.time.bounds();
@ -155,7 +260,6 @@ export default {
let durationFormatter = this.getFormatter(timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
return {
currentZoom: this.calculateZoomFromBounds(),
timeFormatter: timeFormatter,
durationFormatter: durationFormatter,
offsets: {
@ -184,7 +288,7 @@ export default {
this.isUTCBased = timeSystem.isUTCBased;
},
setOffsetsFromView($event) {
if (this.offsetsChanged() && this.$refs.conductorForm.checkValidity()){
if (this.$refs.conductorForm.checkValidity()){
let startOffset = 0 - this.durationFormatter.parse(this.offsets.start);
let endOffset = this.durationFormatter.parse(this.offsets.end);
@ -198,13 +302,8 @@ export default {
return false;
}
},
offsetsChanged() {
let currentOffsets = this.openmct.time.clockOffsets();
return this.offsets.start !== currentOffsets.start ||
this.offsets.end !== currentOffsets.end;
},
setBoundsFromView($event) {
if (this.boundsChanged() && this.$refs.conductorForm.checkValidity()){
if (this.$refs.conductorForm.checkValidity()){
let start = this.timeFormatter.parse(this.formattedBounds.start);
let end = this.timeFormatter.parse(this.formattedBounds.end);
@ -218,14 +317,6 @@ export default {
return false;
}
},
boundsChanged() {
let currentBounds = this.openmct.time.bounds();
return this.timeFormatter.parse(this.formattedBounds.start) !== currentBounds.start ||
this.timeFormatter.parse(this.formattedBounds.end) !== currentBounds.end;
},
showValidityMessage($event) {
$event.target.reportValidity();
},
setViewFromClock(clock) {
this.isFixed = clock === undefined;
},
@ -239,9 +330,6 @@ export default {
this.offsets.start = this.durationFormatter.format(Math.abs(offsets.start));
this.offsets.end = this.durationFormatter.format(Math.abs(offsets.end));
},
showValidityMessage($event) {
$event.target.reportValidity();
},
validateBounds(startOrEnd, input) {
let validationResult = true;
@ -297,49 +385,8 @@ export default {
this.validateBounds('end', this.$refs.endDate);
this.setBoundsFromView();
},
zoomLevelToTimespan() {
let minMaxDelta = MAX_ZOOM_OUT - MAX_ZOOM_IN;
return minMaxDelta * Math.pow((1 - this.currentZoom), 4);
},
zoom() {
let zoomTimespan = this.zoomLevelToTimespan();
let start = this.openmct.time.bounds().start;
let end = this.openmct.time.bounds().end
let currentTimeSpan = end - start;
let delta = currentTimeSpan - zoomTimespan;
let bounds = {
start: start + delta / 2,
end: end - delta / 2
};
this.rawBounds = bounds;
this.setViewFromBounds(bounds);
this.zooming = false;
},
calculateZoomFromBounds() {
let start = this.openmct.time.bounds().start;
let end = this.openmct.time.bounds().end
let zoomMaxMinDelta = MAX_ZOOM_OUT - MAX_ZOOM_IN;
let currentBoundsDelta = end - start;
return 1 - Math.pow(currentBoundsDelta / zoomMaxMinDelta, 1 / 4);
}
},
computed: {
currentZoomText() {
return moment.duration(this.zoomLevelToTimespan()).humanize();
}
},
watch: {
currentZoom() {
if (!this.zooming) {
this.zooming = true;
requestAnimationFrame(this.zoom, RESIZE_POLL_INTERVAL);
}
}
},
mounted() {
this.zooming = false;
this.setTimeSystem(JSON.parse(JSON.stringify(this.openmct.time.timeSystem())));
this.openmct.time.on('bounds', this.setViewFromBounds);

View File

@ -20,14 +20,90 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div class="l-axis-holder" ref="axisHolder"
@mousedown="dragStart($event)"></div>
<div class="c-conductor-axis"
ref="axisHolder"
@mousedown="dragStart($event)">
</div>
</template>
<style lang="scss">
.l-axis-holder {
user-select: none;
@import "~styles/sass-base";
.c-conductor-axis {
$h: 18px;
$tickYPos: ($h / 2) + 12px;
@include userSelectNone();
@include bgTicks($c: rgba($colorBodyFg, 0.4));
background-position: 0 50%;
background-size: 5px 2px;
height: $h;
svg {
text-rendering: geometricPrecision;
width: 100%;
height: 100%;
> g {
// Overall Tick holder
transform: translateY($tickYPos);
path {
// Domain line
display: none;
}
g {
// Each tick. These move on drag.
line {
// Line beneath ticks
display: none;
}
}
}
text {
// Tick labels
fill: $colorBodyFg;
font-size: 1em;
paint-order: stroke;
font-weight: bold;
stroke: $colorBodyBg;
stroke-linecap: butt;
stroke-linejoin: bevel;
stroke-width: 6px;
}
}
body.desktop .is-fixed-mode & {
@include cursorGrab();
background-size: 3px 30%;
border-radius: $controlCr;
background-color: $colorBodyBgSubtle;
box-shadow: inset rgba(black, 0.2) 0 1px 1px;
svg text {
fill: $colorBodyFg;
stroke: $colorBodyBgSubtle;
}
&:hover,
&:active {
$c: $colorKeySubtle;
background-color: $c;
svg text {
stroke: $c;
}
}
}
.is-realtime-mode & {
svg text {
fill: $colorTime;
}
}
}
</style>
<script>
@ -40,6 +116,8 @@ import utcMultiTimeFormat from './utcMultiTimeFormat.js';
const PADDING = 1;
const DEFAULT_DURATION_FORMATTER = 'duration';
const RESIZE_POLL_INTERVAL = 200;
const PIXELS_PER_TICK = 100;
const PIXELS_PER_TICK_WIDE = 200;
export default {
inject: ['openmct'],
@ -62,6 +140,12 @@ export default {
this.xScale.range([PADDING, this.width - PADDING * 2]);
this.axisElement.call(this.xAxis);
if (this.width > 1800) {
this.xAxis.ticks(this.width / PIXELS_PER_TICK_WIDE);
} else {
this.xAxis.ticks(this.width / PIXELS_PER_TICK);
}
this.msPerPixel = (bounds.end - bounds.start) / this.width;
},
setViewFromTimeSystem(timeSystem) {
@ -119,7 +203,7 @@ export default {
start: newStart,
end: newStart + deltaTime
};
this.$emit('panZoom', this.bounds);
this.$emit('panAxis', this.bounds);
this.dragging = false;
})
} else {

View File

@ -20,46 +20,62 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div class="holder flex-elem menus-up time-system">
<span>
<div class="s-menu-button" @click="toggleMenu($event)">
<span class="title-label">{{selectedMode.name}}</span>
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up">
<div class="c-button--menu c-mode-button"
@click="toggleMenu($event)">
<span class="c-button__label">{{selectedMode.name}}</span>
</div>
<div class="menu super-menu mini l-mode-selector-menu"
v-if="showMenu">
<div class="w-menu">
<div class="col menu-items">
<ul>
<li v-for="mode in modes"
:key="mode.key"
@click="setOption(mode)">
<a @mouseover="hoveredMode = mode"
@mouseleave="hoveredMode = {}"
class="menu-item-a"
:class="mode.cssClass">
{{mode.name}}
</a>
</li>
</ul>
</div>
<div class="col menu-item-description">
<div class="desc-area ui-symbol icon type-icon" :class="hoveredMode.cssClass"></div>
<div class="w-title-desc">
<div class="desc-area title">
{{hoveredMode.name}}
</div>
<div class="desc-area description">
{{hoveredMode.description}}
</div>
</div>
</div>
<div class="c-menu c-super-menu c-conductor__mode-menu"
v-if="showMenu">
<div class="c-super-menu__menu">
<ul>
<li v-for="mode in modes"
:key="mode.key"
@click="setOption(mode)"
@mouseover="hoveredMode = mode"
@mouseleave="hoveredMode = {}"
class="menu-item-a"
:class="mode.cssClass">
{{mode.name}}
</li>
</ul>
</div>
<div class="c-super-menu__item-description">
<div :class="['l-item-description__icon', 'bg-' + hoveredMode.cssClass]"></div>
<div class="l-item-description__name">{{hoveredMode.name}}</div>
<div class="l-item-description__description">{{hoveredMode.description}}</div>
</div>
</div>
</span>
</div>
</div>
</template>
<style lang="scss">
@import "~styles/sass-base";
.c-conductor__mode-menu {
max-height: 80vh;
max-width: 500px;
min-height: 250px;
z-index: 70;
[class*="__icon"] {
filter: $colorKeyFilter;
}
[class*="__item-description"] {
min-width: 200px;
}
}
.is-realtime-mode {
.c-mode-button {
background: $colorTimeBg;
&:hover {
background: $colorTimeHov;
}
}
}
</style>
<script>
@ -90,7 +106,7 @@ export default {
* Populate the modes menu with metadata from the available clocks
* "Fixed Mode" is always first, and has no defined clock
*/
this.modes = [this.getModeOptionForClock(undefined)]
this.modes = [undefined]
.concat(clocks)
.map(this.getModeOptionForClock);
@ -105,7 +121,7 @@ export default {
key: 'fixed',
name: 'Fixed Timespan Mode',
description: 'Query and explore data that falls between two fixed datetimes.',
cssClass: 'icon-calendar'
cssClass: 'icon-tabular'
}
} else {
return {

View File

@ -0,0 +1,139 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div class="c-clock-symbol">
<div class="hand-little"></div>
<div class="hand-big"></div>
</div>
</template>
<style lang="scss">
@import "~styles/sass-base";
@keyframes clock-hands {
0% { transform: translate(-50%, -50%) rotate(0deg); }
100% { transform: translate(-50%, -50%) rotate(360deg); }
}
@keyframes clock-hands-sticky {
0% { transform: translate(-50%, -50%) rotate(0deg); }
7% { transform: translate(-50%, -50%) rotate(0deg); }
8% { transform: translate(-50%, -50%) rotate(30deg); }
15% { transform: translate(-50%, -50%) rotate(30deg); }
16% { transform: translate(-50%, -50%) rotate(60deg); }
24% { transform: translate(-50%, -50%) rotate(60deg); }
25% { transform: translate(-50%, -50%) rotate(90deg); }
32% { transform: translate(-50%, -50%) rotate(90deg); }
33% { transform: translate(-50%, -50%) rotate(120deg); }
40% { transform: translate(-50%, -50%) rotate(120deg); }
41% { transform: translate(-50%, -50%) rotate(150deg); }
49% { transform: translate(-50%, -50%) rotate(150deg); }
50% { transform: translate(-50%, -50%) rotate(180deg); }
57% { transform: translate(-50%, -50%) rotate(180deg); }
58% { transform: translate(-50%, -50%) rotate(210deg); }
65% { transform: translate(-50%, -50%) rotate(210deg); }
66% { transform: translate(-50%, -50%) rotate(240deg); }
74% { transform: translate(-50%, -50%) rotate(240deg); }
75% { transform: translate(-50%, -50%) rotate(270deg); }
82% { transform: translate(-50%, -50%) rotate(270deg); }
83% { transform: translate(-50%, -50%) rotate(300deg); }
90% { transform: translate(-50%, -50%) rotate(300deg); }
91% { transform: translate(-50%, -50%) rotate(330deg); }
99% { transform: translate(-50%, -50%) rotate(330deg); }
100% { transform: translate(-50%, -50%) rotate(360deg); }
}
.c-clock-symbol {
$c: $colorBtnBg; //$colorObjHdrIc;
$d: 18px;
height: $d;
width: $d;
position: relative;
&:before {
font-family: symbolsfont;
color: $c;
content: $glyph-icon-brackets;
font-size: $d;
line-height: normal;
display: block;
width: 100%;
height: 100%;
z-index: 1;
}
// Clock hands
div[class*="hand"] {
$handW: 2px;
$handH: $d * 0.4;
animation-iteration-count: infinite;
animation-timing-function: linear;
transform-origin: bottom;
position: absolute;
height: $handW;
width: $handW;
left: 50%;
top: 50%;
z-index: 2;
&:before {
background: $c;
content: '';
display: block;
position: absolute;
width: 100%;
bottom: -1px;
}
&.hand-little {
z-index: 2;
animation-duration: 12s;
transform: translate(-50%, -50%) rotate(120deg);
&:before {
height: ceil($handH * 0.6);
}
}
&.hand-big {
z-index: 1;
animation-duration: 1s;
transform: translate(-50%, -50%);
&:before {
height: $handH;
}
}
}
// Modes
.is-realtime-mode &,
.is-lad-mode & {
&:before {
// Brackets icon
color: $colorTime;
}
div[class*="hand"] {
animation-name: clock-hands;
&:before {
background: $colorTime;
}
}
}
}
</style>

View File

@ -20,30 +20,38 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div class="holder flex-elem menus-up time-system">
<div class="s-menu-button menu-element"
:class="selectedTimeSystem.cssClass">
<span class="l-click-area" @click="toggleMenu($event)"></span>
<span class="title-label" v-if="selectedTimeSystem.name">
{{selectedTimeSystem.name}}
</span>
<div class="menu" v-if="showMenu">
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up"
v-if="selectedTimeSystem.name">
<div class="c-button--menu c-time-system-button"
:class="selectedTimeSystem.cssClass"
@click="toggleMenu($event)">
<span class="c-button__label">{{selectedTimeSystem.name}}</span>
</div>
<div class="c-menu" v-if="showMenu">
<ul>
<li @click="setTimeSystemFromView(timeSystem)"
v-for="timeSystem in timeSystems"
:key="timeSystem.key"
:class="timeSystem.cssClass">
{{timeSystem.name}}
{{timeSystem.name}}
</li>
</ul>
</div>
</div>
</div>
</template>
<style lang="scss">
@import "~styles/sass-base";
.is-realtime-mode {
.c-time-system-button {
background: $colorTimeBg;
&:hover {
background: $colorTimeHov;
}
}
}
</style>
<script>
@ -66,7 +74,7 @@ export default {
},
setTimeSystemFromView(timeSystem) {
if (timeSystem !== this.selectedTimeSystem) {
if (timeSystem.key !== this.selectedTimeSystem.key) {
let activeClock = this.openmct.time.clock();
let configuration = this.getMatchingConfig({
clock: activeClock && activeClock.key,

View File

@ -20,35 +20,106 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<span class="menus-up">
<a class="ui-symbol icon icon-calendar" ref="calendarButton" @click="togglePicker($event)"></a>
<div class="l-datetime-picker s-datetime-picker s-menu" v-if="showPicker" ref="popup">
<div class="holder">
<div class="l-month-year-pager">
<a class="pager prev" ng-click="changeMonth(-1)"></a>
<span class="val">{{model.month}} {{model.year}}</span>
<a class="pager next" ng-click="changeMonth(1)"></a>
<div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up" ref="calendarHolder">
<a class="c-click-icon icon-calendar"
@click="togglePicker()"></a>
<div class="c-menu c-datetime-picker"
v-if="showPicker">
<div class="c-datetime-picker__month-year-pager c-pager l-month-year-pager">
<div class="c-pager__prev c-click-icon icon-arrow-left"
@click="changeMonth(-1)"></div>
<div class="c-pager__month-year">{{model.month}} {{model.year}}</div>
<div class="c-pager__next c-click-icon icon-arrow-right"
@click="changeMonth(1)"></div>
</div>
<div class="l-calendar">
<ul class="l-cal-row l-header">
<li v-for="day in ['Su','Mo','Tu','We','Th','Fr','Sa']" :key="day">{{day}}</li>
<div class="c-datetime-picker__calendar c-calendar">
<ul class="c-calendar__row--header l-cal-row">
<li v-for="day in ['Su','Mo','Tu','We','Th','Fr','Sa']"
:key="day">{{day}}</li>
</ul>
<ul class="l-cal-row l-body" v-for="(row, index) in table" :key="index">
<ul class="c-calendar__row--body"
v-for="(row, index) in table"
:key="index">
<li v-for="(cell, index) in row"
:key="index"
@click="select(cell)"
:class='{ "in-month": isInCurrentMonth(cell), selected: isSelected(cell) }'>
<div class="prime">{{cell.day}}</div>
<div class="sub">{{cell.dayOfYear}}</div>
:class="{ 'is-in-month': isInCurrentMonth(cell), selected: isSelected(cell) }">
<div class="c-calendar__day--prime">{{cell.day}}</div>
<div class="c-calendar__day--sub">{{cell.dayOfYear}}</div>
</li>
</ul>
</div>
</div>
</div>
</span>
</template>
<style lang="scss">
@import "~styles/sass-base";
/******************************************************** PICKER */
.c-datetime-picker {
@include userSelectNone();
padding: $interiorMarginLg !important;
display: flex;
flex-direction: column;
> * + * {
border-top: 1px solid $colorInteriorBorder;
margin-top: $interiorMargin;
}
}
.c-pager {
display: grid;
grid-column-gap: $interiorMargin;
grid-template-rows: 1fr;
grid-template-columns: auto 1fr auto;
align-items: center;
.c-click-icon {
font-size: 0.8em;
}
&__month-year {
text-align: center;
}
}
/******************************************************** CALENDAR */
.c-calendar {
display: grid;
grid-template-columns: repeat(7, min-content);
grid-template-rows: auto;
grid-gap: 1px;
$mutedOpacity: 0.7;
ul {
display: contents;
&[class*='--header'] {
pointer-events: none;
li {
opacity: $mutedOpacity;
}
}
}
li {
display: flex;
flex-direction: column;
padding: $interiorMargin;
&.is-in-month {
background: rgba($colorBodyFg, 0.1);
}
}
&__day {
&--sub {
opacity: $mutedOpacity;
font-size: 0.8em;
}
}
}
</style>
<script>
@ -178,6 +249,7 @@ export default {
this.date.year = cell.year;
this.date.day = cell.day;
this.updateFromView();
this.showPicker = false;
},
dateEquals(d1, d2) {
@ -187,14 +259,14 @@ export default {
},
changeMonth(delta) {
picker.month += delta;
if (picker.month > 11) {
picker.month = 0;
picker.year += 1;
this.picker.month += delta;
if (this.picker.month > 11) {
this.picker.month = 0;
this.picker.year += 1;
}
if (picker.month < 0) {
picker.month = 11;
picker.year -= 1;
if (this.picker.month < 0) {
this.picker.month = 11;
this.picker.year -= 1;
}
this.picker.interacted = true;
this.updateViewForMonth();
@ -209,26 +281,20 @@ export default {
},
hidePicker(event) {
if (event.srcElement !== this.$refs.calendarButton){
let path = event.composedPath();
if (path.indexOf(this.$refs.calendarHolder) === -1) {
this.showPicker = false;
}
},
togglePicker(event) {
togglePicker() {
this.showPicker = !this.showPicker;
if (this.showPicker) {
document.addEventListener('click', this.hidePicker, {
capture: true,
once: true,
passive: true
capture: true
});
this.$nextTick().then(this.setPopupPosition);
}
},
setPopupPosition() {
this.$refs.popup.style.bottom = this.$refs.popup.offsetHeight + 20 + 'px';
}
},
mounted: function () {
@ -236,6 +302,9 @@ export default {
this.updateViewForMonth();
},
destroyed: function () {
document.addEventListener('click', this.hidePicker, {
capture: true
});
}
}

View File

@ -25,8 +25,8 @@ $colorKeyFilterHov: brightness(1) sepia(1) hue-rotate(145deg) saturate(7);
$colorKeySelectedBg: $colorKey;
$colorKeyFg: #fff;
$colorKeyHov: #00c0f6;
$colorEditAreaBg: #eafaff;
$colorEditAreaFg: #4bb1c7;
$colorEditAreaBg: #eafaff; // Deprecated, use $editColor instead
$colorEditAreaFg: #4bb1c7; // Deprecated, use $editColor instead
$colorInteriorBorder: rgba($colorBodyFg, 0.2);
$colorA: #999;
$colorAHov: $colorKey;
@ -38,6 +38,16 @@ $smallCr: 2px;
$overlayCr: 11px;
$shdwTextSubtle: rgba(black, 0.2) 0 1px 2px;
// Variations
$colorBodyBgSubtle: pullForward($colorBodyBg, 5%);
$colorBodyBgSubtleHov: pushBack($colorKey, 50%);
$colorKeySubtle: pushBack($colorKey, 50%);
$colorTime: #618cff;
$colorTimeBg: $colorTime;
$colorTimeFg: $colorBodyBg;
$colorTimeHov: pushBack($colorTime, 5%);
$colorTimeSubtle: pushBack($colorTime, 20%);
// Buttons and Controls
$btnPad: $interiorMargin, $interiorMargin * 1.25;
$colorBtnBg: #aaaaaa;
@ -50,6 +60,9 @@ $colorBtnMajorBg: $colorKey;
$colorBtnMajorBgHov: $colorKeyHov;
$colorBtnMajorFg: $colorKeyFg;
$colorBtnMajorFgHov: pushBack($colorBtnMajorFg, $hoverRatioPercent);
$colorBtnCautionBg: #f16f6f;
$colorBtnCautionBgHov: #f1504e;
$colorBtnCautionFg: $colorBtnFg;
$colorClickIcon: $colorKey;
$colorClickIconHov: $colorKeyHov;
$colorToggleIcon: rgba($colorClickIcon, 0.5);
@ -70,7 +83,7 @@ $sliderColorRangeValHovFg: $colorBodyFg;
$sliderKnobW: 15px;
$sliderKnobR: 2px;
$timeControllerToiLineColor: $colorBodyFg;
$timeControllerToiLineColorHov: #0052b5;
$timeControllerToiLineColorHov: $colorTime;
$colorTransLucBg: #666; // Used as a visual blocking element over variable backgrounds, like imagery
$createBtnTextTransform: uppercase;
@ -88,13 +101,20 @@ $colorIconAliasForKeyFilter: #aaa;
$colorPausedBg: #ff9900;
$colorPausedFg: #fff;
$colorCreateBtn: $colorKey;
$colorGridLines: rgba(#000, 0.05);
$colorInvokeMenu: #fff;
$colorObjHdrTxt: $colorBodyFg;
$colorObjHdrIc: lighten($colorObjHdrTxt, 30%);
$colorTick: rgba(black, 0.2);
$colorSelectableSelectedPrimary: $colorKey;
$colorSelectableHov: rgba($colorBodyFg, 0.4);
$editColor: #00c7c3;
$browseBorderSelectableHov: 1px dotted rgba($colorBodyFg, 0.2);
$browseShdwSelectableHov: rgba($colorBodyFg, 0.2) 0 0 3px;
$browseBorderSelected: 1px solid rgba($colorBodyFg, 0.6);
$editBorderSelectable: 1px dotted rgba($editColor, 1);
$editBorderSelectableHov: 1px dashed rgba($editColor, 1);
$editBorderSelected: 1px solid $editColor;
$editBorderDrilledIn: 1px dashed #ff4d9a;
$colorGridLines: rgba($editColor, 0.2);
// Menus
$colorMenuBg: pushBack($colorBodyBg, 10%);
@ -109,6 +129,11 @@ $colorCreateMenuLgIcon: $colorKey;
$colorCreateMenuText: $colorBodyFg;
$menuItemPad: ($interiorMargin, nth($btnPad, 2));
// Palettes and Swatches
$paletteItemBorderOuterColorSelected: black;
$paletteItemBorderInnerColorSelected: white;
$paletteItemBorderInnerColor: rgba($paletteItemBorderOuterColorSelected, 0.3);
// Form colors
$colorCheck: $colorKey;
$colorFormRequired: $colorKey;
@ -125,6 +150,9 @@ $colorInputPlaceholder: pushBack($colorBodyFg, 20%);
$colorFormText: pushBack($colorBodyFg, 10%);
$colorInputIcon: pushBack($colorBodyFg, 25%);
$colorFieldHint: pullForward($colorBodyFg, 40%);
$shdwInput: inset rgba(black, 0.4) 0 0 1px;
$shdwInputHov: inset rgba(black, 0.7) 0 0 1px;
$shdwInputFoc: inset rgba(black, 0.7) 0 0 3px;
// Inspector
$colorInspectorBg: pullForward($colorBodyBg, 5%);
@ -282,12 +310,6 @@ $colorCalCellSelectedBg: $colorItemTreeSelectedBg;
$colorCalCellSelectedFg: $colorItemTreeSelectedFg;
$colorCalCellInMonthBg: pullForward($colorMenuBg, 5%);
// Palettes
$colorPaletteFg: pullForward($colorMenuBg, 30%);
$colorPaletteSelected: #333;
$shdwPaletteFg: none;
$shdwPaletteSelected: inset 0 0 0 1px #fff;
// About Screen
$colorAboutLink: #84b3ff;

View File

@ -152,7 +152,7 @@ $glyph-icon-notebook: '\e1131';
$bg-icon-activity: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M288 32H160l160 160H174.872C152.74 153.742 111.377 128 64 128H0v256h64c47.377 0 88.74-25.742 110.872-64H320L160 480h128l224-224L288 32z'/%3e%3c/svg%3e");
$bg-icon-activity-mode: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M256 0C148.6 0 56.6 66.2 18.6 160H64c28.4 0 54 12.4 71.5 32H256l-96-96h128l160 160-160 160H160l96-96H135.5C118 339.6 92.4 352 64 352H18.6c38 93.8 129.9 160 237.4 160 141.4 0 256-114.6 256-256S397.4 0 256 0z'/%3e%3c/svg%3e");
$bg-icon-autoflow-tabular: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M96 0C43.2 0 0 43.2 0 96v320c0 52.8 43.2 96 96 96h32V0H96zM192 0h128v512H192zM416 0h-32v352h128V96c0-52.8-43.2-96-96-96z'/%3e%3c/svg%3e");
$bg-icon-clock: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M256 0C114.62 0 0 114.62 0 256s114.62 256 256 256 256-114.62 256-256S397.38 0 256 0zm135 345a36 36 0 0 1-31.21 18 35.83 35.83 0 0 1-18-4.83l-110.85-64-.14-.08q-.6-.35-1.19-.73l-.43-.28-.93-.64-.63-.45-.63-.48-.85-.67-.32-.27c-.36-.3-.72-.61-1.07-.92a35.76 35.76 0 0 1-6.52-7.9c-.14-.23-.27-.47-.41-.7s-.29-.49-.43-.74a35.75 35.75 0 0 1-3.58-9.59v-.06c-.1-.46-.19-.92-.27-1.38 0-.14-.05-.28-.08-.42-.06-.35-.11-.71-.15-1.07s-.07-.52-.1-.79-.05-.51-.07-.77l-.09-1.12v-.52-1.39V81a36 36 0 0 1 36-36 36 36 0 0 1 36 36v161.22l92.85 53.61A36 36 0 0 1 391 345z' fill='%2300a14b'/%3e%3c/svg%3e");
$bg-icon-clock: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256 256-114.6 256-256S397.4 0 256 0zm135 345c-6.4 11.1-18.3 18-31.2 18-6.3 0-12.5-1.7-18-4.8l-110.9-64-.1-.1c-.4-.2-.8-.5-1.2-.7l-.4-.3-.9-.6-.6-.5-.6-.5-.9-.7-.3-.3c-.4-.3-.7-.6-1.1-.9-2.5-2.3-4.7-5-6.5-7.9-.1-.2-.3-.5-.4-.7s-.3-.5-.4-.7c-1.6-3-2.9-6.2-3.6-9.6v-.1c-.1-.5-.2-.9-.3-1.4 0-.1 0-.3-.1-.4-.1-.3-.1-.7-.1-1.1s-.1-.5-.1-.8 0-.5-.1-.8-.1-.8-.1-1.1v-.5-1.4V81c0-19.9 16.1-36 36-36s36 16.1 36 36v161.2l92.9 53.6c17.1 10 22.9 32 13 49.2z'/%3e%3c/svg%3e");
$bg-icon-database: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M256 256C114.615 256 0 213.019 0 160v256c0 53.019 114.615 96 256 96s256-42.981 256-96V160c0 53.019-114.615 96-256 96z'/%3e%3cellipse fill='%23666666' cx='256' cy='96' rx='256' ry='96'/%3e%3c/svg%3e");
$bg-icon-database-query: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M341.76 409.643C316.369 423.871 287.118 432 256 432c-97.047 0-176-78.953-176-176S158.953 80 256 80s176 78.953 176 176c0 31.118-8.129 60.369-22.357 85.76l95.846 95.846C509.747 430.661 512 423.429 512 416V96c0-53.019-114.615-96-256-96S0 42.981 0 96v320c0 53.019 114.615 96 256 96 63.055 0 120.774-8.554 165.388-22.73l-79.628-79.627z'/%3e%3cpath fill='%23666666' d='M176 256c0 44.112 35.888 80 80 80s80-35.888 80-80-35.888-80-80-80-80 35.888-80 80z'/%3e%3c/svg%3e");
$bg-icon-dataset: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3e%3cpath fill='%23666666' d='M448 96H288l-54.6-54.6-18.7-18.7C202.2 10.2 177.6 0 160 0H32C14.4 0 0 14.4 0 32v192c0-35.2 28.8-64 64-64h384c35.2 0 64 28.8 64 64v-64c0-35.2-28.8-64-64-64zM448 224H64c-35.2 0-64 28.8-64 64v160c0 35.2 28.8 64 64 64h384c35.2 0 64-28.8 64-64V288c0-35.2-28.8-64-64-64zM160 448H96V288h64v160zm128 0h-64V288h64v160zm128 0h-64V288h64v160z'/%3e%3c/svg%3e");

View File

@ -1,12 +1,35 @@
/******************************************************** BUTTONS */
%c-control {
@include userSelectNone();
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
// VERSION MANUALLY MIGRATED FROM VUE-TOOLBAR
/******************************************************** PLACEHOLDERS */
@mixin cControl() {
$fs: 1em;
@include userSelectNone();
display: inline-flex;
align-items: center;
font-size: $fs;
justify-content: start;
cursor: pointer;
justify-content: center;
overflow: hidden;
&:before,
&:after {
@ -20,17 +43,19 @@
}
[class*="__label"] {
@include ellipsize();
display: block;
line-height: $fs; // Remove effect on top and bottom padding
font-size: $fs;
}
}
%c-button {
@extend %c-control;
@mixin cButton() {
@include cControl();
background: $colorBtnBg;
border-radius: $controlCr;
color: $colorBtnFg;
cursor: pointer;
padding: nth($btnPad, 1) nth($btnPad, 2);
&:hover {
@ -47,119 +72,121 @@
color: $colorBtnMajorFgHov;
}
}
&[class*='--caution'] {
background: $colorBtnCautionBg;
color: $colorBtnCautionFg;
&:hover {
background: $colorBtnCautionBgHov;
}
}
}
/********* Buttons */
// Optionally can include icon in :before via markup
.c-button,
button {
@extend %c-button;
}
/********* Icon Buttons */
.c-icon-button {
@mixin cClickIcon() {
// A clickable element that just includes the icon, no background
// Padding is included to facilitate a bigger hit area
// Make the icon bigger relative to its container
@extend %c-control;
@include cControl();
$pLR: 3px;
$pTB: 3px;
border-radius: $controlCr;
color: $colorKey;
font-size: $fontBaseSize * 1.2;
cursor: pointer;
padding: $pTB $pLR ;
&:hover {
background: rgba($colorKey, 0.2);
}
&:before {
font-size: 1.1em;
&:before,
*:before {
// *:before handles any nested containers that may contain glyph elements
// Needed for c-togglebutton.
font-size: 1.3em;
}
}
/********* Button Sets */
.c-button-set {
// Buttons are smashed together with minimal margin
// c-buttons don't have border-radius between buttons, creates a tool-button-strip look
// c-icon-buttons get grouped more closely together
// When one set is adjacent to another, provides a divider between
@mixin cCtrlWrapper {
// Provides a wrapper around buttons and other controls
// Contains control and provides positioning context for contained menu/palette.
// Wraps --menu elements, contains button and menu
overflow: visible;
display: inline-flex;
.c-menu {
// Default position of contained menu
top: 100%; left: 0;
}
&[class*='--menus-up'] {
.c-menu {
top: auto; bottom: 100%;
}
}
&[class*='--menus-left'] {
.c-menu {
left: auto; right: 0;
}
}
}
/********* Buttons */
// Optionally can include icon in :before via markup
.c-button,
.c-button--menu,
button {
@include cButton();
}
.c-button--menu {
$m: $interiorMargin;
&:before,
> * {
// Assume buttons are immediate descendants
flex: 0 0 auto;
&[class^="c-button"] {
// Only apply the following to buttons that have background, eg. c-button
border-radius: 0;
+ * {
margin-left: 1px;
}
&:first-child {
border-top-left-radius: $controlCr;
border-bottom-left-radius: $controlCr;
}
&:last-child {
border-top-right-radius: $controlCr;
border-bottom-right-radius: $controlCr;
}
}
}
+ .c-button-set {
$m: $interiorMarginSm;
&:before {
content: '';
display: block;
width: $m;
border-right: 1px solid $colorInteriorBorder;
margin-right: $m;
}
}
}
/********* Menu Buttons */
// Always includes :after dropdown arrow
// Optionally can include icon in :before
// Default menu position is down and to the right
// Apply c-menu-button--menus-up and c-menu-button--menus-left to --w wrapper element to modify menu position
.c-menu-button {
$m: $interiorMarginSm;
@extend %c-button;
&:before {
margin-right: $m;
}
&:after {
content: $glyph-icon-arrow-down;
font-family: symbolsfont;
margin-left: $m;
opacity: 0.5;
}
}
&--w {
// Wraps c-menu-button, contains button and menu
.c-menu {
// Default position
top: 100%; left: 0;
/********* Icon Buttons */
.c-click-icon {
@include cClickIcon();
&--menu {
&:after {
content: $glyph-icon-arrow-down;
font-family: symbolsfont;
font-size: 0.6em;
margin-left: floor($interiorMarginSm * 0.8);
opacity: 0.5;
}
}
&--swatched {
// Color control, show swatch element
display: flex;
flex-flow: column nowrap;
align-items: center;
justify-content: center;
> [class*='swatch'] {
box-shadow: inset rgba(black, 0.2) 0 0 1px;
flex: 0 0 auto;
height: 4px;
width: 100%;
margin-top: 1px;
}
&.c-menu-button--menus-up {
.c-menu {
top: auto; bottom: 100%;
}
}
&.c-menu-button--menus-left {
.c-menu {
left: auto; right: 0;
}
&:before {
// Reduce size of icon to make a bit of room
flex: 1 1 auto;
font-size: 1.1em;
}
}
}
@ -169,7 +196,7 @@ button {
// Provides a downward arrow icon that when clicked displays a context menu
// Always placed AFTER an element
.c-disclosure-button {
@extend .c-icon-button;
@include cClickIcon();
margin-left: $interiorMarginSm;
&:before {
@ -208,13 +235,39 @@ button {
}
}
/******************************************************** FORM ELEMENTS */
/********* Inline inputs */
input, textarea {
font-family: inherit;
font-weight: inherit;
letter-spacing: inherit;
}
input[type=text],
input[type=search],
input[type=number] {
@include reactive-input();
padding: $inputTextP;
&.numeric {
text-align: right;
}
}
.c-input {
&--datetime {
// Sized for values such as 2018-09-28 22:32:33.468Z
width: 160px;
}
&--hrs-min-sec {
// Sized for values such as 00:25:00
width: 60px;
}
&-inline,
&--inline {
// A text input or contenteditable element that indicates edit affordance on hover and looks like an input on focus
.c-input-inline {
@include input-base();
border: 1px solid transparent;
@include reactive-input();
box-shadow: none;
display: block !important;
min-width: 0;
padding-left: 0;
@ -232,12 +285,38 @@ button {
padding-left: $inputTextPLeftRight;
padding-right: $inputTextPLeftRight;
}
&:hover {
border-color: rgba($colorBodyFg, 0.2);
}
&--labeled {
// TODO: replace .c-labeled-input with this
// An input used in the Toolbar
// Assumes label is before the input
@include cControl();
input {
margin-left: $interiorMarginSm;
}
&:focus {
@include nice-input($shdw: rgba(0, 0, 0, 0.6) 0 1px 3px);
border-color: transparent;
}
}
.c-labeled-input {
// An input used in the Toolbar
// Assumes label is before the input
@include cControl();
input {
margin-left: $interiorMarginSm;
}
}
/******************************************************** HYPERLINKS AND HYPERLINK BUTTONS */
.c-hyperlink {
&--link {
color: $colorKey;
}
&--button {
@include cButton();
}
}
@ -256,8 +335,10 @@ button {
@mixin menuInner() {
color: $colorMenuFg;
li {
@extend %c-control;
@include cControl();
justify-content: start;
color: $colorMenuFg;
cursor: pointer;
display: flex;
padding: nth($menuItemPad, 1) nth($menuItemPad, 2);
transition: $transIn;
@ -281,11 +362,6 @@ button {
.c-menu {
@include menuOuter();
@include menuInner();
li {
&:not(:first-child) {
border-top: 1px solid pullForward($colorMenuBg, 10%);
}
}
}
.c-super-menu {
@ -354,3 +430,161 @@ button {
}
}
/******************************************************** PALETTES */
.c-palette {
display: flex;
flex-flow: column nowrap;
&__items {
flex: 1 1 auto;
display: grid;
grid-template-columns: repeat(10, [col] auto );
grid-gap: 1px;
}
&__item {
$d: 16px;
border: 1px solid transparent;
cursor: pointer;
width: 16px; height: 16px;
transition: $transOut;
&:hover {
transition: $transIn;
$o: 0.7;
border-color: rgba($paletteItemBorderOuterColorSelected, $o);
box-shadow: inset rgba($paletteItemBorderInnerColorSelected, $o) 0 0 0 1px;
}
&.is-selected {
border-color: $paletteItemBorderOuterColorSelected !important;
border-width: 2px;
box-shadow: inset rgba($paletteItemBorderInnerColorSelected, 1) 0 0 0 1px;
}
}
&__item-none {
flex: 0 0 auto;
display: flex;
align-items: center;
margin-bottom: $interiorMarginSm;
.c-palette__item {
@include noColor();
border-color: $paletteItemBorderInnerColor;
margin-right: $interiorMarginSm;
}
}
}
/******************************************************** TOOLBAR */
.c-ctrl-wrapper {
@include cCtrlWrapper();
}
.c-toolbar,
.c-toolbar .c-ctrl-wrapper {
display: flex;
align-items: stretch;
}
.c-toolbar {
height: 24px; // Need to standardize the height
.c-click-icon {
@include cControl();
$pLR: $interiorMargin - 1;
$pTB: 2px;
color: $colorBodyFg;
padding: $pTB $pLR;
&--swatched {
padding-bottom: floor($pTB / 2);
width: 2em; // Standardize the width
}
&[class*='--caution'] {
&:before {
color: $colorBtnCautionBg;
}
&:hover {
background: rgba($colorBtnCautionBgHov, 0.2);
:before {
color: $colorBtnCautionBgHov;
}
}
}
}
.c-labeled-input {
font-size: 0.9em;
input[type='number'] {
width: 40px; // Number input sucks and must have size set using this method
}
+ .c-labeled-input {
margin-left: $interiorMargin;
}
}
}
/********* Button Sets */
.c-button-set {
// When one set is adjacent to another, provides a divider between
display: inline-flex;
flex: 0 0 auto;
> * {
// Assume buttons are immediate descendants
flex: 0 0 auto;
+ * {
// margin-left: $interiorMarginSm;
}
}
+ .c-button-set {
$m: $interiorMargin;
$b: 1px;
&:before {
content: '';
display: block;
width: $m + $b; // Allow for border
border-right: $b solid $colorInteriorBorder;
margin-right: $m;
}
}
&[class*='--strip'] {
// Buttons are smashed together with minimal margin
// c-buttons don't have border-radius between buttons, creates a tool-button-strip look
// c-click-icons get grouped more closely together
&[class^="c-button"] {
// Only apply the following to buttons that have background, eg. c-button
border-radius: 0;
+ * {
margin-left: 1px;
}
&:first-child {
border-top-left-radius: $controlCr;
border-bottom-left-radius: $controlCr;
}
&:last-child {
border-top-right-radius: $controlCr;
border-bottom-right-radius: $controlCr;
}
}
}
}
/***************************************************** SLIDERS */
.c-slider {
@include cControl();
> * + * { margin-left: $interiorMargin; }
}

View File

@ -118,22 +118,6 @@ em {
font-style: normal;
}
input, textarea {
font-family: inherit;
font-weight: inherit;
letter-spacing: inherit;
}
input[type=text],
input[type=search],
input[type=number] {
@include nice-input();
padding: $inputTextP;
&.numeric {
text-align: right;
}
}
h1, h2, h3 {
letter-spacing: 0.04em;
margin: 0;

View File

@ -53,6 +53,37 @@
background-size: $bgsize $bgsize;
}
@mixin noColor() {
// A "no fill/stroke" selection option. Used in palettes.
$c: red;
$s: 48%;
$e: 52%;
background-image: linear-gradient(-45deg,
transparent $s - 5%,
$c $s,
$c $e,
transparent $e + 5%
);
background-repeat: no-repeat;
background-size: contain;
}
@mixin bgTicks($c: $colorBodyFg, $repeatDir: 'x') {
$deg: 90deg;
@if ($repeatDir != 'x') {
$deg: 0deg;
$repeatDir: repeat-y;
} @else {
$repeatDir: repeat-x;
}
background-image: linear-gradient($deg,
$c 1px, transparent 1px,
transparent 100%
);
background-repeat: $repeatDir;
}
@mixin bgVertStripes($c: yellow, $a: 0.1, $d: 40px) {
@include background-image(linear-gradient(-90deg,
rgba($c, $a) 0%, rgba($c, $a) 50%,
@ -63,6 +94,11 @@
}
/************************** LAYOUT */
@mixin abs($m: 0) {
position: absolute;
top: $m; right: $m; bottom: $m; left: $m;
}
@mixin gridTwoColumn() {
display: grid;
grid-row-gap: 0;
@ -126,15 +162,28 @@
}
}
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.5) 0 0px 2px) {
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.5) 0 0 2px) {
@include input-base();
background: $bg;
color: $fg;
box-shadow: inset $shdw;
}
@mixin reactive-input($bg: $colorInputBg, $fg: $colorInputFg) {
@include input-base();
background: $bg;
box-shadow: $shdwInput;
color: $fg;
&:hover {
box-shadow: $shdwInputHov;
}
&:focus {
box-shadow: $shdwInputFoc;
}
}
@mixin button($bg: $colorBtnBg, $fg: $colorBtnFg, $radius: $controlCr, $shdw: none) {
background: $bg;
color: $fg;
@ -142,6 +191,63 @@
box-shadow: $shdw;
}
@mixin wrappedInput() {
// An input that is wrapped. Optionally includes a __label or icon element.
// Based on .c-search.
@include nice-input();
display: flex;
align-items: center;
padding-left: 4px;
padding-right: 4px;
&:before,
[class*='__label'] {
opacity: 0.5;
}
&:before {
// Adds an icon. Content defined in class.
direction: rtl; // Aligns glyph to right-hand side of container, for transition
display: block;
font-family: symbolsfont;
flex: 0 0 auto;
overflow: hidden;
padding: 2px 0; // Prevents clipping
transition: width 250ms ease;
width: 1em;
}
&:hover {
box-shadow: inset rgba(black, 0.8) 0 0px 2px;
&:before {
opacity: 0.9;
}
}
&--major {
padding: 4px;
}
&__input,
input[type='text'],
input[type='search'],
input[type='number'] {
background: none !important;
box-shadow: none !important; // !important needed to override default for [input]
flex: 1 1 auto;
padding-left: 2px !important;
padding-right: 2px !important;
min-width: 10px; // Must be set to allow input to collapse below browser min
}
&.is-active {
&:before {
padding: 2px 0px;
width: 0px;
}
}
}
/************************** MATH */
@function percentToDecimal($p) {
@return $p / 100%;
@ -161,4 +267,13 @@
@mixin userSelectNone() {
@include browserPrefix(user-select, none);
}
}
@mixin cursorGrab() {
cursor: grab;
cursor: -webkit-grab;
&:active {
cursor: grabbing;
cursor: -webkit-grabbing;
}
}

View File

@ -1,6 +1,6 @@
<template>
<div class="c-create-button--w">
<div class="c-create-button c-menu-button c-button--major icon-plus"
<div class="c-create-button c-button--menu c-button--major icon-plus"
@click="toggleCreateMenu">
<span class="c-button__label">Create</span>
</div>

View File

@ -1,7 +1,7 @@
<template>
<div class="l-browse-bar">
<div class="l-browse-bar__start">
<a class="l-browse-bar__nav-to-parent-button c-icon-button icon-pointer-left"></a>
<a class="l-browse-bar__nav-to-parent-button c-click-icon icon-pointer-left"></a>
<div class="l-browse-bar__object-name--w"
:class="type.cssClass">
<span
@ -15,9 +15,9 @@
</div>
<div class="l-browse-bar__end">
<div class="l-browse-bar__view-switcher c-menu-button--w c-menu-button--menus-left"
<div class="l-browse-bar__view-switcher c-ctrl-wrapper c-ctrl-wrapper--menus-left"
v-if="views.length > 1">
<div class="c-menu-button"
<div class="c-button--menu"
:class="currentView.cssClass"
title="Switch view type"
@click="toggleViewMenu">

View File

@ -3,11 +3,11 @@
<div class="l-shell__head">
<CreateButton class="l-shell__create-button"></CreateButton>
<div class="l-shell__controls">
<a class="c-icon-button icon-new-window" title="Open in a new browser tab"
<a class="c-click-icon icon-new-window" title="Open in a new browser tab"
@click="openInNewTab"
target="_blank">
</a>
<a v-bind:class="['c-icon-button', fullScreen ? 'icon-fullscreen-expand' : 'icon-fullscreen-collapse']"
<a v-bind:class="['c-click-icon', fullScreen ? 'icon-fullscreen-expand' : 'icon-fullscreen-collapse']"
v-bind:title="`${fullScreen ? 'Exit' : 'Enable'} full screen mode`"
@click="fullScreenToggle">
</a>
@ -179,7 +179,7 @@
&__time-conductor {
border-top: 1px solid $colorInteriorBorder;
flex: 0 0 auto;
padding: $interiorMargin;
padding-top: $interiorMargin;
}
body.desktop & {