First version of design system

* Add SPOT foundation styles

* Initial work on buttons

* Implement basic examples page

* Improve spot-checkbox

* Add outline buttons in HTML

* Checkbox works

* Add filter chips

* Initial text field implementation

* Chip field initial implementation, add filter-chip component

* Keep old styleguide page

* Add drop modal component

* Finish checkbox list

* Improve action bar

* Add drop modal alignment options

* Fix drop modal zindex

* Make sure clicks do not close the drop modal, add escape closing event for drop modal

* Add spot-body

* Don't hide drop modal body via display

* Update buttons and colors

* Add basic button type

* Set line height for typography styles

* Add basic toggle component

* Better docs

* Fix toggle font size

* Add current date color

* Fix names for form components

* Fix package-lock.json

Co-authored-by: Henriette Darge <h.darge@openproject.com>
Co-authored-by: Oliver Günther <mail@oliverguenther.de>
pull/10198/head
Benjamin Bädorf 3 years ago committed by GitHub
parent daf1a5fa07
commit 2f99c9f5ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      config/routes.rb
  2. 1260
      frontend/package-lock.json
  3. 5
      frontend/package.json
  4. 3
      frontend/src/app/app.module.ts
  5. 7
      frontend/src/app/shared/components/option-list/option-list.component.ts
  6. 10
      frontend/src/app/spot/components/checkbox.component.html
  7. 69
      frontend/src/app/spot/components/checkbox.component.ts
  8. 30
      frontend/src/app/spot/components/chip-field.component.html
  9. 94
      frontend/src/app/spot/components/chip-field.component.ts
  10. 8
      frontend/src/app/spot/components/drop-modal.component.html
  11. 74
      frontend/src/app/spot/components/drop-modal.component.ts
  12. 7
      frontend/src/app/spot/components/filter-chip.component.html
  13. 20
      frontend/src/app/spot/components/filter-chip.component.ts
  14. 10
      frontend/src/app/spot/components/text-field.component.html
  15. 60
      frontend/src/app/spot/components/text-field.component.ts
  16. 13
      frontend/src/app/spot/components/toggle.component.html
  17. 59
      frontend/src/app/spot/components/toggle.component.ts
  18. 215
      frontend/src/app/spot/spot-docs.component.html
  19. 35
      frontend/src/app/spot/spot-docs.component.ts
  20. 40
      frontend/src/app/spot/spot.module.ts
  21. 41
      frontend/src/app/spot/spot.routes.ts
  22. 26
      frontend/src/app/spot/styles/sass/blocks/action-bar.sass
  23. 13
      frontend/src/app/spot/styles/sass/blocks/body.sass
  24. 182
      frontend/src/app/spot/styles/sass/blocks/button.sass
  25. 62
      frontend/src/app/spot/styles/sass/blocks/checkbox.sass
  26. 7
      frontend/src/app/spot/styles/sass/blocks/chip-field.sass
  27. 43
      frontend/src/app/spot/styles/sass/blocks/drop-modal.sass
  28. 24
      frontend/src/app/spot/styles/sass/blocks/filter-chip.sass
  29. 12
      frontend/src/app/spot/styles/sass/blocks/index.sass
  30. 28
      frontend/src/app/spot/styles/sass/blocks/list.sass
  31. 32
      frontend/src/app/spot/styles/sass/blocks/text-field.sass
  32. 44
      frontend/src/app/spot/styles/sass/blocks/toggle.sass
  33. 4
      frontend/src/app/spot/styles/sass/index.sass
  34. 48
      frontend/src/app/spot/styles/sass/typography.sass
  35. 1
      frontend/src/app/spot/styles/sass/variables.sass
  36. 6
      frontend/src/app/spot/styles/sass/zindex.sass
  37. 66
      frontend/src/app/spot/styles/tokens/colors.yml
  38. 57
      frontend/src/app/spot/styles/tokens/dist/tokens.json
  39. 56
      frontend/src/app/spot/styles/tokens/dist/tokens.sass
  40. 18
      frontend/src/app/spot/styles/tokens/shadows.yml
  41. 47
      frontend/src/app/spot/styles/tokens/spacings.yml
  42. 4
      frontend/src/app/spot/styles/tokens/tokens.yml
  43. 1
      frontend/src/global_styles/openproject.sass
  44. 3
      nix/shell.nix

@ -583,6 +583,7 @@ OpenProject::Application.routes.draw do
# Development route for styleguide # Development route for styleguide
if Rails.env.development? if Rails.env.development?
get '/spot-docs', to: 'angular#empty_layout'
get '/styleguide' => redirect('/assets/styleguide.html') get '/styleguide' => redirect('/assets/styleguide.html')
end end
end end

File diff suppressed because it is too large Load Diff

@ -23,6 +23,7 @@
"@types/jquery": "^3.3.33", "@types/jquery": "^3.3.33",
"@types/jqueryui": "^1.12.10", "@types/jqueryui": "^1.12.10",
"@types/lodash": "^4.14.149", "@types/lodash": "^4.14.149",
"@types/mime": "^2.0.3",
"@types/moment-timezone": "^0.5.12", "@types/moment-timezone": "^0.5.12",
"@types/mousetrap": "^1.6.3", "@types/mousetrap": "^1.6.3",
"@types/pako": "^1.0.1", "@types/pako": "^1.0.1",
@ -33,7 +34,6 @@
"@typescript-eslint/eslint-plugin": "4.23.0", "@typescript-eslint/eslint-plugin": "4.23.0",
"@typescript-eslint/parser": "4.23.0", "@typescript-eslint/parser": "4.23.0",
"browserslist": "^4.9.1", "browserslist": "^4.9.1",
"@types/mime": "^2.0.3",
"codelyzer": "^6.0.0", "codelyzer": "^6.0.0",
"eslint": "^7.26.0", "eslint": "^7.26.0",
"eslint-config-airbnb-base": "^14.2.1", "eslint-config-airbnb-base": "^14.2.1",
@ -54,7 +54,9 @@
"karma-jasmine": "~3.3.0", "karma-jasmine": "~3.3.0",
"karma-jasmine-html-reporter": "^1.5.0", "karma-jasmine-html-reporter": "^1.5.0",
"karma-spec-reporter": "^0.0.32", "karma-spec-reporter": "^0.0.32",
"optimist": "^0.6.1",
"source-map-explorer": "^2.5.2", "source-map-explorer": "^2.5.2",
"theo": "^8.1.5",
"ts-node": "~8.3.0", "ts-node": "~8.3.0",
"typescript": "~4.2.4", "typescript": "~4.2.4",
"webpack-bundle-analyzer": "^4.4.2" "webpack-bundle-analyzer": "^4.4.2"
@ -143,6 +145,7 @@
"prebuild": "./scripts/link_plugin_placeholder.js", "prebuild": "./scripts/link_plugin_placeholder.js",
"build": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --configuration production --named-chunks --extract-css --source-map", "build": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --configuration production --named-chunks --extract-css --source-map",
"build:watch": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --watch --named-chunks --extract-css", "build:watch": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --watch --named-chunks --extract-css",
"tokens:generate": "theo src/app/spot/styles/tokens/tokens.yml --transform web --format sass,json --dest src/app/spot/styles/tokens/dist",
"preserve": "./scripts/link_plugin_placeholder.js", "preserve": "./scripts/link_plugin_placeholder.js",
"serve": "NG_PERSISTENT_BUILD_CACHE=1 node --max_old_space_size=8096 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --public-host http://localhost:4200", "serve": "NG_PERSISTENT_BUILD_CACHE=1 node --max_old_space_size=8096 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --public-host http://localhost:4200",
"serve:test": "NG_PERSISTENT_BUILD_CACHE=1 node --max_old_space_size=8096 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --disable-host-check --public-host http://frontend-test:4200", "serve:test": "NG_PERSISTENT_BUILD_CACHE=1 node --max_old_space_size=8096 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --disable-host-check --public-host http://frontend-test:4200",

