chore: update Angular cache and TypeScript build info
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
<div class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4" (click)="onBackdropClick($event)">
|
||||
<div class="bg-white dark:bg-gray-900 rounded-lg shadow-xl max-w-2xl w-full p-6" (click)="$event.stopPropagation()">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-gray-100">
|
||||
{{ isEditMode() ? 'Edit bookmark' : 'Add bookmark' }}
|
||||
</h2>
|
||||
<button
|
||||
(click)="onCancel()"
|
||||
class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
|
||||
aria-label="Close">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Form -->
|
||||
<div class="space-y-4">
|
||||
<!-- Path -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Path
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
[value]="path()"
|
||||
(input)="onPathChange($any($event.target).value)"
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder="e.g. Tests/Allo note.md"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Title -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Title
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
[value]="title()"
|
||||
(input)="onTitleChange($any($event.target).value)"
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder="Display name (optional)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Bookmark group -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Bookmark group
|
||||
</label>
|
||||
<select
|
||||
[value]="selectedGroupCtime() || ''"
|
||||
(change)="onGroupChange($any($event.target).value)"
|
||||
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
<option value="">Root (no group)</option>
|
||||
@for (group of groups(); track group.ctime) {
|
||||
<option [value]="group.ctime">{{ group.title }}</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="flex items-center justify-end gap-3 mt-6">
|
||||
<button
|
||||
(click)="onCancel()"
|
||||
class="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 rounded-md transition-colors">
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
(click)="onSave()"
|
||||
class="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-md transition-colors">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,16 @@
|
||||
:host {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
select {
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E");
|
||||
background-position: right 0.5rem center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 1.5em 1.5em;
|
||||
padding-right: 2.5rem;
|
||||
}
|
||||
|
||||
:host-context(.dark) select {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%239ca3af' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E");
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Add Bookmark Modal Component
|
||||
*/
|
||||
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
Input,
|
||||
Output,
|
||||
EventEmitter,
|
||||
signal,
|
||||
computed,
|
||||
inject,
|
||||
} from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { BookmarksService } from '../../core/bookmarks/bookmarks.service';
|
||||
import type { BookmarkGroup } from '../../core/bookmarks/types';
|
||||
|
||||
export interface BookmarkFormData {
|
||||
path: string;
|
||||
title: string;
|
||||
groupCtime: number | null;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-add-bookmark-modal',
|
||||
imports: [CommonModule, FormsModule],
|
||||
templateUrl: './add-bookmark-modal.component.html',
|
||||
styleUrls: ['./add-bookmark-modal.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class AddBookmarkModalComponent {
|
||||
private readonly bookmarksService = inject(BookmarksService);
|
||||
|
||||
@Input() notePath: string = '';
|
||||
@Input() noteTitle: string = '';
|
||||
@Input() existingBookmark: { ctime: number; title?: string; groupCtime?: number } | null = null;
|
||||
|
||||
@Output() close = new EventEmitter<void>();
|
||||
@Output() save = new EventEmitter<BookmarkFormData>();
|
||||
|
||||
readonly path = signal('');
|
||||
readonly title = signal('');
|
||||
readonly selectedGroupCtime = signal<number | null>(null);
|
||||
|
||||
readonly groups = computed(() => {
|
||||
const doc = this.bookmarksService.doc();
|
||||
const result: Array<{ ctime: number; title: string }> = [];
|
||||
|
||||
const collectGroups = (items: any[], level = 0) => {
|
||||
for (const item of items) {
|
||||
if (item.type === 'group') {
|
||||
result.push({
|
||||
ctime: item.ctime,
|
||||
title: ' '.repeat(level) + (item.title || 'Untitled Group'),
|
||||
});
|
||||
if (item.items) {
|
||||
collectGroups(item.items, level + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
collectGroups(doc.items);
|
||||
return result;
|
||||
});
|
||||
|
||||
readonly isEditMode = computed(() => this.existingBookmark !== null);
|
||||
|
||||
ngOnInit(): void {
|
||||
this.path.set(this.notePath);
|
||||
this.title.set(this.noteTitle);
|
||||
|
||||
if (this.existingBookmark) {
|
||||
this.title.set(this.existingBookmark.title || this.noteTitle);
|
||||
this.selectedGroupCtime.set(this.existingBookmark.groupCtime || null);
|
||||
}
|
||||
}
|
||||
|
||||
onPathChange(value: string): void {
|
||||
this.path.set(value);
|
||||
}
|
||||
|
||||
onTitleChange(value: string): void {
|
||||
this.title.set(value);
|
||||
}
|
||||
|
||||
onGroupChange(value: string): void {
|
||||
const ctime = value ? parseInt(value, 10) : null;
|
||||
this.selectedGroupCtime.set(ctime);
|
||||
}
|
||||
|
||||
onSave(): void {
|
||||
const pathValue = this.path().trim();
|
||||
const titleValue = this.title().trim();
|
||||
|
||||
if (!pathValue) {
|
||||
alert('Path is required');
|
||||
return;
|
||||
}
|
||||
|
||||
this.save.emit({
|
||||
path: pathValue,
|
||||
title: titleValue || pathValue,
|
||||
groupCtime: this.selectedGroupCtime(),
|
||||
});
|
||||
}
|
||||
|
||||
onCancel(): void {
|
||||
this.close.emit();
|
||||
}
|
||||
|
||||
onBackdropClick(event: MouseEvent): void {
|
||||
if (event.target === event.currentTarget) {
|
||||
this.close.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user