@ -0,0 +1,2 @@ |
|||||||
|
.op-search-highlight |
||||||
|
color: $spot-color-main |
@ -0,0 +1,43 @@ |
|||||||
|
import { |
||||||
|
AfterViewChecked, |
||||||
|
Directive, |
||||||
|
ElementRef, |
||||||
|
Input, |
||||||
|
} from '@angular/core'; |
||||||
|
|
||||||
|
@Directive({ |
||||||
|
selector: '[opSearchHighlight]', |
||||||
|
}) |
||||||
|
export class OpSearchHighlightDirective implements AfterViewChecked { |
||||||
|
@Input('opSearchHighlight') public query = ''; |
||||||
|
|
||||||
|
constructor(readonly elementRef:ElementRef) { } |
||||||
|
|
||||||
|
ngAfterViewChecked():void { |
||||||
|
if (!this.query) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
const el = this.elementRef.nativeElement as HTMLElement; |
||||||
|
|
||||||
|
const textNode = Array.from(el.childNodes).find((n:Node) => n.nodeType === n.TEXT_NODE) as Node; |
||||||
|
const content = textNode?.textContent || ''; |
||||||
|
if (!content) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
const query = this.query.toLowerCase(); |
||||||
|
const startIndex = content.toLowerCase().indexOf(query); |
||||||
|
if (startIndex < 0) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
const start = content.slice(0, startIndex); |
||||||
|
const result = content.slice(startIndex, startIndex + query.length); |
||||||
|
const end = content.slice(startIndex + query.length); |
||||||
|
|
||||||
|
const newNode = document.createElement('span'); |
||||||
|
newNode.innerHTML = `${start}<span class="op-search-highlight">${result}</span>${end}`; |
||||||
|
el.replaceChild(newNode, textNode); |
||||||
|
} |
||||||
|
} |
@ -1,8 +0,0 @@ |
|||||||
<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,17 @@ |
|||||||
|
<ng-content select="[slot=trigger]"></ng-content> |
||||||
|
<div |
||||||
|
[ngClass]="['spot-drop-modal--body', 'spot-body', alignmentClass]" |
||||||
|
(click)="onBodyClick($event)" |
||||||
|
cdkTrapFocus |
||||||
|
> |
||||||
|
<ng-content select="[slot=body]"></ng-content> |
||||||
|
|
||||||
|
<button |
||||||
|
class="spot-drop-modal--close-button spot-button" |
||||||
|
type="button" |
||||||
|
[attr.aria-label]="text.close" |
||||||
|
(click)="close()" |
||||||
|
> |
||||||
|
<span class="spot-icon spot-icon_close"></span> |
||||||
|
</button> |
||||||
|
</div> |
@ -1,7 +0,0 @@ |
|||||||
<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,16 @@ |
|||||||
|
<button |
||||||
|
*ngIf="removable" |
||||||
|
class="spot-filter-chip--remove" |
||||||
|
type="button" |
||||||
|
(click)="remove.emit()" |
||||||
|
[attr.aria-label]="text.remove" |
||||||
|
> |
||||||
|
<span class="spot-icon spot-icon_close"></span> |
||||||
|
</button> |
||||||
|
<div class="spot-filter-chip--title"> |
||||||
|
<span |
||||||
|
*ngIf="icon" |
||||||
|
[ngClass]="iconClasses" |
||||||
|
></span> |
||||||
|
{{ title }} |
||||||
|
</div> |
@ -0,0 +1,57 @@ |
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const webfontsGenerator = require('webfonts-generator'); |
||||||
|
const path = require('path'); |
||||||
|
const glob = require("glob") |
||||||
|
|
||||||
|
const TEMPLATE_DIR = path.resolve(process.argv[2]); |
||||||
|
const CSS_FONT_URL = "../../../../../frontend/src/assets/fonts/openproject_icon/"; |
||||||
|
const FONT_DESTINATION = path.resolve(__dirname, '..', '..', '..', '..', '..', 'frontend', 'src', 'assets', 'fonts', 'openproject_icon'); |
||||||
|
|
||||||
|
const files = glob.sync(path.join(TEMPLATE_DIR, 'src/*.svg')); |
||||||
|
|
||||||
|
webfontsGenerator({ |
||||||
|
files, |
||||||
|
"fontName": "openproject-icon-font", |
||||||
|
"cssFontsUrl": CSS_FONT_URL, |
||||||
|
"dest": FONT_DESTINATION, |
||||||
|
"cssDest": path.join( |
||||||
|
path.resolve(__dirname, '..', 'styles', 'sass', 'common'), |
||||||
|
'icon.sass', |
||||||
|
), |
||||||
|
"cssTemplate": path.join(TEMPLATE_DIR, "icon.template.sass"), |
||||||
|
"types": ['woff2', 'woff'], |
||||||
|
"fixedWidth": true, |
||||||
|
"descent": 100 |
||||||
|
}, function(error) { |
||||||
|
if (error) { |
||||||
|
console.log('Failed to build icon font. ', error); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
webfontsGenerator({ |
||||||
|
files, |
||||||
|
"fontName": "openproject-icon-font", |
||||||
|
"cssFontsUrl": CSS_FONT_URL, |
||||||
|
"dest": FONT_DESTINATION, |
||||||
|
"cssDest": path.join( |
||||||
|
path.resolve(__dirname, '..', '..', '..', '..', '..', 'frontend', 'src', 'global_styles', 'fonts'), |
||||||
|
'_openproject_icon_definitions.sass', |
||||||
|
), |
||||||
|
"cssTemplate": path.join(TEMPLATE_DIR, "openproject-icon-font.template.sass"), |
||||||
|
"classPrefix": "icon-", |
||||||
|
"baseSelector": ".icon", |
||||||
|
"html": true, |
||||||
|
"htmlDest": path.join( |
||||||
|
path.resolve(__dirname, '..', '..', '..', '..', '..', 'frontend', 'src', 'global_styles', 'fonts'), |
||||||
|
'_openproject_icon_font.lsg', |
||||||
|
), |
||||||
|
"htmlTemplate": path.join(TEMPLATE_DIR, "openproject-icon-font.template.lsg"), |
||||||
|
"types": ['woff2', 'woff'], |
||||||
|
"fixedWidth": true, |
||||||
|
"descent": 100 |
||||||
|
}, function(error) { |
||||||
|
if (error) { |
||||||
|
console.log('Failed to build icon font. ', error); |
||||||
|
} |
||||||
|
}); |
@ -0,0 +1,28 @@ |
|||||||
|
.spot-icon |
||||||
|
display: inline-flex |
||||||
|
justify-content: center |
||||||
|
align-items: center |
||||||
|
|
||||||
|
&::before |
||||||
|
font-family: "openproject-icon-font" |
||||||
|
font-style: normal |
||||||
|
font-weight: normal |
||||||
|
font-variant: normal |
||||||
|
font-size: inherit |
||||||
|
text-transform: none |
||||||
|
text-decoration: none |
||||||
|
display: block |
||||||
|
speak: none |
||||||
|
line-height: 1 |
||||||
|
-webkit-font-smoothing: antialiased |
||||||
|
-moz-osx-font-smoothing: grayscale |
||||||
|
|
||||||
|
{{#each codepoints}} |
||||||
|
|
||||||
|
@mixin spot-icon-{{@key}} |
||||||
|
content: "\\{{this}}" |
||||||
|
|
||||||
|
.spot-icon_{{@key}}:before |
||||||
|
content: "\\{{this}}" |
||||||
|
|
||||||
|
{{/each}} |
@ -0,0 +1,9 @@ |
|||||||
|
{{#each codepoints}} |
||||||
|
|
||||||
|
@mixin icon-mixin-{{@key}} |
||||||
|
content: "\\{{this}}" |
||||||
|
|
||||||
|
.{{../classPrefix}}{{@key}}:before |
||||||
|
content: "\\{{this}}" |
||||||
|
|
||||||
|
{{/each}} |
Before Width: | Height: | Size: 678 B After Width: | Height: | Size: 678 B |
Before Width: | Height: | Size: 455 B After Width: | Height: | Size: 455 B |
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 129 B |
Before Width: | Height: | Size: 193 B After Width: | Height: | Size: 193 B |
Before Width: | Height: | Size: 175 B After Width: | Height: | Size: 175 B |
Before Width: | Height: | Size: 187 B After Width: | Height: | Size: 187 B |
Before Width: | Height: | Size: 194 B After Width: | Height: | Size: 194 B |
Before Width: | Height: | Size: 232 B After Width: | Height: | Size: 232 B |
Before Width: | Height: | Size: 99 B After Width: | Height: | Size: 99 B |
Before Width: | Height: | Size: 273 B After Width: | Height: | Size: 273 B |
Before Width: | Height: | Size: 470 B After Width: | Height: | Size: 470 B |
Before Width: | Height: | Size: 225 B After Width: | Height: | Size: 225 B |
Before Width: | Height: | Size: 103 B After Width: | Height: | Size: 103 B |
Before Width: | Height: | Size: 104 B After Width: | Height: | Size: 104 B |
Before Width: | Height: | Size: 227 B After Width: | Height: | Size: 227 B |
Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 463 B |
Before Width: | Height: | Size: 135 B After Width: | Height: | Size: 135 B |
Before Width: | Height: | Size: 104 B After Width: | Height: | Size: 104 B |
Before Width: | Height: | Size: 148 B After Width: | Height: | Size: 148 B |
Before Width: | Height: | Size: 102 B After Width: | Height: | Size: 102 B |
Before Width: | Height: | Size: 138 B After Width: | Height: | Size: 138 B |
Before Width: | Height: | Size: 231 B After Width: | Height: | Size: 231 B |
Before Width: | Height: | Size: 101 B After Width: | Height: | Size: 101 B |
Before Width: | Height: | Size: 380 B After Width: | Height: | Size: 380 B |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 610 B After Width: | Height: | Size: 610 B |
Before Width: | Height: | Size: 388 B After Width: | Height: | Size: 388 B |
Before Width: | Height: | Size: 125 B After Width: | Height: | Size: 125 B |
Before Width: | Height: | Size: 683 B After Width: | Height: | Size: 683 B |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 488 B After Width: | Height: | Size: 488 B |
Before Width: | Height: | Size: 451 B After Width: | Height: | Size: 451 B |
Before Width: | Height: | Size: 283 B After Width: | Height: | Size: 283 B |
Before Width: | Height: | Size: 582 B After Width: | Height: | Size: 582 B |
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 450 B |
Before Width: | Height: | Size: 341 B After Width: | Height: | Size: 341 B |
Before Width: | Height: | Size: 358 B After Width: | Height: | Size: 358 B |
Before Width: | Height: | Size: 257 B After Width: | Height: | Size: 257 B |
Before Width: | Height: | Size: 285 B After Width: | Height: | Size: 285 B |
Before Width: | Height: | Size: 166 B After Width: | Height: | Size: 166 B |
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 359 B |
Before Width: | Height: | Size: 211 B After Width: | Height: | Size: 211 B |
Before Width: | Height: | Size: 214 B After Width: | Height: | Size: 214 B |
Before Width: | Height: | Size: 167 B After Width: | Height: | Size: 167 B |
Before Width: | Height: | Size: 244 B After Width: | Height: | Size: 244 B |
Before Width: | Height: | Size: 266 B After Width: | Height: | Size: 266 B |
Before Width: | Height: | Size: 153 B After Width: | Height: | Size: 153 B |
Before Width: | Height: | Size: 172 B After Width: | Height: | Size: 172 B |
Before Width: | Height: | Size: 166 B After Width: | Height: | Size: 166 B |
Before Width: | Height: | Size: 382 B After Width: | Height: | Size: 382 B |
Before Width: | Height: | Size: 233 B After Width: | Height: | Size: 233 B |
Before Width: | Height: | Size: 345 B After Width: | Height: | Size: 345 B |
Before Width: | Height: | Size: 149 B After Width: | Height: | Size: 149 B |
Before Width: | Height: | Size: 141 B After Width: | Height: | Size: 141 B |
Before Width: | Height: | Size: 161 B After Width: | Height: | Size: 161 B |
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 201 B |
Before Width: | Height: | Size: 677 B After Width: | Height: | Size: 677 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 284 B After Width: | Height: | Size: 284 B |
Before Width: | Height: | Size: 514 B After Width: | Height: | Size: 514 B |
Before Width: | Height: | Size: 235 B After Width: | Height: | Size: 235 B |
Before Width: | Height: | Size: 206 B After Width: | Height: | Size: 206 B |
Before Width: | Height: | Size: 583 B After Width: | Height: | Size: 583 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 560 B After Width: | Height: | Size: 560 B |
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 862 B |
Before Width: | Height: | Size: 564 B After Width: | Height: | Size: 564 B |