@ -37,6 +37,7 @@ import { OpContextMenuTrigger } from 'core-app/shared/components/op-context-menu
import { States } from 'core-app/core/states/states.service'; import { States } from 'core-app/core/states/states.service';
import { OpenprojectFieldsModule } from 'core-app/shared/components/fields/openproject-fields.module'; import { OpenprojectFieldsModule } from 'core-app/shared/components/fields/openproject-fields.module';
import { OPSharedModule } from 'core-app/shared/shared.module'; import { OPSharedModule } from 'core-app/shared/shared.module';
import { OpSpotModule } from 'core-app/spot/spot.module';
import { OpDragScrollDirective } from 'core-app/shared/directives/op-drag-scroll/op-drag-scroll.directive'; import { OpDragScrollDirective } from 'core-app/shared/directives/op-drag-scroll/op-drag-scroll.directive';
import { DynamicBootstrapper } from 'core-app/core/setup/globals/dynamic-bootstrapper'; import { DynamicBootstrapper } from 'core-app/core/setup/globals/dynamic-bootstrapper';
import { OpenprojectWorkPackagesModule } from 'core-app/features/work-packages/openproject-work-packages.module'; import { OpenprojectWorkPackagesModule } from 'core-app/features/work-packages/openproject-work-packages.module';
@ -109,6 +110,8 @@ export function initializeServices(injector:Injector) {
BrowserModule, BrowserModule,
// Commons // Commons
OPSharedModule, OPSharedModule,
// Design System
OpSpotModule,
// State module // State module
OpenProjectStateModule, OpenProjectStateModule,
// Router module // Router module

@ -1,5 +1,10 @@
import { import {
Component, EventEmitter, forwardRef, HostBinding, Input, Output, Component,
EventEmitter,
forwardRef,
HostBinding,
Input,
Output,
} from '@angular/core'; } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@ -0,0 +1,10 @@
<input
type="checkbox"
class="spot-checkbox--input"
[attr.name]="name"
[disabled]="disabled"
[checked]="checked"
(change)="onStateChange()"
#input
/>
<span class="spot-checkbox--fake"></span>

@ -0,0 +1,69 @@
import {
Component,
ElementRef,
EventEmitter,
ViewChild,
forwardRef,
HostBinding,
Input,
Output,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
export type SpotCheckboxState = true|false|null;
@Component({
selector: 'spot-checkbox',
templateUrl: './checkbox.component.html',
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SpotCheckboxComponent),
multi: true,
}],
})
export class SpotCheckboxComponent implements ControlValueAccessor {
@HostBinding('class.spot-checkbox') public className = true;
@ViewChild('input') public input:ElementRef;
@Input() disabled = false;
@Input() name = `spot-checkbox-${+(new Date())}`;
@Output() checkedChange = new EventEmitter<boolean>();
@Input() public checked = false;
onStateChange() {
const value = this.input.nativeElement.checked;
this.checkedChange.emit(value);
this.onChange(value);
this.onTouched(value);
}
writeValue(value:SpotCheckboxState) {
// This is set in a timeout because the initial value is set before the template is ready,
// which causes the input nativeElement to not be available yet.
setTimeout(() => {
const input = this.input.nativeElement;
if (value === null) {
input.indeterminate = true;
} else {
input.indeterminate = false;
}
this.checked = !!value;
});
}
onChange = (_:SpotCheckboxState) => {};
onTouched = (_:SpotCheckboxState) => {};
registerOnChange(fn:any) {
this.onChange = fn;
}
registerOnTouched(fn:any) {
this.onTouched = fn;
}
}

@ -0,0 +1,30 @@
<!--
Normally I'd just wrap a spot-text-field here
but because Angular is trash we'd increase HTML nesting,
making it harder to write clean CSS.
-->
<ng-content select="[slot=before]"></ng-content>
<div class="spot-chip-field--values">
<spot-filter-chip
class="spot-filter-chip spot-chip-field--value"
*ngFor="let item of value; index as i"
(remove)="remove(i)"
[title]="item"
></spot-filter-chip>
</div>
<input
class="spot-text-field--input"
[attr.name]="name"
[disabled]="disabled"
[placeholder]="placeholder"
[(ngModel)]="textValue"
(keydown.enter)="onEnter($event)"
(keydown.backspace)="onBackspace($event)"
#input
/>
<ng-content select="[slot=after]"></ng-content>

