mirror of
https://github.com/bpatrik/pigallery2.git
synced 2024-12-23 01:27:14 +02:00
parent
4a1daff947
commit
6c0c883298
@ -41,7 +41,7 @@ export type TAGS = {
|
||||
experimental?: boolean, //is it a beta feature
|
||||
unit?: string, // Unit info to display on UI
|
||||
uiIcon?: string,
|
||||
uiType?: 'SearchQuery' | 'ThemeSelector' | 'SelectedThemeSettings', // Hint for the UI about the type
|
||||
uiType?: 'SearchQuery' | 'ThemeSelector' | 'SelectedThemeSettings' | 'SVGIconConfig', // Hint for the UI about the type
|
||||
uiOptions?: (string | number)[], //Hint for the UI about the recommended options
|
||||
uiAllowSpaces?: boolean
|
||||
uiOptional?: boolean; //makes the tag not "required"
|
||||
@ -318,27 +318,23 @@ export class MapLayers {
|
||||
darkLayer: boolean = false;
|
||||
}
|
||||
|
||||
export enum MapPathGroupTypes {
|
||||
Transportation = 1, Sport, Custom
|
||||
}
|
||||
|
||||
|
||||
@SubConfigClass({tags: {client: true}, softReadonly: true})
|
||||
export class SVGIconConfig {
|
||||
|
||||
constructor(viewBoxWidth: number = 512, path: string = '') {
|
||||
this.viewBoxWidth = viewBoxWidth;
|
||||
constructor(viewBox: string = '0 0 512 512', path: string = '') {
|
||||
this.viewBox = viewBox;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@ConfigProperty({
|
||||
tags: {
|
||||
name: $localize`SBG icon viewBox with`,
|
||||
name: $localize`SVG icon viewBox`,
|
||||
priority: ConfigPriority.advanced
|
||||
},
|
||||
description: $localize`You need the with from the SVG viewBox (assuming height is 512). See: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox`,
|
||||
description: $localize`SVG path viewBox. See: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox`,
|
||||
})
|
||||
viewBoxWidth: number = 512;
|
||||
viewBox: string = '0 0 512 512';
|
||||
|
||||
@ConfigProperty({
|
||||
tags: {
|
||||
@ -372,7 +368,8 @@ export class PathThemeConfig {
|
||||
@ConfigProperty({
|
||||
tags: {
|
||||
name: $localize`Dash pattern`,
|
||||
priority: ConfigPriority.advanced
|
||||
priority: ConfigPriority.advanced,
|
||||
uiOptions: ['', '4', '4 1', '4 8', '4 1 2', '0 4 0', '4 1 2 3'],
|
||||
},
|
||||
description: $localize`Dash pattern of the path. Represents the spacing and length of the dash. Read more about dash array at: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray.`,
|
||||
})
|
||||
@ -383,8 +380,9 @@ export class PathThemeConfig {
|
||||
type: SVGIconConfig,
|
||||
tags: {
|
||||
name: $localize`Svg Icon`,
|
||||
uiType: 'SVGIconConfig',
|
||||
priority: ConfigPriority.advanced
|
||||
},
|
||||
} as TAGS,
|
||||
description: $localize`Set the icon of the map marker pin.`,
|
||||
})
|
||||
svgIcon: SVGIconConfig = new SVGIconConfig();
|
||||
@ -406,7 +404,7 @@ export class MapPathGroupThemeConfig {
|
||||
name: $localize`Matchers`,
|
||||
priority: ConfigPriority.advanced
|
||||
},
|
||||
description: $localize`List of regex string to match the name of the path. Case insensitive.`,
|
||||
description: $localize`List of regex string to match the name of the path. Case insensitive. Empty list matches everything.`,
|
||||
})
|
||||
matchers: string[] = [];
|
||||
|
||||
@ -527,7 +525,7 @@ export class ClientMapConfig {
|
||||
['flight', 'flying', 'drive', 'driving'],
|
||||
new PathThemeConfig('var(--bs-orange)',
|
||||
'4 8',
|
||||
new SVGIconConfig(567, 'M482.3 192c34.2 0 93.7 29 93.7 64c0 36-59.5 64-93.7 64l-116.6 0L265.2 495.9c-5.7 10-16.3 16.1-27.8 16.1l-56.2 0c-10.6 0-18.3-10.2-15.4-20.4l49-171.6L112 320 68.8 377.6c-3 4-7.8 6.4-12.8 6.4l-42 0c-7.8 0-14-6.3-14-14c0-1.3 .2-2.6 .5-3.9L32 256 .5 145.9c-.4-1.3-.5-2.6-.5-3.9c0-7.8 6.3-14 14-14l42 0c5 0 9.8 2.4 12.8 6.4L112 192l102.9 0-49-171.6C162.9 10.2 170.6 0 181.2 0l56.2 0c11.5 0 22.1 6.2 27.8 16.1L365.7 192l116.6 0z')
|
||||
new SVGIconConfig('0 0 567 512', 'M482.3 192c34.2 0 93.7 29 93.7 64c0 36-59.5 64-93.7 64l-116.6 0L265.2 495.9c-5.7 10-16.3 16.1-27.8 16.1l-56.2 0c-10.6 0-18.3-10.2-15.4-20.4l49-171.6L112 320 68.8 377.6c-3 4-7.8 6.4-12.8 6.4l-42 0c-7.8 0-14-6.3-14-14c0-1.3 .2-2.6 .5-3.9L32 256 .5 145.9c-.4-1.3-.5-2.6-.5-3.9c0-7.8 6.3-14 14-14l42 0c5 0 9.8 2.4 12.8 6.4L112 192l102.9 0-49-171.6C162.9 10.2 170.6 0 181.2 0l56.2 0c11.5 0 22.1 6.2 27.8 16.1L365.7 192l116.6 0z')
|
||||
)
|
||||
)]),
|
||||
new MapPathGroupConfig('Sport',
|
||||
@ -535,7 +533,7 @@ export class ClientMapConfig {
|
||||
['run', 'walk', 'hike', 'hiking', 'bike', 'biking', 'cycling', 'skiing'],
|
||||
new PathThemeConfig('var(--bs-primary)',
|
||||
'',
|
||||
new SVGIconConfig(417, 'M320 48a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zM125.7 175.5c9.9-9.9 23.4-15.5 37.5-15.5c1.9 0 3.8 .1 5.6 .3L137.6 254c-9.3 28 1.7 58.8 26.8 74.5l86.2 53.9-25.4 88.8c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l28.7-100.4c5.9-20.6-2.6-42.6-20.7-53.9L238 299l30.9-82.4 5.1 12.3C289 264.7 323.9 288 362.7 288H384c17.7 0 32-14.3 32-32s-14.3-32-32-32H362.7c-12.9 0-24.6-7.8-29.5-19.7l-6.3-15c-14.6-35.1-44.1-61.9-80.5-73.1l-48.7-15c-11.1-3.4-22.7-5.2-34.4-5.2c-31 0-60.8 12.3-82.7 34.3L57.4 153.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l23.1-23.1zM91.2 352H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h69.6c19 0 36.2-11.2 43.9-28.5L157 361.6l-9.5-6c-17.5-10.9-30.5-26.8-37.9-44.9L91.2 352z')
|
||||
new SVGIconConfig('0 0 417 512', 'M320 48a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zM125.7 175.5c9.9-9.9 23.4-15.5 37.5-15.5c1.9 0 3.8 .1 5.6 .3L137.6 254c-9.3 28 1.7 58.8 26.8 74.5l86.2 53.9-25.4 88.8c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l28.7-100.4c5.9-20.6-2.6-42.6-20.7-53.9L238 299l30.9-82.4 5.1 12.3C289 264.7 323.9 288 362.7 288H384c17.7 0 32-14.3 32-32s-14.3-32-32-32H362.7c-12.9 0-24.6-7.8-29.5-19.7l-6.3-15c-14.6-35.1-44.1-61.9-80.5-73.1l-48.7-15c-11.1-3.4-22.7-5.2-34.4-5.2c-31 0-60.8 12.3-82.7 34.3L57.4 153.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l23.1-23.1zM91.2 352H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h69.6c19 0 36.2-11.2 43.9-28.5L157 361.6l-9.5-6c-17.5-10.9-30.5-26.8-37.9-44.9L91.2 352z')
|
||||
)
|
||||
)]),
|
||||
new MapPathGroupConfig('Other paths',
|
||||
|
@ -3,7 +3,7 @@ import {DivIcon, setOptions} from 'leaflet';
|
||||
export interface SvgIconOptions {
|
||||
color?: string;
|
||||
svgPath?: string;
|
||||
width?: number;
|
||||
viewBox?: string;
|
||||
small?: boolean;
|
||||
}
|
||||
|
||||
@ -11,8 +11,8 @@ const SvgIcon: { new(options?: SvgIconOptions): DivIcon } = DivIcon.extend({
|
||||
initialize: function(options: SvgIconOptions = {}) {
|
||||
options.color = options.color || 'var(--bs-primary)';
|
||||
options.svgPath = options.svgPath || 'M256 512c141.4 0 256-114.6 256-256S397.4 0 256 0S0 114.6 0 256S114.6 512 256 512z';
|
||||
options.width = options.width || 512;
|
||||
const svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ' + options.width + ' 512"><path fill="' + options.color + '" d="' + options.svgPath + '"/></svg>';
|
||||
options.viewBox = options.viewBox || '0 0 512 512';
|
||||
const svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="' + options.viewBox + '"><path fill="' + options.color + '" d="' + options.svgPath + '"/></svg>';
|
||||
setOptions(this, {
|
||||
iconSize: options.small ? [15, 15] : [30, 30],
|
||||
iconAnchor: options.small ? [15, 28] : [15, 35],
|
||||
|
@ -189,7 +189,7 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy {
|
||||
icon: MarkerFactory.getSvgIcon({
|
||||
color: ths.theme.color,
|
||||
svgPath: ths.theme.svgIcon?.path,
|
||||
width: ths.theme.svgIcon?.viewBoxWidth
|
||||
viewBox: ths.theme.svgIcon?.viewBox
|
||||
})
|
||||
};
|
||||
})
|
||||
|
@ -151,6 +151,79 @@
|
||||
(ngModelChange)="onChange($event)">
|
||||
</app-settings-workflow>
|
||||
|
||||
<ng-container *ngSwitchCase="'SVGIconConfig'">
|
||||
<button class="btn btn-outline-primary"
|
||||
(click)="showIconModal(iconModalTmp)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
[attr.viewBox]="state.value.viewBox || '0 0 512 512'">
|
||||
<path [attr.d]="state.value.path"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
|
||||
<ng-template #iconModalTmp>
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" i18n>Icon</h5>
|
||||
<button type="button" class="btn-close" (click)="hideIconModal()" data-dismiss="modal"
|
||||
aria-label="Close">
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row mb-4">
|
||||
<div class="col text-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="2em"
|
||||
[attr.viewBox]="state.value.viewBox || '0 0 512 512'">
|
||||
<path [attr.d]="state.value.path"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="iconModal?.error" class="alert alert-danger">{{iconModal.error}}</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-2 control-label">
|
||||
<label [for]="'icon_f_'+idName" class="form-label" i18n>Load from SVG file</label>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<input type="file" class="form-control" [id]="'icon_f_'+idName" accept="image/svg+xml"
|
||||
(change)="newSvgFile($event)">
|
||||
|
||||
<small class="form-text text-muted" i18n>To auto load these values from file: pick an SVG file with a
|
||||
single 'path'. You can use e.g: http://fontawesome.com/icons.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<hr/>
|
||||
|
||||
<app-settings-entry
|
||||
[ngModel]="state.value.__state.viewBox"
|
||||
[name]="'icon_w_'+idName"
|
||||
[id]="'icon_w_'+idName"
|
||||
(change)="onChange($event)"></app-settings-entry>
|
||||
|
||||
<app-settings-entry
|
||||
[ngModel]="state.value.__state.path"
|
||||
[name]="'icon_p_'+idName"
|
||||
[id]="'icon_p_'+idName"
|
||||
(change)="onChange($event)"></app-settings-entry>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
|
||||
<div class="btn-group float-end row mt-2" role="group" style="display: block">
|
||||
<div class="pe-0">
|
||||
<button class="btn btn-primary" type="button"
|
||||
(click)="hideIconModal()">
|
||||
<ng-container i18n>Save & Close</ng-container>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'MapLayers'">
|
||||
<div class="container">
|
||||
<table class="table">
|
||||
@ -227,17 +300,11 @@
|
||||
</div>
|
||||
<div class="row mt-1 mb-1 bg-body-tertiary">
|
||||
<app-settings-entry
|
||||
[ngModel]="val.theme.svgIcon.__state.viewBoxWidth"
|
||||
[name]="'viewBoxWidth_n_'+idName+i"
|
||||
[id]="'viewBoxWidth_n_'+idName+i"
|
||||
(change)="onChange($event)"></app-settings-entry>
|
||||
</div>
|
||||
<div class="row mt-1 mb-1 bg-body-tertiary">
|
||||
<app-settings-entry
|
||||
[ngModel]="val.theme.svgIcon.__state.path"
|
||||
[name]="'path_n_'+idName+i"
|
||||
[id]="'path_n_'+idName+i"
|
||||
(change)="onChange($event)"></app-settings-entry>
|
||||
[ngModel]="val.theme.__state.svgIcon"
|
||||
[name]="'svgIcon_'+idName+i"
|
||||
[id]="'svgIcon_'+idName+i"
|
||||
(ngModelChange)="onChange($event)">
|
||||
</app-settings-entry>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -279,7 +346,8 @@
|
||||
[ngModel]="arr.__state.matchers"
|
||||
[name]="'arr_m_'+idName+i"
|
||||
[id]="'arr_m_'+idName+i"
|
||||
(change)="onChange($event)"></app-settings-entry>
|
||||
(ngModelChange)="onChange($event)">
|
||||
</app-settings-entry>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,7 +3,15 @@ import {ControlValueAccessor, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors
|
||||
import {Utils} from '../../../../../../common/Utils';
|
||||
import {propertyTypes} from 'typeconfig/common';
|
||||
import {SearchQueryParserService} from '../../../gallery/search/search-query-parser.service';
|
||||
import {MapLayers, MapPathGroupConfig, MapPathGroupThemeConfig, NavigationLinkConfig, NavigationLinkTypes, TAGS, ThemeConfig} from '../../../../../../common/config/public/ClientConfig';
|
||||
import {
|
||||
MapLayers,
|
||||
MapPathGroupConfig,
|
||||
MapPathGroupThemeConfig,
|
||||
NavigationLinkConfig,
|
||||
NavigationLinkTypes,
|
||||
TAGS,
|
||||
ThemeConfig
|
||||
} from '../../../../../../common/config/public/ClientConfig';
|
||||
import {SettingsService} from '../../settings.service';
|
||||
import {WebConfig} from '../../../../../../common/config/private/WebConfig';
|
||||
import {JobScheduleConfig, UserConfig} from '../../../../../../common/config/private/PrivateConfig';
|
||||
@ -69,6 +77,7 @@ export class SettingsEntryComponent
|
||||
public arrayType: string;
|
||||
public uiType: string;
|
||||
newThemeModalRef: any;
|
||||
iconModal: { ref?: any, error?: string };
|
||||
|
||||
|
||||
constructor(private searchQueryParserService: SearchQueryParserService,
|
||||
@ -217,11 +226,16 @@ export class SettingsEntryComponent
|
||||
} else {
|
||||
this.arrayType = this.state.arrayType;
|
||||
}
|
||||
|
||||
if (this.state.tags?.uiOptions) {
|
||||
this.state.isEnumType = true;
|
||||
}
|
||||
this.uiType = this.arrayType;
|
||||
if (!this.state.isEnumType &&
|
||||
!this.state.isEnumArrayType &&
|
||||
this.type !== 'boolean' &&
|
||||
this.type !== 'SearchQuery' &&
|
||||
this.type !== 'SVGIconConfig' &&
|
||||
this.arrayType !== 'MapLayers' &&
|
||||
this.arrayType !== 'NavigationLinkConfig' &&
|
||||
this.arrayType !== 'MapPathGroupConfig' &&
|
||||
@ -242,9 +256,6 @@ export class SettingsEntryComponent
|
||||
|
||||
this.placeholder = this.state.tags?.hint || this.state.default;
|
||||
|
||||
if (this.state.tags?.uiOptions) {
|
||||
this.state.isEnumType = true;
|
||||
}
|
||||
this.title = '';
|
||||
if (this.state.readonly) {
|
||||
this.title = $localize`readonly` + ', ';
|
||||
@ -404,11 +415,54 @@ export class SettingsEntryComponent
|
||||
}
|
||||
|
||||
|
||||
showIconModal(template: TemplateRef<any>): void {
|
||||
this.iconModal = {};
|
||||
this.iconModal.ref = this.modalService.show(template, {
|
||||
class: 'modal-lg',
|
||||
});
|
||||
document.body.style.paddingRight = '0px';
|
||||
}
|
||||
|
||||
|
||||
public hideNewThemeModal(): void {
|
||||
this.newThemeModalRef.hide();
|
||||
this.newThemeModalRef = null;
|
||||
}
|
||||
|
||||
hideIconModal(): void {
|
||||
if (!this.iconModal) {
|
||||
return;
|
||||
}
|
||||
this.iconModal.ref.hide();
|
||||
delete this.iconModal;
|
||||
}
|
||||
|
||||
newSvgFile(event: Event): void {
|
||||
|
||||
const file: File = (event.target as HTMLInputElement).files[0];
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
console.log(reader.result);
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(reader.result as string, 'image/svg+xml');
|
||||
try {
|
||||
const wb = doc.documentElement.getAttribute('viewBox');
|
||||
const path = doc.documentElement.getElementsByTagName('path')[0].getAttribute('d');
|
||||
this.state.value.path = path;
|
||||
this.state.value.viewBox = wb;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (this.iconModal) {
|
||||
this.iconModal.error = 'Can\'t parse SVG file: ' + e.toState;
|
||||
}
|
||||
}
|
||||
this.onChange(null);
|
||||
};
|
||||
reader.readAsText(file);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user