@ -0,0 +1,94 @@
import {
Component,
ElementRef,
ViewChild,
forwardRef,
HostBinding,
HostListener,
Input,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'spot-chip-field',
templateUrl: './chip-field.component.html',
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SpotChipFieldComponent),
multi: true,
}],
})
export class SpotChipFieldComponent implements ControlValueAccessor {
@HostBinding('class.spot-chip-field') public classNameChipField = true;
@HostBinding('class.spot-text-field') public classNameTextField = true;
@HostListener('click') public onParentClick() {
this.input.nativeElement.focus();
}
@ViewChild('input') public input:ElementRef;
@Input() name = `spot-chip-field-${+(new Date())}`;
@Input() disabled = false;
@Input() public placeholder = '';
@Input('value') public _value:string[] = [];
public textValue = '';
public get value():string[] {
return this._value;
}
public set value(value:string[]) {
this._value = value;
this.onChange(value);
this.onTouched(value);
}
public remove(i:number) {
this.value = this.value.slice(0, i).concat(this.value.slice(i + 1));
}
public onBackspace(e:KeyboardEvent) {
if (this.textValue !== '') {
return;
}
e.preventDefault();
this.value = this.value.slice(0, this.value.length - 1);
}
public onEnter(e:KeyboardEvent) {
e.stopPropagation();
if (this.textValue === '') {
return;
}
e.preventDefault();
this.value = [
...this.value,
this.textValue,
];
this.textValue = '';
}
writeValue(value:string[]) {
this.value = value;
}
onChange = (_:string[]) => {};
onTouched = (_:string[]) => {};
registerOnChange(fn:any) {
this.onChange = fn;
}
registerOnTouched(fn:any) {
this.onTouched = fn;
}
}

@ -0,0 +1,8 @@
<ng-content select="[slot=trigger]"></ng-content>
<div
[ngClass]="['spot-drop-modal--body', 'spot-body', alignmentClass]"
(click)="onBodyClick($event)"
(keypress.escape)="close()"
>
<ng-content select="[slot=body]"></ng-content>
</div>

@ -0,0 +1,74 @@
import {
Component,
HostBinding,
Input,
Output,
EventEmitter,
OnDestroy,
} from '@angular/core';
enum SpotDropModalAlignmentOption {
BottomCenter = 'bottom-center',
BottomLeft = 'bottom-left',
BottomRight = 'bottom-right',
TopCenter = 'top-center',
TopLeft = 'top-left',
TopRight = 'top-right',
}
@Component({
selector: 'spot-drop-modal',
templateUrl: './drop-modal.component.html',
})
export class SpotDropModalComponent implements OnDestroy {
@HostBinding('class.spot-drop-modal') public className = true;
@HostBinding('class.spot-drop-modal_opened') public _open = false;
@Input('open')
public set open(value:boolean) {
this._open = value;
if (this._open) {
/* We have to set these listeners next tick, because they're so far up the tree.
* If the open value was set because of a click listener in the trigger slot,
* that event would reach the event listener added here and close the modal right away.
*/
setTimeout(() => {
document.body.addEventListener('click', this.closeEventListener);
})
} else {
document.body.removeEventListener('click', this.closeEventListener);
this.closed.emit();
}
}
public get open():boolean {
return this._open;
}
@Input('alignment') public alignment:SpotDropModalAlignmentOption = SpotDropModalAlignmentOption.BottomCenter;
get alignmentClass() {
return `spot-drop-modal--body_${this.alignment}`;
}
@Output() closed = new EventEmitter<void>();
private closeEventListener = this.close.bind(this);
public close():void {
this.open = false;
}
public onBodyClick(e:MouseEvent) {
// We stop propagation here so that clicks inside the body do not
// close the modal when the event reaches the document body
e.stopPropagation();
}
public ngOnDestroy():void {
document.body.removeEventListener('click', this.closeEventListener);
}
}

@ -0,0 +1,7 @@
<button
*ngIf="removable"
class="spot-filter-chip--remove"
type="button"
(click)="remove.emit()"
>x</button>
<div class="spot-filter-chip--title">{{ title }}</div>

@ -0,0 +1,20 @@
import {
Component,
EventEmitter,
HostBinding,
Input,
Output,
} from '@angular/core';
@Component({
selector: 'spot-filter-chip',
templateUrl: './filter-chip.component.html',
})
export class SpotFilterChipComponent {
@HostBinding('class.spot-filter-chip') public className = true;
@Input() removable = true;
@Input() title = '';
@Output() remove = new EventEmitter<void>();
}

@ -0,0 +1,10 @@
<ng-content select="[slot=before]"></ng-content>
<input
class="spot-text-field--input"
[attr.name]="name"
[disabled]="disabled"
[placeholder]="placeholder"
[(ngModel)]="value"
#input
/>
<ng-content select="[slot=after]"></ng-content>

@ -0,0 +1,60 @@
import {
Component,
ElementRef,
ViewChild,
forwardRef,
HostBinding,
HostListener,
Input,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'spot-text-field',
templateUrl: './text-field.component.html',
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SpotTextFieldComponent),
multi: true,
}],
})
export class SpotTextFieldComponent implements ControlValueAccessor {
@HostBinding('class.spot-text-field') public className = true;
@HostListener('click') public onParentClick() {
this.input.nativeElement.focus();
}
@ViewChild('input') public input:ElementRef;
@Input() name = `spot-text-field-${+(new Date())}`;
@Input() disabled = false;
@Input() public placeholder = '';
@Input('value') public _value = '';
public get value():string {
return this._value;
}
public set value(value:string) {
this._value = value;
this.onChange(value);
this.onTouched(value);
}
writeValue(value:string) {
this.value = value;
}
onChange = (_:string) => {};
onTouched = (_:string) => {};
registerOnChange(fn:any) {
this.onChange = fn;
}
registerOnTouched(fn:any) {
this.onTouched = fn;
}
}

@ -0,0 +1,13 @@
<label
*ngFor="let option of options"
[ngClass]="{ 'spot-toggle--option': true, 'spot-toggle--option_selected': value === option.value }"
>
<input
class="spot-toggle--option-input"
type="radio"
[name]="name"
[value]="option.value"
[(ngModel)]="value"
/>
{{ option.title }}
</label>

@ -0,0 +1,59 @@
import {
Component,
EventEmitter,
forwardRef,
HostBinding,
Input,
Output,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
export interface SpotToggleOption<T> {
value:T;
title:string;
};
@Component({
selector: 'spot-toggle',
templateUrl: './toggle.component.html',
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SpotToggleComponent),
multi: true,
}],
})
export class SpotToggleComponent<T> implements ControlValueAccessor {
@HostBinding('class.spot-toggle') public className = true;
@Output() checkedChange = new EventEmitter<boolean>();
@Input() options:SpotToggleOption<T>[] = [];
@Input() name = `spot-toggle-${+(new Date())}`;
@Input('value') public _value:T;
public get value():T {
return this._value;
}
public set value(value:T) {
this._value = value;
this.onChange(value);
this.onTouched(value);
}
writeValue(value:T) {
this.value = value;
}
onChange = (_:T) => {};
onTouched = (_:T) => {};
registerOnChange(fn:any) {
this.onChange = fn;
}
registerOnTouched(fn:any) {
this.onTouched = fn;
}
}

@ -0,0 +1,215 @@
<h1>Buttons</h1>
<button class="spot-button">Default</button>
<button class="spot-button spot-button_main">Main</button>
<button class="spot-button spot-button_accent">Accent</button>
<button class="spot-button spot-button_danger">Danger</button>
<button class="spot-button" disabled>Disabled</button>
<hr>
<button class="spot-button spot-button_outlined">Default</button>
<button class="spot-button spot-button_outlined spot-button_main">Main</button>
<button class="spot-button spot-button_outlined spot-button_accent">Accent</button>
<button class="spot-button spot-button_outlined spot-button_danger">Danger</button>
<button class="spot-button spot-button_outlined" disabled>Disabled</button>
<hr>
<button class="spot-button spot-button_basic">Default</button>
<button class="spot-button spot-button_basic spot-button_main">Main</button>
<button class="spot-button spot-button_basic spot-button_accent">Accent</button>
<button class="spot-button spot-button_basic spot-button_danger">Danger</button>
<button class="spot-button spot-button_basic" disabled>Disabled</button>
<h1>Toggles</h1>
<spot-toggle
[options]="toggleOptions"
[(ngModel)]="toggleValue"
></spot-toggle>
Currently selected value is {{ toggleValue }}
<h1>Checkbox</h1>
<label>
<spot-checkbox></spot-checkbox> Unchecked
</label>
<label>
<spot-checkbox [checked]="true"></spot-checkbox> Checked
</label>
<label>
<spot-checkbox [disabled]="true"></spot-checkbox> Disabled
</label>
<label>
<spot-checkbox
[checked]="true"
[disabled]="true"
></spot-checkbox> Disabled checked
</label>
<label>
<spot-checkbox [(ngModel)]="checkboxValue"></spot-checkbox>
Currently {{ checkboxValueString() }}
</label>
<label>
<spot-checkbox
[(ngModel)]="checkboxValue"
[disabled]="true"
name="checkbox-name"
></spot-checkbox>
Currently {{ checkboxValueString() }}
</label>
<h1>Lists</h1>
<ul class="spot-list">
<li class="spot-list--item">
<label class="spot-list--item-action">
<spot-checkbox [(ngModel)]="checkboxValue"></spot-checkbox>
<div class="spot-list--item-title">Checkbox item</div>
</label>
</li>
<li class="spot-list--item">
<label class="spot-list--item-action">
<spot-checkbox [(ngModel)]="checkboxValue"></spot-checkbox>
<div class="spot-list--item-title">Checkbox item with children</div>
</label>
<ul class="spot-list">
<li class="spot-list--item">
<label class="spot-list--item-action">
<spot-checkbox [(ngModel)]="checkboxValue"></spot-checkbox>
<div class="spot-list--item-title">Child checkbox item</div>
</label>
</li>
<li class="spot-list--item">
<label class="spot-list--item-action">
<spot-checkbox [(ngModel)]="checkboxValue"></spot-checkbox>
<div class="spot-list--item-title">Second child checkbox item</div>
</label>
</li>
</ul>
</li>
</ul>
<h1>Filter Chip</h1>
<spot-filter-chip
title="Default chip"
(remove)="onRemoveChip()"
></spot-filter-chip>
<spot-filter-chip
[removable]="false"
title="Unremovable chip"
></spot-filter-chip>
<h1>Text Field</h1>
<input
class="spot-text-field"
placeholder="Placeholder value"
/>
<input
class="spot-text-field"
value="Test value"
/>
<spot-text-field
placeholder="Placeholder value"
value="Test value"
name="textfield-name"
></spot-text-field>
<spot-text-field
placeholder="Placeholder value"
[(ngModel)]="textFieldValue"
></spot-text-field>
<spot-text-field
placeholder="Placeholder value"
[(ngModel)]="textFieldValue"
>
<span
slot="after"
class="op-icon icon-bell"
></span>
</spot-text-field>
<spot-text-field
placeholder="Placeholder value"
[(ngModel)]="textFieldValue"
>
<span
slot="before"
class="op-icon icon-bell"
></span>
<span
slot="after"
class="op-icon icon-bell"
></span>
</spot-text-field>
<spot-text-field
placeholder="Placeholder value"
[(ngModel)]="textFieldValue"
>
<span
slot="before"
class="op-icon icon-bell"
></span>
</spot-text-field>
<h1>Chip Field</h1>
<spot-chip-field
placeholder="Type and press enter"
></spot-chip-field>
<h1>Drop Modal</h1>
<select [(ngModel)]="alignment">
<option>bottom-center</option>
<option>bottom-left</option>
<option>bottom-right</option>
<option>top-center</option>
<option>top-left</option>
<option>top-right</option>
</select>
<spot-drop-modal
[open]="dropModalOpen"
[alignment]="alignment"
(closed)="dropModalOpen = false"
>
<button
slot="trigger"
type="button"
class="spot-button spot-button_main"
(click)="dropModalOpen = !dropModalOpen"
>Open Modal</button>
<ng-container slot="body">
<h1>Test</h1>
</ng-container>
</spot-drop-modal>
<h1>Action Bar</h1>
<div class="spot-action-bar">
<div class="spot-action-bar--left">
<button class="spot-button spot-button_outlined spot-button_main">
Independent action
</button>
</div>
<div class="spot-action-bar--right">
<button class="spot-button spot-button_outlined spot-button_main">
Some Action
</button>
<button class="spot-button spot-button_main">
Another Action
</button>
</div>
</div>

@ -0,0 +1,35 @@
import { Component } from '@angular/core';
@Component({
selector: 'spot-docs',
templateUrl: './spot-docs.component.html',
})
export class SpotDocsComponent {
indeterminateState = null;
checkboxValue = null;
textFieldValue = 'ngModel value';
dropModalOpen = false;
alignment = 'bottom-center';
toggleValue = null;
toggleOptions = [
{value: 1, title: '1'},
{value: 2, title: '2'}
];
onRemoveChip() {
alert('Remove chip');
}
checkboxValueString() {
if (this.checkboxValue === null) {
return 'null (indeterminate)';
}
if (this.checkboxValue) {
return 'true (checked)';
}
return 'false (unchecked)';
}
}

@ -0,0 +1,40 @@
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { UIRouterModule } from '@uirouter/angular';
import { SPOT_DOCS_ROUTES } from './spot.routes';
import { SpotCheckboxComponent } from './components/checkbox.component';
import { SpotToggleComponent } from './components/toggle.component';
import { SpotTextFieldComponent } from './components/text-field.component';
import { SpotFilterChipComponent } from './components/filter-chip.component';
import { SpotChipFieldComponent } from './components/chip-field.component';
import { SpotDropModalComponent } from './components/drop-modal.component';
import { SpotDocsComponent } from './spot-docs.component';
@NgModule({
imports: [
// Routes for /spot-docs
UIRouterModule.forChild({ states: SPOT_DOCS_ROUTES }),
FormsModule,
CommonModule,
],
declarations: [
SpotDocsComponent,
SpotCheckboxComponent,
SpotToggleComponent,
SpotTextFieldComponent,
SpotFilterChipComponent,
SpotChipFieldComponent,
SpotDropModalComponent,
],
exports: [
SpotCheckboxComponent,
SpotToggleComponent,
SpotTextFieldComponent,
SpotFilterChipComponent,
SpotChipFieldComponent,
SpotDropModalComponent,
],
})
export class OpSpotModule { }

@ -0,0 +1,41 @@
// -- copyright
// OpenProject is an open source project management software.
// Copyright (C) 2012-2021 the OpenProject GmbH
//
// 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-2013 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 COPYRIGHT and LICENSE files for more details.
//++
import { Ng2StateDeclaration } from '@uirouter/angular';
import { SpotDocsComponent } from './spot-docs.component';
export const SPOT_DOCS_ROUTES:Ng2StateDeclaration[] = [
{
name: 'styleguide',
parent: 'root',
url: '/spot-docs',
views: {
'!$default': { component: SpotDocsComponent },
},
},
];

@ -0,0 +1,26 @@
.spot-action-bar
display: flex
flex-direction: row
flex-wrap: nowrap
justify-content: space-between
padding: $spot-spacing-0_75
background-color: $spot-color-basic-gray-6
&--left,
&--right
display: flex
flex-direction: row
flex-wrap: wrap
align-items: center
&--left
justify-content: flex-start
> *:not(:last-child)
margin-right: $spot-spacing-1
&--right
justify-content: flex-end
> *:not(:first-child)
margin-left: $spot-spacing-1

@ -0,0 +1,13 @@
.spot-body
display: flex
flex-direction: column
> .spot-text-field,
> .spot-list
margin: $spot-spacing-0_5
&:first-child
margin-top: $spot-spacing-1
&:last-child
margin-bottom: $spot-spacing-1

@ -0,0 +1,182 @@
.spot-button
@include spot-body-small
display: inline-flex
flex-direction: row
flex-wrap: nowrap
margin: 0
padding: $spot-spacing-0_5
border-width: 1px
border-style: solid
border-radius: $spot-spacing-1
border-color: $spot-color-basic-white
background-color: $spot-color-basic-white
color: $spot-color-main
cursor: pointer
&, *
box-sizing: border-box
&:hover
background-color: $spot-color-basic-gray-6
border-color: $spot-color-basic-gray-6
color: $spot-color-main-dark
&:active
background-color: $spot-color-basic-gray-6
border-color: $spot-color-basic-gray-6
color: $spot-color-main
&_main
border-color: $spot-color-main
background-color: $spot-color-main
color: $spot-color-basic-white
&:hover
border-color: $spot-color-main-light
background-color: $spot-color-main-light
color: $spot-color-main-dark
&:active
border-color: $spot-color-main-light
background-color: $spot-color-main-light
color: $spot-color-main
&_accent
border-color: $spot-color-accent
background-color: $spot-color-accent
color: $spot-color-basic-white
&:hover
border-color: $spot-color-accent-light
background-color: $spot-color-accent-light
color: $spot-color-accent-dark
&:active
border-color: $spot-color-accent-light
background-color: $spot-color-accent-light
color: $spot-color-accent
&_danger
border-color: $spot-color-danger
background-color: $spot-color-danger
color: $spot-color-basic-white
&:hover
border-color: $spot-color-danger-light
background-color: $spot-color-danger-light
color: $spot-color-danger-dark
&:active
border-color: $spot-color-danger-light
background-color: $spot-color-danger-light
color: $spot-color-danger
&[disabled],
&_disabled
&,
&:hover,
&:active
border-color: $spot-color-basic-gray-4
background-color: $spot-color-basic-gray-4
color: $spot-color-basic-white
cursor: default
&_outlined
background-color: transparent
border-color: $spot-color-basic-white
color: $spot-color-basic-white
&:hover
background-color: $spot-color-basic-gray-6
border-color: $spot-color-main
color: $spot-color-main
&:active
background-color: $spot-color-basic-white
border-color: $spot-color-basic-white
color: $spot-color-main
&_outlined#{&}_main
background-color: transparent
border-color: $spot-color-main
color: $spot-color-main
&:hover
background-color: $spot-color-main-light
border-color: $spot-color-main
color: $spot-color-main
&:active
background-color: $spot-color-main
border-color: $spot-color-basic-white
color: $spot-color-basic-white
&_outlined#{&}_accent
background-color: transparent
border-color: $spot-color-accent
color: $spot-color-accent
&:hover
background-color: $spot-color-accent-light
border-color: $spot-color-accent
color: $spot-color-accent
&:active
background-color: $spot-color-accent
border-color: $spot-color-basic-white
color: $spot-color-basic-white
&_outlined#{&}_danger
background-color: transparent
border-color: $spot-color-danger
color: $spot-color-danger
&:hover
background-color: $spot-color-danger-light
border-color: $spot-color-danger
color: $spot-color-danger
&:active
background-color: $spot-color-danger
border-color: $spot-color-basic-white
color: $spot-color-basic-white
&_basic
background-color: transparent
border-color: transparent
color: $spot-color-basic-white
&:hover,
&:active
background-color: transparent
border-color: transparent
color: $spot-color-main
&_basic#{&}_main
color: $spot-color-main
&:hover
color: $spot-color-main-dark
&:active
color: $spot-color-main
&_basic#{&}_accent
color: $spot-color-accent
&:hover
color: $spot-color-accent-dark
&:active
color: $spot-color-accent
&_basic#{&}_danger
color: $spot-color-danger
&:hover
color: $spot-color-danger-dark
&:active
color: $spot-color-danger

@ -0,0 +1,62 @@
.spot-checkbox
display: inline-flex
justify-content: center
align-items: center
height: $spot-spacing-1_5
width: $spot-spacing-1_5
&, *
box-sizing: border-box
&--input
position: absolute
height: 1px
width: 1px
overflow: hidden
clip: rect(1px,1px,1px,1px)
&--fake
box-sizing: border-box
display: flex
justify-content: center
align-items: center
height: $spot-spacing-1
width: $spot-spacing-1
border-radius: 3px
border: 1px solid $spot-color-main
cursor: pointer
&::before,
&::after
display: block
content: ''
&--input:indeterminate + &--fake::before
width: 8px
height: 2px
background-color: $spot-color-main
&--input:checked + &--fake::before,
&--input:checked + &--fake::after
border-radius: 1px
position: absolute
&--input:checked + &--fake::before
width: 2px
height: 5px
background-color: $spot-color-main
transform: translateX(-2.3px) translateY(1.4px) rotate(-40deg)
&--input:checked + &--fake::after
width: 8px
height: 2px
background-color: $spot-color-main
transform: translateX(1px) rotate(-45deg)
&--input:disabled + &--fake
border-color: $spot-color-basic-gray-3
cursor: default
&--input:disabled + &--fake::before,
&--input:disabled + &--fake::after
background-color: $spot-color-basic-gray-3

@ -0,0 +1,7 @@
.spot-chip-field
&--values
display: flex
&--value
&:not(:last-child)
margin-right: $spot-spacing-0_5

@ -0,0 +1,43 @@
.spot-drop-modal
position: relative
display: inline-flex
&--body
@include spot-z-index("drop-modal")
box-shadow: $spot-shadow-light-mid
position: absolute
background: $spot-color-basic-white
border-radius: 5px
pointer-events: none
opacity: 0
&_bottom-center
top: 100%
left: 50%
transform: translateX(-50%)
&_bottom-left
top: 100%
left: 0%
&_bottom-right
top: 100%
right: 0%
&_top-center
bottom: 100%
left: 50%
transform: translateX(-50%)
&_top-left
bottom: 100%
left: 0%
&_top-right
bottom: 100%
right: 0%
&_opened &--body
pointer-events: all
opacity: 1

@ -0,0 +1,24 @@
.spot-filter-chip
@include spot-caption
display: inline-flex
align-items: center
flex-wrap: nowrap
background-color: $spot-color-main-light
color: $spot-color-basic-gray-1
border-radius: 5px
&--remove
display: flex
justify-content: center
align-items: center
border: 0
border-right: 1px solid rgba($spot-color-main, 0.5)
background: transparent
cursor: pointer
padding: $spot-spacing-0_25
&--title
padding: $spot-spacing-0_25

@ -0,0 +1,12 @@
// This directory will hold files that implement the styles for specific blocks and components
// Import them here
@import './button'
@import './toggle'
@import './checkbox'
@import './text-field'
@import './filter-chip'
@import './chip-field'
@import './drop-modal'
@import './list'
@import './action-bar'
@import './body'

@ -0,0 +1,28 @@
.spot-list
display: flex
flex-direction: column
list-style: none
margin: 0
&--item
display: flex
flex-direction: column
&-action
display: flex
align-items: center
justify-content: flex-start
padding: $spot-spacing-0_5
background-color: transparent
margin: 0
border: 0
cursor: pointer
&-title
&:not(:first-child)
margin-left: $spot-spacing-0_5
&:not(:last-child)
margin-left: $spot-spacing-0_5
.spot-list
margin-left: $spot-spacing-1_5

@ -0,0 +1,32 @@
.spot-text-field
@include spot-body-small
border: 1px solid $spot-color-basic-gray-3
color: $spot-color-basic-black
border-radius: 4px
padding: $spot-spacing-0_5
background-color: $spot-color-basic-white
display: inline-flex
justify-content: center
align-items: center
&::placeholder
color: $spot-color-basic-gray-3
&:focus,
&:focus-within
border-color: $spot-color-main-dark
color: $spot-color-main-dark
&--input
background: transparent
border: 0
padding: 0
flex-grow: 1
outline: 0
&:not(:first-child)
margin-left: $spot-spacing-0_5
&:not(:last-child)
margin-right: $spot-spacing-0_5

@ -0,0 +1,44 @@
.spot-toggle
display: flex
border: 0
margin: 0
padding: 0
&--option
@include spot-body-small
display: flex
flex-direction: row
flex-wrap: nowrap
margin: 0
padding: $spot-spacing-0_5
border-width: 1px
border-style: solid
border-color: $spot-color-main
background-color: transparent
color: $spot-color-main
cursor: pointer
&:not(:last-child)
border-right: 0
&:first-child
padding-left: $spot-spacing-0_75
border-top-left-radius: $spot-spacing-1
border-bottom-left-radius: $spot-spacing-1
&:last-child
padding-right: $spot-spacing-0_75
border-top-right-radius: $spot-spacing-1
border-bottom-right-radius: $spot-spacing-1
&_selected
background-color: $spot-color-main-light
&--option-input
position: absolute
height: 1px
width: 1px
overflow: hidden
clip: rect(1px,1px,1px,1px)

@ -0,0 +1,4 @@
@import 'variables'
@import 'typography'
@import 'zindex'
@import 'blocks'

@ -0,0 +1,48 @@
@mixin spot-header-big($weight: bold, $style: normal)
font-family: Lato, sans-serif
font-size: 2rem
font-weight: $weight
font-style: $style
line-height: 1.2em
@mixin spot-header-small($weight: bold, $style: normal)
font-family: Lato, sans-serif
font-size: 1.5rem
font-weight: $weight
font-style: $style
line-height: 1.2em
@mixin spot-subheader-big($weight: bold, $style: normal)
font-family: Lato, sans-serif
font-size: 1.25rem
font-weight: $weight
font-style: $style
line-height: 1.2em
@mixin spot-subheader-small($weight: bold, $style: normal)
font-family: Lato, sans-serif
font-size: 1.125rem
font-weight: $weight
font-style: $style
line-height: 1.2em
@mixin spot-body-big($weight: normal, $style: normal)
font-family: Lato, sans-serif
font-size: 1rem
font-weight: $weight
font-style: $style
line-height: 1.2em
@mixin spot-body-small($weight: normal, $style: normal)
font-family: Lato, sans-serif
font-size: 0.875rem
font-weight: $weight
font-style: $style
line-height: 1.2em
@mixin spot-caption($weight: normal, $style: normal)
font-family: Lato, sans-serif
font-size: 0.75rem
font-weight: $weight
font-style: $style
line-height: 1.2em

@ -0,0 +1 @@
@import '../tokens/dist/tokens.sass'

@ -0,0 +1,6 @@
@use "sass:map"
$spot-z-indexes: ( "drop-modal": 1000 )
@mixin spot-z-index($type, $addition: 0)
z-index: map.get($spot-z-indexes, $type) + $addition

@ -0,0 +1,66 @@
props:
- name: spot-color-basic-black
value: "#000000"
- name: spot-color-basic-gray-1
value: "#333333"
- name: spot-color-basic-gray-2
value: "#555555"
- name: spot-color-basic-gray-3
value: "#878787"
- name: spot-color-basic-gray-4
value: "#cccccc"
- name: spot-color-basic-gray-5
value: "#e0e0e0"
- name: spot-color-basic-gray-6
value: "#f3f3f3"
- name: spot-color-basic-white
value: "#ffffff"
- name: spot-color-main
value: "#1a67a3"
- name: spot-color-main-dark
value: "#034579"
- name: spot-color-main-light
value: "#d1e5f5"
- name: spot-color-accent
value: "#308720"
- name: spot-color-accent-dark
value: "#007528"
- name: spot-color-accent-light
value: "#bfeeb6"
- name: spot-color-danger
value: "#d01100"
- name: spot-color-danger-dark
value: "#7D000D"
- name: spot-color-danger-light
value: "#F4ABA9"
- name: spot-color-indication-notification
value: "#00A3FF"
- name: spot-color-indication-flagged
value: "#1CB6C0"
- name: spot-color-indication-current-date
value: "#ffffE1"
- name: spot-color-feedback-error-dark
value: "#CA3F3F"
- name: spot-color-feedback-error-light
value: "#FEDADA"
- name: spot-color-feedback-warning-dark
value: "#EF9E56"
- name: spot-color-feedback-warning-light
value: "#FFE6C6"
- name: spot-color-feedback-success-dark
value: "#35C53F"
- name: spot-color-feedback-success-light
value: "#D8FDD1"
- name: spot-color-feedback-info-dark
value: "#8FC0DB"
- name: spot-color-feedback-info-light
value: "#E3F5FF"
global:
type: color
category: colors

@ -0,0 +1,57 @@
{
"spot-color-basic-black": "rgb(0, 0, 0)",
"spot-color-basic-gray-1": "rgb(51, 51, 51)",
"spot-color-basic-gray-2": "rgb(85, 85, 85)",
"spot-color-basic-gray-3": "rgb(135, 135, 135)",
"spot-color-basic-gray-4": "rgb(204, 204, 204)",
"spot-color-basic-gray-5": "rgb(224, 224, 224)",
"spot-color-basic-gray-6": "rgb(243, 243, 243)",
"spot-color-basic-white": "rgb(255, 255, 255)",
"spot-color-main": "rgb(26, 103, 163)",
"spot-color-main-dark": "rgb(3, 69, 121)",
"spot-color-main-light": "rgb(209, 229, 245)",
"spot-color-accent": "rgb(48, 135, 32)",
"spot-color-accent-dark": "rgb(0, 117, 40)",
"spot-color-accent-light": "rgb(191, 238, 182)",
"spot-color-danger": "rgb(208, 17, 0)",
"spot-color-danger-dark": "rgb(125, 0, 13)",
"spot-color-danger-light": "rgb(244, 171, 169)",
"spot-color-indication-notification": "rgb(0, 163, 255)",
"spot-color-indication-flagged": "rgb(28, 182, 192)",
"spot-color-indication-current-date": "rgb(255, 255, 225)",
"spot-color-feedback-error-dark": "rgb(202, 63, 63)",
"spot-color-feedback-error-light": "rgb(254, 218, 218)",
"spot-color-feedback-warning-dark": "rgb(239, 158, 86)",
"spot-color-feedback-warning-light": "rgb(255, 230, 198)",
"spot-color-feedback-success-dark": "rgb(53, 197, 63)",
"spot-color-feedback-success-light": "rgb(216, 253, 209)",
"spot-color-feedback-info-dark": "rgb(143, 192, 219)",
"spot-color-feedback-info-light": "rgb(227, 245, 255)",
"spot-spacing-5": "5rem",
"spot-spacing-6": "6rem",
"spot-spacing-1_75": "1.75rem",
"spot-spacing-7": "7rem",
"spot-spacing-0_75": "0.75rem",
"spot-spacing-8": "8rem",
"spot-spacing-9": "9rem",
"spot-spacing-2_25": "2.25rem",
"spot-spacing-1_25": "1.25rem",
"spot-spacing-0_25": "0.25rem",
"spot-spacing-0_5": "0.5rem",
"spot-spacing-1_5": "1.5rem",
"spot-spacing-2_5": "2.5rem",
"spot-spacing-10": "10rem",
"spot-spacing-3_5": "3.5rem",
"spot-spacing-4_5": "4.5rem",
"spot-spacing-5_5": "5.5rem",
"spot-spacing-1": "1rem",
"spot-spacing-2": "2rem",
"spot-spacing-3": "3rem",
"spot-spacing-4": "4rem",
"spot-shadow-light-low": "2px 2px 5px rgba(0, 0, 0, 0.15)",
"spot-shadow-light-mid": "4px 4px 10px rgba(0, 0, 0, 0.15)",
"spot-shadow-light-high": "6px 6px 20px rgba(0, 0, 0, 0.15)",
"spot-shadow-hard-low": "2px 2px 5px rgba(0, 0, 0, 0.25)",
"spot-shadow-hard-mid": "4px 4px 10px rgba(0, 0, 0, 0.25)",
"spot-shadow-hard-high": "6px 6px 20px rgba(0, 0, 0, 0.25)"
}

@ -0,0 +1,56 @@
$spot-color-basic-black: rgb(0, 0, 0)
$spot-color-basic-gray-1: rgb(51, 51, 51)
$spot-color-basic-gray-2: rgb(85, 85, 85)
$spot-color-basic-gray-3: rgb(135, 135, 135)
$spot-color-basic-gray-4: rgb(204, 204, 204)
$spot-color-basic-gray-5: rgb(224, 224, 224)
$spot-color-basic-gray-6: rgb(243, 243, 243)
$spot-color-basic-white: rgb(255, 255, 255)
$spot-color-main: rgb(26, 103, 163)
$spot-color-main-dark: rgb(3, 69, 121)
$spot-color-main-light: rgb(209, 229, 245)
$spot-color-accent: rgb(48, 135, 32)
$spot-color-accent-dark: rgb(0, 117, 40)
$spot-color-accent-light: rgb(191, 238, 182)
$spot-color-danger: rgb(208, 17, 0)
$spot-color-danger-dark: rgb(125, 0, 13)
$spot-color-danger-light: rgb(244, 171, 169)
$spot-color-indication-notification: rgb(0, 163, 255)
$spot-color-indication-flagged: rgb(28, 182, 192)
$spot-color-indication-current-date: rgb(255, 255, 225)
$spot-color-feedback-error-dark: rgb(202, 63, 63)
$spot-color-feedback-error-light: rgb(254, 218, 218)
$spot-color-feedback-warning-dark: rgb(239, 158, 86)
$spot-color-feedback-warning-light: rgb(255, 230, 198)
$spot-color-feedback-success-dark: rgb(53, 197, 63)
$spot-color-feedback-success-light: rgb(216, 253, 209)
$spot-color-feedback-info-dark: rgb(143, 192, 219)
$spot-color-feedback-info-light: rgb(227, 245, 255)
$spot-spacing-5: 5rem
$spot-spacing-6: 6rem
$spot-spacing-1-75: 1.75rem
$spot-spacing-7: 7rem
$spot-spacing-0-75: 0.75rem
$spot-spacing-8: 8rem
$spot-spacing-9: 9rem
$spot-spacing-2-25: 2.25rem
$spot-spacing-1-25: 1.25rem
$spot-spacing-0-25: 0.25rem
$spot-spacing-0-5: 0.5rem
$spot-spacing-1-5: 1.5rem
$spot-spacing-2-5: 2.5rem
$spot-spacing-10: 10rem
$spot-spacing-3-5: 3.5rem
$spot-spacing-4-5: 4.5rem
$spot-spacing-5-5: 5.5rem
$spot-spacing-1: 1rem
$spot-spacing-2: 2rem
$spot-spacing-3: 3rem
$spot-spacing-4: 4rem
$spot-shadow-light-low: 2px 2px 5px rgba(0, 0, 0, 0.15)
$spot-shadow-light-mid: 4px 4px 10px rgba(0, 0, 0, 0.15)
$spot-shadow-light-high: 6px 6px 20px rgba(0, 0, 0, 0.15)
$spot-shadow-hard-low: 2px 2px 5px rgba(0, 0, 0, 0.25)
$spot-shadow-hard-mid: 4px 4px 10px rgba(0, 0, 0, 0.25)
$spot-shadow-hard-high: 6px 6px 20px rgba(0, 0, 0, 0.25)

@ -0,0 +1,18 @@
props:
spot-shadow-light-low:
value: "2px 2px 5px rgba(0, 0, 0, 0.15)"
spot-shadow-light-mid:
value: "4px 4px 10px rgba(0, 0, 0, 0.15)"
spot-shadow-light-high:
value: "6px 6px 20px rgba(0, 0, 0, 0.15)"
spot-shadow-hard-low:
value: "2px 2px 5px rgba(0, 0, 0, 0.25)"
spot-shadow-hard-mid:
value: "4px 4px 10px rgba(0, 0, 0, 0.25)"
spot-shadow-hard-high:
value: "6px 6px 20px rgba(0, 0, 0, 0.25)"
global:
type: box-shadow
category: shadows

@ -0,0 +1,47 @@
props:
spot-spacing-0_25:
value: "0.25rem"
spot-spacing-0_5:
value: "0.5rem"
spot-spacing-0_75:
value: "0.75rem"
spot-spacing-1:
value: "1rem"
spot-spacing-1_25:
value: "1.25rem"
spot-spacing-1_5:
value: "1.5rem"
spot-spacing-1_75:
value: "1.75rem"
spot-spacing-2:
value: "2rem"
spot-spacing-2_25:
value: "2.25rem"
spot-spacing-2_5:
value: "2.5rem"
spot-spacing-3:
value: "3rem"
spot-spacing-3_5:
value: "3.5rem"
spot-spacing-4:
value: "4rem"
spot-spacing-4_5:
value: "4.5rem"
spot-spacing-5:
value: "5rem"
spot-spacing-5_5:
value: "5.5rem"
spot-spacing-6:
value: "6rem"
spot-spacing-7:
value: "7rem"
spot-spacing-8:
value: "8rem"
spot-spacing-9:
value: "9rem"
spot-spacing-10:
value: "10rem"
global:
type: spacing
category: spacings

@ -0,0 +1,4 @@
imports:
- ./colors.yml
- ./spacings.yml
- ./shadows.yml

@ -5,6 +5,7 @@
@import "content/_index.sass" @import "content/_index.sass"
@import "./common/openproject-common.module" @import "./common/openproject-common.module"
@import "../app/spot/styles/sass"
@import "../app/shared/components/modal/modal.module" @import "../app/shared/components/modal/modal.module"
// Dynamically linked plugin styles from Rails plugins // Dynamically linked plugin styles from Rails plugins

@ -1,4 +1,5 @@
{ pkgs ? import <nixpkgs> {} }: { pkgs ? import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/8ca77a63599ed951d6a2d244c1d62092776a3fe1.tar.gz") {}
}:
with pkgs; with pkgs;
let let
op-get-test-failures = writeShellScriptBin "op-get-test-failures" '' op-get-test-failures = writeShellScriptBin "op-get-test-failures" ''

Loading…
Cancel
Save