@shival99/z-ui 2.1.18 → 2.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/css/base.css +2 -46
- package/assets/css/global.css +100 -0
- package/fesm2022/shival99-z-ui-components-z-autocomplete.mjs +29 -16
- package/fesm2022/shival99-z-ui-components-z-autocomplete.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-calendar.mjs +1 -1
- package/fesm2022/shival99-z-ui-components-z-calendar.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-gallery.mjs +1 -1
- package/fesm2022/shival99-z-ui-components-z-gallery.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-input.mjs +1 -1
- package/fesm2022/shival99-z-ui-components-z-input.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-kanban.mjs +1 -1
- package/fesm2022/shival99-z-ui-components-z-kanban.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-pagination.mjs +1 -1
- package/fesm2022/shival99-z-ui-components-z-pagination.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-popover.mjs +9 -3
- package/fesm2022/shival99-z-ui-components-z-popover.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-select.mjs +48 -21
- package/fesm2022/shival99-z-ui-components-z-select.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-table.mjs +3 -3
- package/fesm2022/shival99-z-ui-components-z-table.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-timeline.mjs +129 -9
- package/fesm2022/shival99-z-ui-components-z-timeline.mjs.map +1 -1
- package/package.json +1 -1
- package/types/shival99-z-ui-components-z-autocomplete.d.ts +2 -0
- package/types/shival99-z-ui-components-z-popover.d.ts +2 -0
- package/types/shival99-z-ui-components-z-select.d.ts +8 -2
- package/types/shival99-z-ui-components-z-timeline.d.ts +10 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { NgTemplateOutlet } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { input, computed, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { input, booleanAttribute, inject, DestroyRef, viewChildren, signal, computed, effect, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
4
4
|
import { ZIconComponent } from '@shival99/z-ui/components/z-icon';
|
|
5
5
|
import { zMergeClasses } from '@shival99/z-ui/utils';
|
|
6
6
|
import { cva } from 'class-variance-authority';
|
|
7
7
|
|
|
8
8
|
// Host container
|
|
9
|
-
const zTimelineVariants = cva(['relative block'], {
|
|
9
|
+
const zTimelineVariants = cva(['z-timeline relative block min-w-0'], {
|
|
10
10
|
variants: {
|
|
11
11
|
zSize: {
|
|
12
12
|
sm: 'text-sm',
|
|
@@ -46,7 +46,7 @@ const zTimelineInnerDotVariants = cva(['rounded-full bg-primary transition-color
|
|
|
46
46
|
});
|
|
47
47
|
// Time badge
|
|
48
48
|
const zTimelineTimeBadgeVariants = cva([
|
|
49
|
-
'inline-flex w-fit shrink-0 items-center justify-center rounded-
|
|
49
|
+
'inline-flex w-fit max-w-full shrink-0 items-center justify-center rounded-md bg-primary px-2 py-0.5 text-sm font-semibold leading-tight text-primary-foreground transition-colors duration-300',
|
|
50
50
|
], {
|
|
51
51
|
variants: {
|
|
52
52
|
zSize: {
|
|
@@ -63,9 +63,9 @@ const zTimelineTimeBadgeVariants = cva([
|
|
|
63
63
|
const zTimelineTitleVariants = cva(['font-medium leading-snug text-foreground'], {
|
|
64
64
|
variants: {
|
|
65
65
|
zSize: {
|
|
66
|
-
sm: 'text-
|
|
67
|
-
default: 'text-
|
|
68
|
-
lg: 'text-
|
|
66
|
+
sm: 'text-sm',
|
|
67
|
+
default: 'text-base md:text-lg',
|
|
68
|
+
lg: 'text-lg md:text-xl',
|
|
69
69
|
},
|
|
70
70
|
},
|
|
71
71
|
defaultVariants: {
|
|
@@ -91,6 +91,10 @@ class ZTimelineComponent {
|
|
|
91
91
|
zItems = input([], ...(ngDevMode ? [{ debugName: "zItems" }] : []));
|
|
92
92
|
zSize = input('default', ...(ngDevMode ? [{ debugName: "zSize" }] : []));
|
|
93
93
|
zLayout = input('default', ...(ngDevMode ? [{ debugName: "zLayout" }] : []));
|
|
94
|
+
zScrollProgress = input(false, { ...(ngDevMode ? { debugName: "zScrollProgress" } : {}), transform: booleanAttribute });
|
|
95
|
+
_destroyRef = inject(DestroyRef);
|
|
96
|
+
_timelineItems = viewChildren('timelineItem', ...(ngDevMode ? [{ debugName: "_timelineItems" }] : []));
|
|
97
|
+
_progressRatio = signal(0, ...(ngDevMode ? [{ debugName: "_progressRatio" }] : []));
|
|
94
98
|
hostClasses = computed(() => zMergeClasses(zTimelineVariants({ zSize: this.zSize() }), this.class()), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
|
|
95
99
|
dotClasses = computed(() => zTimelineDotVariants({ zSize: this.zSize() }), ...(ngDevMode ? [{ debugName: "dotClasses" }] : []));
|
|
96
100
|
innerDotClasses = computed(() => zTimelineInnerDotVariants({ zSize: this.zSize() }), ...(ngDevMode ? [{ debugName: "innerDotClasses" }] : []));
|
|
@@ -99,15 +103,131 @@ class ZTimelineComponent {
|
|
|
99
103
|
descriptionClasses = computed(() => zTimelineDescriptionVariants({ zSize: this.zSize() }), ...(ngDevMode ? [{ debugName: "descriptionClasses" }] : []));
|
|
100
104
|
isCareer = computed(() => this.zLayout() === 'career', ...(ngDevMode ? [{ debugName: "isCareer" }] : []));
|
|
101
105
|
isAlternate = computed(() => this.zLayout() === 'alternate', ...(ngDevMode ? [{ debugName: "isAlternate" }] : []));
|
|
106
|
+
progressStates = computed(() => {
|
|
107
|
+
const items = this.zItems();
|
|
108
|
+
if (!this.zScrollProgress()) {
|
|
109
|
+
return items.map(() => true);
|
|
110
|
+
}
|
|
111
|
+
const lastIndex = items.length - 1;
|
|
112
|
+
const progressRatio = this._progressRatio();
|
|
113
|
+
if (lastIndex <= 0) {
|
|
114
|
+
return items.map(() => progressRatio > 0);
|
|
115
|
+
}
|
|
116
|
+
return items.map((_item, index) => {
|
|
117
|
+
if (index === 0) {
|
|
118
|
+
return progressRatio > 0;
|
|
119
|
+
}
|
|
120
|
+
return progressRatio >= index / lastIndex;
|
|
121
|
+
});
|
|
122
|
+
}, ...(ngDevMode ? [{ debugName: "progressStates" }] : []));
|
|
123
|
+
progressLineHeight = computed(() => {
|
|
124
|
+
if (!this.zScrollProgress()) {
|
|
125
|
+
return '100%';
|
|
126
|
+
}
|
|
127
|
+
return `${this._progressRatio() * 100}%`;
|
|
128
|
+
}, ...(ngDevMode ? [{ debugName: "progressLineHeight" }] : []));
|
|
129
|
+
progressSegments = computed(() => {
|
|
130
|
+
const items = this.zItems();
|
|
131
|
+
const lastIndex = items.length - 1;
|
|
132
|
+
if (!this.zScrollProgress()) {
|
|
133
|
+
return items.map(() => '100%');
|
|
134
|
+
}
|
|
135
|
+
if (lastIndex <= 0) {
|
|
136
|
+
return items.map(() => `${this._progressRatio() * 100}%`);
|
|
137
|
+
}
|
|
138
|
+
const progressRatio = this._progressRatio();
|
|
139
|
+
return items.map((_item, index) => {
|
|
140
|
+
const segmentStart = index / lastIndex;
|
|
141
|
+
const segmentEnd = (index + 1) / lastIndex;
|
|
142
|
+
const segmentProgress = (progressRatio - segmentStart) / (segmentEnd - segmentStart);
|
|
143
|
+
const boundedProgress = Math.min(Math.max(segmentProgress, 0), 1);
|
|
144
|
+
return `${boundedProgress * 100}%`;
|
|
145
|
+
});
|
|
146
|
+
}, ...(ngDevMode ? [{ debugName: "progressSegments" }] : []));
|
|
147
|
+
constructor() {
|
|
148
|
+
effect(onCleanup => {
|
|
149
|
+
if (!this.zScrollProgress()) {
|
|
150
|
+
this._progressRatio.set(0);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (typeof window === 'undefined') {
|
|
154
|
+
this._progressRatio.set(1);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const elements = this._timelineItems().map(item => item.nativeElement);
|
|
158
|
+
if (!elements.length) {
|
|
159
|
+
this._progressRatio.set(0);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
let animationFrame = null;
|
|
163
|
+
const updateProgress = () => {
|
|
164
|
+
this._progressRatio.set(this._calculateProgressRatio(elements));
|
|
165
|
+
};
|
|
166
|
+
const scheduleUpdate = () => {
|
|
167
|
+
if (animationFrame !== null) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
animationFrame = window.requestAnimationFrame(() => {
|
|
171
|
+
animationFrame = null;
|
|
172
|
+
updateProgress();
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
scheduleUpdate();
|
|
176
|
+
window.addEventListener('scroll', scheduleUpdate, { passive: true });
|
|
177
|
+
window.addEventListener('resize', scheduleUpdate);
|
|
178
|
+
onCleanup(() => {
|
|
179
|
+
window.removeEventListener('scroll', scheduleUpdate);
|
|
180
|
+
window.removeEventListener('resize', scheduleUpdate);
|
|
181
|
+
if (animationFrame === null) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
window.cancelAnimationFrame(animationFrame);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
this._destroyRef.onDestroy(() => this._progressRatio.set(0));
|
|
188
|
+
}
|
|
189
|
+
_calculateProgressRatio(elements) {
|
|
190
|
+
if (!elements.length) {
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
const triggerY = window.innerHeight * 0.55;
|
|
194
|
+
const itemTops = elements.map(element => element.getBoundingClientRect().top);
|
|
195
|
+
const firstTop = itemTops[0];
|
|
196
|
+
const lastTop = itemTops[itemTops.length - 1];
|
|
197
|
+
if (triggerY <= firstTop) {
|
|
198
|
+
return 0;
|
|
199
|
+
}
|
|
200
|
+
if (triggerY >= lastTop) {
|
|
201
|
+
return 1;
|
|
202
|
+
}
|
|
203
|
+
const activeSegmentIndex = itemTops.findIndex((top, index) => {
|
|
204
|
+
const nextTop = itemTops[index + 1];
|
|
205
|
+
if (nextTop === undefined) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
return triggerY >= top && triggerY < nextTop;
|
|
209
|
+
});
|
|
210
|
+
if (activeSegmentIndex < 0) {
|
|
211
|
+
return 0;
|
|
212
|
+
}
|
|
213
|
+
const segmentStart = itemTops[activeSegmentIndex];
|
|
214
|
+
const segmentEnd = itemTops[activeSegmentIndex + 1];
|
|
215
|
+
const segmentDistance = segmentEnd - segmentStart;
|
|
216
|
+
if (segmentDistance <= 0) {
|
|
217
|
+
return 0;
|
|
218
|
+
}
|
|
219
|
+
const localProgress = (triggerY - segmentStart) / segmentDistance;
|
|
220
|
+
return (activeSegmentIndex + localProgress) / (itemTops.length - 1);
|
|
221
|
+
}
|
|
102
222
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTimelineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
103
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.9", type: ZTimelineComponent, isStandalone: true, selector: "z-timeline", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, zItems: { classPropertyName: "zItems", publicName: "zItems", isSignal: true, isRequired: false, transformFunction: null }, zSize: { classPropertyName: "zSize", publicName: "zSize", isSignal: true, isRequired: false, transformFunction: null }, zLayout: { classPropertyName: "zLayout", publicName: "zLayout", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, ngImport: i0, template: "@if (isCareer()) {\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- CAREER / EXPERIENCE LAYOUT -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <div class=\"mx-auto w-full max-w-3xl px-2 sm:px-4\">\n <div class=\"relative ml-3\">\n <div class=\"bg-border absolute top-3 bottom-3 left-0 w-0.5\"></div>\n\n @for (item of zItems(); track item.id ?? $index; let isLast = $last) {\n <article class=\"relative pb-10 pl-8\" [class.pb-0]=\"isLast\">\n <span\n class=\"bg-background border-primary absolute top-2 left-0 z-[1] size-3 -translate-x-1/2 rounded-full border-2\"></span>\n\n <div class=\"space-y-3\">\n <div class=\"flex items-center gap-2.5\">\n <div class=\"bg-accent flex size-9 shrink-0 items-center justify-center rounded-full\">\n <z-icon [zType]=\"item.icon ?? 'lucideBuilding2'\" zSize=\"18\" class=\"text-muted-foreground\" />\n </div>\n <span class=\"text-base font-medium\">{{ item.company ?? item.subtitle ?? 'Experience' }}</span>\n </div>\n\n <div class=\"space-y-2\">\n <h3 class=\"text-foreground text-xl leading-tight font-semibold tracking-[-0.01em]\">{{ item.title }}</h3>\n @if (item.period || item.time) {\n <div class=\"text-muted-foreground flex items-center gap-2 text-sm\">\n <z-icon zType=\"lucideCalendar\" zSize=\"15\" class=\"shrink-0\" />\n <span>{{ item.period ?? item.time }}</span>\n </div>\n }\n </div>\n\n @if (item.description) {\n <p class=\"text-muted-foreground text-sm leading-relaxed sm:text-base\">{{ item.description }}</p>\n }\n\n @if (item.technologies?.length) {\n <div class=\"flex flex-wrap gap-2\">\n @for (tech of item.technologies; track tech) {\n <span\n class=\"bg-secondary text-secondary-foreground inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-medium\">\n {{ tech }}\n </span>\n }\n </div>\n }\n\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </article>\n }\n </div>\n </div>\n} @else if (isAlternate()) {\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- ALTERNATE / ZIGZAG LAYOUT -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <div class=\"relative mx-auto max-w-7xl space-y-4\">\n @for (item of zItems(); track item.id ?? $index; let isEven = $even) {\n <div class=\"flex items-start md:flex-row\" [class.md:flex-row-reverse]=\"!isEven\">\n <!-- Opposite-side badge (desktop only) -->\n <div\n class=\"hidden w-full md:flex md:flex-1 md:items-start\"\n [class.md:justify-end]=\"isEven\"\n [class.md:justify-start]=\"!isEven\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\">{{ item.time }}</span>\n }\n </div>\n\n <!-- Center marker column -->\n <div class=\"relative flex flex-col items-center pr-4 md:px-4\">\n <div class=\"z-40 flex items-center justify-center\">\n <span [class]=\"dotClasses()\">\n <span [class]=\"innerDotClasses()\"></span>\n </span>\n </div>\n </div>\n\n <!-- Content side -->\n <div class=\"w-full md:flex md:flex-1\" [class.md:justify-start]=\"isEven\" [class.md:justify-end]=\"!isEven\">\n <!-- Mobile badge -->\n @if (item.time) {\n <span [class]=\"badgeClasses()\" class=\"mb-4 block text-left md:hidden\">{{ item.time }}</span>\n }\n\n <div>\n <!-- Card -->\n <div\n class=\"bg-card text-card-foreground mb-8 flex flex-col gap-6 overflow-hidden rounded-xl border py-6 shadow-sm md:max-w-136\">\n <div class=\"space-y-4 px-6\">\n <div [class]=\"titleClasses()\">{{ item.title }}</div>\n @if (item.description) {\n <p [class]=\"descriptionClasses()\">{{ item.description }}</p>\n }\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- Vertical line (absolute, behind everything) -->\n <div class=\"bg-border absolute top-3 bottom-3 left-3 w-0.5 overflow-hidden md:left-1/2 md:-translate-x-1/2\">\n <div class=\"bg-primary absolute inset-x-0 top-0 w-0.5 rounded-full\" style=\"height: 100%; opacity: 1\"></div>\n </div>\n </div>\n} @else {\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- DEFAULT / CHANGELOG LAYOUT -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n @for (item of zItems(); track item.id ?? $index; let isLast = $last) {\n <div class=\"relative flex justify-end gap-2\">\n <!-- Left: badge + subtitle (desktop only) -->\n <div class=\"flex w-36 flex-col items-end gap-2 self-start pb-4 max-md:hidden\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\">{{ item.time }}</span>\n }\n @if (item.subtitle) {\n <div class=\"text-muted-foreground text-right text-sm font-medium\">{{ item.subtitle }}</div>\n }\n </div>\n\n <!-- Center: dot + line -->\n <div class=\"relative flex flex-col items-center\">\n <div class=\"bg-background relative z-[1] flex size-6 items-center justify-center rounded-full\">\n <span [class]=\"dotClasses()\">\n <span [class]=\"innerDotClasses()\"></span>\n </span>\n </div>\n @if (!isLast) {\n <span class=\"bg-border absolute top-6 bottom-0 left-1/2 w-px -translate-x-1/2\"></span>\n <span class=\"w-px flex-1\"></span>\n }\n </div>\n\n <!-- Right: content -->\n <div class=\"flex flex-1 flex-col gap-4 pb-11 pl-3 md:pl-6 lg:pl-9\">\n <!-- Mobile badge + subtitle -->\n <div class=\"flex flex-col gap-2 md:hidden\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\" class=\"w-fit text-xs\">{{ item.time }}</span>\n }\n @if (item.subtitle) {\n <div class=\"font-medium\">{{ item.subtitle }}</div>\n }\n </div>\n\n <!-- Content -->\n <div class=\"space-y-4\">\n <div class=\"space-y-3\">\n <h3 [class]=\"titleClasses()\">{{ item.title }}</h3>\n @if (item.description) {\n <p [class]=\"descriptionClasses()\">{{ item.description }}</p>\n }\n </div>\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </div>\n </div>\n }\n}\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
223
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.9", type: ZTimelineComponent, isStandalone: true, selector: "z-timeline", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, zItems: { classPropertyName: "zItems", publicName: "zItems", isSignal: true, isRequired: false, transformFunction: null }, zSize: { classPropertyName: "zSize", publicName: "zSize", isSignal: true, isRequired: false, transformFunction: null }, zLayout: { classPropertyName: "zLayout", publicName: "zLayout", isSignal: true, isRequired: false, transformFunction: null }, zScrollProgress: { classPropertyName: "zScrollProgress", publicName: "zScrollProgress", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "hostClasses()" } }, viewQueries: [{ propertyName: "_timelineItems", predicate: ["timelineItem"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (isCareer()) {\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- CAREER / EXPERIENCE LAYOUT -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n @let progress = progressStates();\n <div class=\"mx-auto w-full max-w-3xl px-2 sm:px-4\">\n <div class=\"relative ml-3\">\n <div class=\"bg-border absolute top-3 bottom-3 left-0 w-0.5 overflow-hidden\">\n <div\n class=\"z-timeline-progress-line absolute inset-x-0 top-0 w-0.5\"\n [style.height]=\"zScrollProgress() ? progressLineHeight() : '0%'\"></div>\n </div>\n\n @for (item of zItems(); track item.id ?? $index; let isLast = $last) {\n @let isActive = progress[$index];\n <article\n #timelineItem\n class=\"relative pb-10 pl-8\"\n [class.pb-0]=\"isLast\"\n [class.z-timeline-progress-inactive]=\"zScrollProgress() && !isActive\">\n <span\n class=\"bg-background border-primary absolute top-2 left-0 z-[1] size-3 -translate-x-1/2 rounded-full border-2\"\n [class.z-timeline-progress-dot]=\"zScrollProgress()\"></span>\n\n <div class=\"space-y-3\">\n <div class=\"flex items-center gap-2.5\">\n <div class=\"bg-accent flex size-9 shrink-0 items-center justify-center rounded-full\">\n <z-icon [zType]=\"item.icon ?? 'lucideBuilding2'\" zSize=\"18\" class=\"text-muted-foreground\" />\n </div>\n <span class=\"text-base font-medium\">{{ item.company ?? item.subtitle ?? 'Experience' }}</span>\n </div>\n\n <div class=\"space-y-2\">\n <h3 class=\"text-foreground text-xl leading-tight font-semibold tracking-[-0.01em]\">{{ item.title }}</h3>\n @if (item.period || item.time) {\n <div class=\"text-muted-foreground flex items-center gap-2 text-sm\">\n <z-icon zType=\"lucideCalendar\" zSize=\"15\" class=\"shrink-0\" />\n <span>{{ item.period ?? item.time }}</span>\n </div>\n }\n </div>\n\n @if (item.description) {\n <p class=\"text-muted-foreground text-sm leading-relaxed sm:text-base\">{{ item.description }}</p>\n }\n\n @if (item.technologies?.length) {\n <div class=\"flex flex-wrap gap-2\">\n @for (tech of item.technologies; track tech) {\n <span\n class=\"bg-secondary text-secondary-foreground inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-medium\">\n {{ tech }}\n </span>\n }\n </div>\n }\n\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </article>\n }\n </div>\n </div>\n} @else if (isAlternate()) {\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- ALTERNATE / ZIGZAG LAYOUT -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n @let progress = progressStates();\n <div class=\"relative mx-auto max-w-7xl space-y-4\">\n @for (item of zItems(); track item.id ?? $index; let isEven = $even) {\n @let isActive = progress[$index];\n <div\n #timelineItem\n class=\"flex items-start md:flex-row\"\n [class.md:flex-row-reverse]=\"!isEven\"\n [class.z-timeline-progress-inactive]=\"zScrollProgress() && !isActive\">\n <!-- Opposite-side badge (desktop only) -->\n <div\n class=\"hidden w-full md:flex md:flex-1 md:items-start\"\n [class.md:justify-end]=\"isEven\"\n [class.md:justify-start]=\"!isEven\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\">{{ item.time }}</span>\n }\n </div>\n\n <!-- Center marker column -->\n <div class=\"relative flex flex-col items-center pr-4 md:px-4\">\n <div class=\"z-40 flex items-center justify-center\">\n <span [class]=\"dotClasses()\" [class.z-timeline-progress-dot-ring]=\"true\">\n <span [class]=\"innerDotClasses()\" [class.z-timeline-progress-dot]=\"true\"></span>\n </span>\n </div>\n </div>\n\n <!-- Content side -->\n <div class=\"w-full md:flex md:flex-1\" [class.md:justify-start]=\"isEven\" [class.md:justify-end]=\"!isEven\">\n <!-- Mobile badge -->\n @if (item.time) {\n <span [class]=\"badgeClasses()\" class=\"mb-4 block text-left md:hidden\">{{ item.time }}</span>\n }\n\n <div>\n <!-- Card -->\n <div\n class=\"bg-card text-card-foreground mb-8 flex flex-col gap-6 overflow-hidden rounded-xl border py-6 shadow-sm md:max-w-136\">\n <div class=\"space-y-4 px-6\">\n <div [class]=\"titleClasses()\">{{ item.title }}</div>\n @if (item.description) {\n <p [class]=\"descriptionClasses()\">{{ item.description }}</p>\n }\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- Vertical line (absolute, behind everything) -->\n <div class=\"bg-border absolute top-3 bottom-3 left-3 w-0.5 overflow-hidden md:left-1/2 md:-translate-x-1/2\">\n <div\n class=\"z-timeline-progress-line absolute inset-x-0 top-0 w-0.5 rounded-full\"\n [style.height]=\"progressLineHeight()\"></div>\n </div>\n </div>\n} @else {\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- DEFAULT / CHANGELOG LAYOUT -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n @let progress = progressStates();\n @let segments = progressSegments();\n @for (item of zItems(); track item.id ?? $index; let isLast = $last) {\n @let isActive = progress[$index];\n <article\n #timelineItem\n class=\"z-timeline-default-item relative grid grid-cols-[7rem_1.5rem_minmax(0,1fr)] gap-x-3\"\n [class.z-timeline-progress-inactive]=\"zScrollProgress() && !isActive\">\n <!-- Left: badge + subtitle (desktop only) -->\n <div class=\"z-timeline-default-meta flex min-w-0 flex-col items-end gap-2 self-start pb-4\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\">{{ item.time }}</span>\n }\n @if (item.subtitle) {\n <div class=\"text-muted-foreground max-w-full text-right text-sm leading-snug font-medium\">\n {{ item.subtitle }}\n </div>\n }\n </div>\n\n <!-- Center: dot + line -->\n <div class=\"relative flex flex-col items-center\">\n <div class=\"bg-background relative z-[1] flex size-6 items-center justify-center rounded-full\">\n <span [class]=\"dotClasses()\" [class.z-timeline-progress-dot-ring]=\"true\">\n <span [class]=\"innerDotClasses()\" [class.z-timeline-progress-dot]=\"true\"></span>\n </span>\n </div>\n @if (!isLast) {\n <span class=\"bg-border absolute top-6 bottom-0 left-1/2 w-px -translate-x-1/2 overflow-hidden rounded-full\">\n @if (zScrollProgress()) {\n <span\n class=\"z-timeline-progress-line absolute inset-x-0 top-0 w-px rounded-full\"\n [style.height]=\"segments[$index]\"></span>\n }\n </span>\n <span class=\"w-px flex-1\"></span>\n }\n </div>\n\n <!-- Right: content -->\n <div class=\"z-timeline-default-content flex min-w-0 flex-col gap-4 pb-10 pl-1\">\n <!-- Mobile badge + subtitle -->\n <div class=\"z-timeline-default-mobile-meta flex-col gap-2\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\" class=\"w-fit\">{{ item.time }}</span>\n }\n @if (item.subtitle) {\n <div class=\"text-muted-foreground text-sm font-medium\">{{ item.subtitle }}</div>\n }\n </div>\n\n <!-- Content -->\n <div class=\"min-w-0 space-y-4\">\n <div class=\"space-y-3\">\n <h3 [class]=\"titleClasses()\">{{ item.title }}</h3>\n @if (item.description) {\n <p [class]=\"descriptionClasses()\">{{ item.description }}</p>\n }\n </div>\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </div>\n </article>\n }\n}\n", styles: [".z-timeline{container-type:inline-size}.z-timeline-default-mobile-meta{display:none}.z-timeline-progress-dot{background:var(--primary);transition:background-color .18s ease,border-color .18s ease,box-shadow .18s ease}.z-timeline-progress-dot-ring{background:color-mix(in oklab,var(--primary) 14%,transparent);transition:background-color .18s ease}.z-timeline-progress-line{background:var(--primary);transition:height .12s linear}.z-timeline-progress-inactive .z-timeline-progress-dot-ring{background:var(--border)}.z-timeline-progress-inactive .z-timeline-progress-dot{background:var(--muted-foreground);border-color:var(--border)}@container (max-width: 34rem){.z-timeline-default-item{grid-template-columns:1.5rem minmax(0,1fr)}.z-timeline-default-meta{display:none}.z-timeline-default-mobile-meta{display:flex}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
104
224
|
}
|
|
105
225
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTimelineComponent, decorators: [{
|
|
106
226
|
type: Component,
|
|
107
227
|
args: [{ selector: 'z-timeline', imports: [NgTemplateOutlet, ZIconComponent], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
|
|
108
228
|
'[class]': 'hostClasses()',
|
|
109
|
-
}, template: "@if (isCareer()) {\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- CAREER / EXPERIENCE LAYOUT -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <div class=\"mx-auto w-full max-w-3xl px-2 sm:px-4\">\n <div class=\"relative ml-3\">\n <div class=\"bg-border absolute top-3 bottom-3 left-0 w-0.5\"></div>\n\n @for (item of zItems(); track item.id ?? $index; let isLast = $last) {\n <article class=\"relative pb-10 pl-8\" [class.pb-0]=\"isLast\">\n <span\n class=\"bg-background border-primary absolute top-2 left-0 z-[1] size-3 -translate-x-1/2 rounded-full border-2\"></span>\n\n <div class=\"space-y-3\">\n <div class=\"flex items-center gap-2.5\">\n <div class=\"bg-accent flex size-9 shrink-0 items-center justify-center rounded-full\">\n <z-icon [zType]=\"item.icon ?? 'lucideBuilding2'\" zSize=\"18\" class=\"text-muted-foreground\" />\n </div>\n <span class=\"text-base font-medium\">{{ item.company ?? item.subtitle ?? 'Experience' }}</span>\n </div>\n\n <div class=\"space-y-2\">\n <h3 class=\"text-foreground text-xl leading-tight font-semibold tracking-[-0.01em]\">{{ item.title }}</h3>\n @if (item.period || item.time) {\n <div class=\"text-muted-foreground flex items-center gap-2 text-sm\">\n <z-icon zType=\"lucideCalendar\" zSize=\"15\" class=\"shrink-0\" />\n <span>{{ item.period ?? item.time }}</span>\n </div>\n }\n </div>\n\n @if (item.description) {\n <p class=\"text-muted-foreground text-sm leading-relaxed sm:text-base\">{{ item.description }}</p>\n }\n\n @if (item.technologies?.length) {\n <div class=\"flex flex-wrap gap-2\">\n @for (tech of item.technologies; track tech) {\n <span\n class=\"bg-secondary text-secondary-foreground inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-medium\">\n {{ tech }}\n </span>\n }\n </div>\n }\n\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </article>\n }\n </div>\n </div>\n} @else if (isAlternate()) {\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- ALTERNATE / ZIGZAG LAYOUT -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <div class=\"relative mx-auto max-w-7xl space-y-4\">\n @for (item of zItems(); track item.id ?? $index; let isEven = $even) {\n <div class=\"flex items-start md:flex-row\" [class.md:flex-row-reverse]=\"!isEven\">\n <!-- Opposite-side badge (desktop only) -->\n <div\n class=\"hidden w-full md:flex md:flex-1 md:items-start\"\n [class.md:justify-end]=\"isEven\"\n [class.md:justify-start]=\"!isEven\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\">{{ item.time }}</span>\n }\n </div>\n\n <!-- Center marker column -->\n <div class=\"relative flex flex-col items-center pr-4 md:px-4\">\n <div class=\"z-40 flex items-center justify-center\">\n <span [class]=\"dotClasses()\">\n <span [class]=\"innerDotClasses()\"></span>\n </span>\n </div>\n </div>\n\n <!-- Content side -->\n <div class=\"w-full md:flex md:flex-1\" [class.md:justify-start]=\"isEven\" [class.md:justify-end]=\"!isEven\">\n <!-- Mobile badge -->\n @if (item.time) {\n <span [class]=\"badgeClasses()\" class=\"mb-4 block text-left md:hidden\">{{ item.time }}</span>\n }\n\n <div>\n <!-- Card -->\n <div\n class=\"bg-card text-card-foreground mb-8 flex flex-col gap-6 overflow-hidden rounded-xl border py-6 shadow-sm md:max-w-136\">\n <div class=\"space-y-4 px-6\">\n <div [class]=\"titleClasses()\">{{ item.title }}</div>\n @if (item.description) {\n <p [class]=\"descriptionClasses()\">{{ item.description }}</p>\n }\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- Vertical line (absolute, behind everything) -->\n <div class=\"bg-border absolute top-3 bottom-3 left-3 w-0.5 overflow-hidden md:left-1/2 md:-translate-x-1/2\">\n <div class=\"bg-primary absolute inset-x-0 top-0 w-0.5 rounded-full\" style=\"height: 100%; opacity: 1\"></div>\n </div>\n </div>\n} @else {\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- DEFAULT / CHANGELOG LAYOUT -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n @for (item of zItems(); track item.id ?? $index; let isLast = $last) {\n <div class=\"relative flex justify-end gap-2\">\n <!-- Left: badge + subtitle (desktop only) -->\n <div class=\"flex w-36 flex-col items-end gap-2 self-start pb-4 max-md:hidden\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\">{{ item.time }}</span>\n }\n @if (item.subtitle) {\n <div class=\"text-muted-foreground text-right text-sm font-medium\">{{ item.subtitle }}</div>\n }\n </div>\n\n <!-- Center: dot + line -->\n <div class=\"relative flex flex-col items-center\">\n <div class=\"bg-background relative z-[1] flex size-6 items-center justify-center rounded-full\">\n <span [class]=\"dotClasses()\">\n <span [class]=\"innerDotClasses()\"></span>\n </span>\n </div>\n @if (!isLast) {\n <span class=\"bg-border absolute top-6 bottom-0 left-1/2 w-px -translate-x-1/2\"></span>\n <span class=\"w-px flex-1\"></span>\n }\n </div>\n\n <!-- Right: content -->\n <div class=\"flex flex-1 flex-col gap-4 pb-11 pl-3 md:pl-6 lg:pl-9\">\n <!-- Mobile badge + subtitle -->\n <div class=\"flex flex-col gap-2 md:hidden\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\" class=\"w-fit text-xs\">{{ item.time }}</span>\n }\n @if (item.subtitle) {\n <div class=\"font-medium\">{{ item.subtitle }}</div>\n }\n </div>\n\n <!-- Content -->\n <div class=\"space-y-4\">\n <div class=\"space-y-3\">\n <h3 [class]=\"titleClasses()\">{{ item.title }}</h3>\n @if (item.description) {\n <p [class]=\"descriptionClasses()\">{{ item.description }}</p>\n }\n </div>\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </div>\n </div>\n }\n}\n" }]
|
|
110
|
-
}], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], zItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "zItems", required: false }] }], zSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSize", required: false }] }], zLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "zLayout", required: false }] }] } });
|
|
229
|
+
}, template: "@if (isCareer()) {\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- CAREER / EXPERIENCE LAYOUT -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n @let progress = progressStates();\n <div class=\"mx-auto w-full max-w-3xl px-2 sm:px-4\">\n <div class=\"relative ml-3\">\n <div class=\"bg-border absolute top-3 bottom-3 left-0 w-0.5 overflow-hidden\">\n <div\n class=\"z-timeline-progress-line absolute inset-x-0 top-0 w-0.5\"\n [style.height]=\"zScrollProgress() ? progressLineHeight() : '0%'\"></div>\n </div>\n\n @for (item of zItems(); track item.id ?? $index; let isLast = $last) {\n @let isActive = progress[$index];\n <article\n #timelineItem\n class=\"relative pb-10 pl-8\"\n [class.pb-0]=\"isLast\"\n [class.z-timeline-progress-inactive]=\"zScrollProgress() && !isActive\">\n <span\n class=\"bg-background border-primary absolute top-2 left-0 z-[1] size-3 -translate-x-1/2 rounded-full border-2\"\n [class.z-timeline-progress-dot]=\"zScrollProgress()\"></span>\n\n <div class=\"space-y-3\">\n <div class=\"flex items-center gap-2.5\">\n <div class=\"bg-accent flex size-9 shrink-0 items-center justify-center rounded-full\">\n <z-icon [zType]=\"item.icon ?? 'lucideBuilding2'\" zSize=\"18\" class=\"text-muted-foreground\" />\n </div>\n <span class=\"text-base font-medium\">{{ item.company ?? item.subtitle ?? 'Experience' }}</span>\n </div>\n\n <div class=\"space-y-2\">\n <h3 class=\"text-foreground text-xl leading-tight font-semibold tracking-[-0.01em]\">{{ item.title }}</h3>\n @if (item.period || item.time) {\n <div class=\"text-muted-foreground flex items-center gap-2 text-sm\">\n <z-icon zType=\"lucideCalendar\" zSize=\"15\" class=\"shrink-0\" />\n <span>{{ item.period ?? item.time }}</span>\n </div>\n }\n </div>\n\n @if (item.description) {\n <p class=\"text-muted-foreground text-sm leading-relaxed sm:text-base\">{{ item.description }}</p>\n }\n\n @if (item.technologies?.length) {\n <div class=\"flex flex-wrap gap-2\">\n @for (tech of item.technologies; track tech) {\n <span\n class=\"bg-secondary text-secondary-foreground inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-medium\">\n {{ tech }}\n </span>\n }\n </div>\n }\n\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </article>\n }\n </div>\n </div>\n} @else if (isAlternate()) {\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- ALTERNATE / ZIGZAG LAYOUT -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n @let progress = progressStates();\n <div class=\"relative mx-auto max-w-7xl space-y-4\">\n @for (item of zItems(); track item.id ?? $index; let isEven = $even) {\n @let isActive = progress[$index];\n <div\n #timelineItem\n class=\"flex items-start md:flex-row\"\n [class.md:flex-row-reverse]=\"!isEven\"\n [class.z-timeline-progress-inactive]=\"zScrollProgress() && !isActive\">\n <!-- Opposite-side badge (desktop only) -->\n <div\n class=\"hidden w-full md:flex md:flex-1 md:items-start\"\n [class.md:justify-end]=\"isEven\"\n [class.md:justify-start]=\"!isEven\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\">{{ item.time }}</span>\n }\n </div>\n\n <!-- Center marker column -->\n <div class=\"relative flex flex-col items-center pr-4 md:px-4\">\n <div class=\"z-40 flex items-center justify-center\">\n <span [class]=\"dotClasses()\" [class.z-timeline-progress-dot-ring]=\"true\">\n <span [class]=\"innerDotClasses()\" [class.z-timeline-progress-dot]=\"true\"></span>\n </span>\n </div>\n </div>\n\n <!-- Content side -->\n <div class=\"w-full md:flex md:flex-1\" [class.md:justify-start]=\"isEven\" [class.md:justify-end]=\"!isEven\">\n <!-- Mobile badge -->\n @if (item.time) {\n <span [class]=\"badgeClasses()\" class=\"mb-4 block text-left md:hidden\">{{ item.time }}</span>\n }\n\n <div>\n <!-- Card -->\n <div\n class=\"bg-card text-card-foreground mb-8 flex flex-col gap-6 overflow-hidden rounded-xl border py-6 shadow-sm md:max-w-136\">\n <div class=\"space-y-4 px-6\">\n <div [class]=\"titleClasses()\">{{ item.title }}</div>\n @if (item.description) {\n <p [class]=\"descriptionClasses()\">{{ item.description }}</p>\n }\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- Vertical line (absolute, behind everything) -->\n <div class=\"bg-border absolute top-3 bottom-3 left-3 w-0.5 overflow-hidden md:left-1/2 md:-translate-x-1/2\">\n <div\n class=\"z-timeline-progress-line absolute inset-x-0 top-0 w-0.5 rounded-full\"\n [style.height]=\"progressLineHeight()\"></div>\n </div>\n </div>\n} @else {\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- DEFAULT / CHANGELOG LAYOUT -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n @let progress = progressStates();\n @let segments = progressSegments();\n @for (item of zItems(); track item.id ?? $index; let isLast = $last) {\n @let isActive = progress[$index];\n <article\n #timelineItem\n class=\"z-timeline-default-item relative grid grid-cols-[7rem_1.5rem_minmax(0,1fr)] gap-x-3\"\n [class.z-timeline-progress-inactive]=\"zScrollProgress() && !isActive\">\n <!-- Left: badge + subtitle (desktop only) -->\n <div class=\"z-timeline-default-meta flex min-w-0 flex-col items-end gap-2 self-start pb-4\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\">{{ item.time }}</span>\n }\n @if (item.subtitle) {\n <div class=\"text-muted-foreground max-w-full text-right text-sm leading-snug font-medium\">\n {{ item.subtitle }}\n </div>\n }\n </div>\n\n <!-- Center: dot + line -->\n <div class=\"relative flex flex-col items-center\">\n <div class=\"bg-background relative z-[1] flex size-6 items-center justify-center rounded-full\">\n <span [class]=\"dotClasses()\" [class.z-timeline-progress-dot-ring]=\"true\">\n <span [class]=\"innerDotClasses()\" [class.z-timeline-progress-dot]=\"true\"></span>\n </span>\n </div>\n @if (!isLast) {\n <span class=\"bg-border absolute top-6 bottom-0 left-1/2 w-px -translate-x-1/2 overflow-hidden rounded-full\">\n @if (zScrollProgress()) {\n <span\n class=\"z-timeline-progress-line absolute inset-x-0 top-0 w-px rounded-full\"\n [style.height]=\"segments[$index]\"></span>\n }\n </span>\n <span class=\"w-px flex-1\"></span>\n }\n </div>\n\n <!-- Right: content -->\n <div class=\"z-timeline-default-content flex min-w-0 flex-col gap-4 pb-10 pl-1\">\n <!-- Mobile badge + subtitle -->\n <div class=\"z-timeline-default-mobile-meta flex-col gap-2\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\" class=\"w-fit\">{{ item.time }}</span>\n }\n @if (item.subtitle) {\n <div class=\"text-muted-foreground text-sm font-medium\">{{ item.subtitle }}</div>\n }\n </div>\n\n <!-- Content -->\n <div class=\"min-w-0 space-y-4\">\n <div class=\"space-y-3\">\n <h3 [class]=\"titleClasses()\">{{ item.title }}</h3>\n @if (item.description) {\n <p [class]=\"descriptionClasses()\">{{ item.description }}</p>\n }\n </div>\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </div>\n </article>\n }\n}\n", styles: [".z-timeline{container-type:inline-size}.z-timeline-default-mobile-meta{display:none}.z-timeline-progress-dot{background:var(--primary);transition:background-color .18s ease,border-color .18s ease,box-shadow .18s ease}.z-timeline-progress-dot-ring{background:color-mix(in oklab,var(--primary) 14%,transparent);transition:background-color .18s ease}.z-timeline-progress-line{background:var(--primary);transition:height .12s linear}.z-timeline-progress-inactive .z-timeline-progress-dot-ring{background:var(--border)}.z-timeline-progress-inactive .z-timeline-progress-dot{background:var(--muted-foreground);border-color:var(--border)}@container (max-width: 34rem){.z-timeline-default-item{grid-template-columns:1.5rem minmax(0,1fr)}.z-timeline-default-meta{display:none}.z-timeline-default-mobile-meta{display:flex}}\n"] }]
|
|
230
|
+
}], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], zItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "zItems", required: false }] }], zSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSize", required: false }] }], zLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "zLayout", required: false }] }], zScrollProgress: [{ type: i0.Input, args: [{ isSignal: true, alias: "zScrollProgress", required: false }] }], _timelineItems: [{ type: i0.ViewChildren, args: ['timelineItem', { isSignal: true }] }] } });
|
|
111
231
|
|
|
112
232
|
/**
|
|
113
233
|
* Generated bundle index. Do not edit.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shival99-z-ui-components-z-timeline.mjs","sources":["../../../../libs/core-ui/components/z-timeline/z-timeline.variants.ts","../../../../libs/core-ui/components/z-timeline/z-timeline.component.ts","../../../../libs/core-ui/components/z-timeline/z-timeline.component.html","../../../../libs/core-ui/components/z-timeline/shival99-z-ui-components-z-timeline.ts"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\n\n// Host container\nexport const zTimelineVariants = cva(['relative block'], {\n variants: {\n zSize: {\n sm: 'text-sm',\n default: 'text-base',\n lg: 'text-lg',\n },\n },\n defaultVariants: {\n zSize: 'default',\n },\n});\n\n// Outer dot ring\nexport const zTimelineDotVariants = cva(\n ['flex shrink-0 items-center justify-center rounded-full bg-primary/10 transition-colors duration-300'],\n {\n variants: {\n zSize: {\n sm: 'size-4.5',\n default: 'size-6',\n lg: 'size-7',\n },\n },\n defaultVariants: {\n zSize: 'default',\n },\n }\n);\n\n// Inner dot\nexport const zTimelineInnerDotVariants = cva(['rounded-full bg-primary transition-colors duration-300'], {\n variants: {\n zSize: {\n sm: 'size-2',\n default: 'size-3',\n lg: 'size-3.5',\n },\n },\n defaultVariants: {\n zSize: 'default',\n },\n});\n\n// Time badge\nexport const zTimelineTimeBadgeVariants = cva(\n [\n 'inline-flex w-fit shrink-0 items-center justify-center rounded-sm bg-primary px-2 py-0.5 text-sm font-medium text-primary-foreground transition-colors duration-300',\n ],\n {\n variants: {\n zSize: {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-sm',\n },\n },\n defaultVariants: {\n zSize: 'default',\n },\n }\n);\n\n// Title\nexport const zTimelineTitleVariants = cva(['font-medium leading-snug text-foreground'], {\n variants: {\n zSize: {\n sm: 'text-base',\n default: 'text-lg md:text-xl lg:text-2xl',\n lg: 'text-xl md:text-2xl',\n },\n },\n defaultVariants: {\n zSize: 'default',\n },\n});\n\n// Description\nexport const zTimelineDescriptionVariants = cva(['text-muted-foreground leading-relaxed'], {\n variants: {\n zSize: {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-base',\n },\n },\n defaultVariants: {\n zSize: 'default',\n },\n});\n\nexport type ZTimelineVariants = VariantProps<typeof zTimelineVariants>;\n","import { NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed, input, ViewEncapsulation } from '@angular/core';\nimport { ZIconComponent } from '@shival99/z-ui/components/z-icon';\nimport { zMergeClasses } from '@shival99/z-ui/utils';\nimport type { ClassValue } from 'clsx';\nimport type { ZTimelineItem, ZTimelineLayout, ZTimelineSize } from './z-timeline.types';\nimport {\n zTimelineDescriptionVariants,\n zTimelineDotVariants,\n zTimelineInnerDotVariants,\n zTimelineTimeBadgeVariants,\n zTimelineTitleVariants,\n zTimelineVariants,\n} from './z-timeline.variants';\n\n@Component({\n selector: 'z-timeline',\n imports: [NgTemplateOutlet, ZIconComponent],\n standalone: true,\n templateUrl: './z-timeline.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': 'hostClasses()',\n },\n})\nexport class ZTimelineComponent {\n public readonly class = input<ClassValue>('');\n public readonly zItems = input<ZTimelineItem[]>([]);\n public readonly zSize = input<ZTimelineSize>('default');\n public readonly zLayout = input<ZTimelineLayout>('default');\n\n protected readonly hostClasses = computed(() =>\n zMergeClasses(zTimelineVariants({ zSize: this.zSize() }), this.class())\n );\n\n protected readonly dotClasses = computed(() => zTimelineDotVariants({ zSize: this.zSize() }));\n\n protected readonly innerDotClasses = computed(() => zTimelineInnerDotVariants({ zSize: this.zSize() }));\n\n protected readonly badgeClasses = computed(() => zTimelineTimeBadgeVariants({ zSize: this.zSize() }));\n\n protected readonly titleClasses = computed(() => zTimelineTitleVariants({ zSize: this.zSize() }));\n\n protected readonly descriptionClasses = computed(() => zTimelineDescriptionVariants({ zSize: this.zSize() }));\n\n protected readonly isCareer = computed(() => this.zLayout() === 'career');\n\n protected readonly isAlternate = computed(() => this.zLayout() === 'alternate');\n}\n","@if (isCareer()) {\n <!-- ══════════════════════════════════════════════════════════ -->\n <!-- CAREER / EXPERIENCE LAYOUT -->\n <!-- ══════════════════════════════════════════════════════════ -->\n <div class=\"mx-auto w-full max-w-3xl px-2 sm:px-4\">\n <div class=\"relative ml-3\">\n <div class=\"bg-border absolute top-3 bottom-3 left-0 w-0.5\"></div>\n\n @for (item of zItems(); track item.id ?? $index; let isLast = $last) {\n <article class=\"relative pb-10 pl-8\" [class.pb-0]=\"isLast\">\n <span\n class=\"bg-background border-primary absolute top-2 left-0 z-[1] size-3 -translate-x-1/2 rounded-full border-2\"></span>\n\n <div class=\"space-y-3\">\n <div class=\"flex items-center gap-2.5\">\n <div class=\"bg-accent flex size-9 shrink-0 items-center justify-center rounded-full\">\n <z-icon [zType]=\"item.icon ?? 'lucideBuilding2'\" zSize=\"18\" class=\"text-muted-foreground\" />\n </div>\n <span class=\"text-base font-medium\">{{ item.company ?? item.subtitle ?? 'Experience' }}</span>\n </div>\n\n <div class=\"space-y-2\">\n <h3 class=\"text-foreground text-xl leading-tight font-semibold tracking-[-0.01em]\">{{ item.title }}</h3>\n @if (item.period || item.time) {\n <div class=\"text-muted-foreground flex items-center gap-2 text-sm\">\n <z-icon zType=\"lucideCalendar\" zSize=\"15\" class=\"shrink-0\" />\n <span>{{ item.period ?? item.time }}</span>\n </div>\n }\n </div>\n\n @if (item.description) {\n <p class=\"text-muted-foreground text-sm leading-relaxed sm:text-base\">{{ item.description }}</p>\n }\n\n @if (item.technologies?.length) {\n <div class=\"flex flex-wrap gap-2\">\n @for (tech of item.technologies; track tech) {\n <span\n class=\"bg-secondary text-secondary-foreground inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-medium\">\n {{ tech }}\n </span>\n }\n </div>\n }\n\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </article>\n }\n </div>\n </div>\n} @else if (isAlternate()) {\n <!-- ══════════════════════════════════════════════════════════ -->\n <!-- ALTERNATE / ZIGZAG LAYOUT -->\n <!-- ══════════════════════════════════════════════════════════ -->\n <div class=\"relative mx-auto max-w-7xl space-y-4\">\n @for (item of zItems(); track item.id ?? $index; let isEven = $even) {\n <div class=\"flex items-start md:flex-row\" [class.md:flex-row-reverse]=\"!isEven\">\n <!-- Opposite-side badge (desktop only) -->\n <div\n class=\"hidden w-full md:flex md:flex-1 md:items-start\"\n [class.md:justify-end]=\"isEven\"\n [class.md:justify-start]=\"!isEven\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\">{{ item.time }}</span>\n }\n </div>\n\n <!-- Center marker column -->\n <div class=\"relative flex flex-col items-center pr-4 md:px-4\">\n <div class=\"z-40 flex items-center justify-center\">\n <span [class]=\"dotClasses()\">\n <span [class]=\"innerDotClasses()\"></span>\n </span>\n </div>\n </div>\n\n <!-- Content side -->\n <div class=\"w-full md:flex md:flex-1\" [class.md:justify-start]=\"isEven\" [class.md:justify-end]=\"!isEven\">\n <!-- Mobile badge -->\n @if (item.time) {\n <span [class]=\"badgeClasses()\" class=\"mb-4 block text-left md:hidden\">{{ item.time }}</span>\n }\n\n <div>\n <!-- Card -->\n <div\n class=\"bg-card text-card-foreground mb-8 flex flex-col gap-6 overflow-hidden rounded-xl border py-6 shadow-sm md:max-w-136\">\n <div class=\"space-y-4 px-6\">\n <div [class]=\"titleClasses()\">{{ item.title }}</div>\n @if (item.description) {\n <p [class]=\"descriptionClasses()\">{{ item.description }}</p>\n }\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- Vertical line (absolute, behind everything) -->\n <div class=\"bg-border absolute top-3 bottom-3 left-3 w-0.5 overflow-hidden md:left-1/2 md:-translate-x-1/2\">\n <div class=\"bg-primary absolute inset-x-0 top-0 w-0.5 rounded-full\" style=\"height: 100%; opacity: 1\"></div>\n </div>\n </div>\n} @else {\n <!-- ══════════════════════════════════════════════════════════ -->\n <!-- DEFAULT / CHANGELOG LAYOUT -->\n <!-- ══════════════════════════════════════════════════════════ -->\n @for (item of zItems(); track item.id ?? $index; let isLast = $last) {\n <div class=\"relative flex justify-end gap-2\">\n <!-- Left: badge + subtitle (desktop only) -->\n <div class=\"flex w-36 flex-col items-end gap-2 self-start pb-4 max-md:hidden\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\">{{ item.time }}</span>\n }\n @if (item.subtitle) {\n <div class=\"text-muted-foreground text-right text-sm font-medium\">{{ item.subtitle }}</div>\n }\n </div>\n\n <!-- Center: dot + line -->\n <div class=\"relative flex flex-col items-center\">\n <div class=\"bg-background relative z-[1] flex size-6 items-center justify-center rounded-full\">\n <span [class]=\"dotClasses()\">\n <span [class]=\"innerDotClasses()\"></span>\n </span>\n </div>\n @if (!isLast) {\n <span class=\"bg-border absolute top-6 bottom-0 left-1/2 w-px -translate-x-1/2\"></span>\n <span class=\"w-px flex-1\"></span>\n }\n </div>\n\n <!-- Right: content -->\n <div class=\"flex flex-1 flex-col gap-4 pb-11 pl-3 md:pl-6 lg:pl-9\">\n <!-- Mobile badge + subtitle -->\n <div class=\"flex flex-col gap-2 md:hidden\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\" class=\"w-fit text-xs\">{{ item.time }}</span>\n }\n @if (item.subtitle) {\n <div class=\"font-medium\">{{ item.subtitle }}</div>\n }\n </div>\n\n <!-- Content -->\n <div class=\"space-y-4\">\n <div class=\"space-y-3\">\n <h3 [class]=\"titleClasses()\">{{ item.title }}</h3>\n @if (item.description) {\n <p [class]=\"descriptionClasses()\">{{ item.description }}</p>\n }\n </div>\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </div>\n </div>\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shival99-z-ui-components-z-timeline.mjs","sources":["../../../../libs/core-ui/components/z-timeline/z-timeline.variants.ts","../../../../libs/core-ui/components/z-timeline/z-timeline.component.ts","../../../../libs/core-ui/components/z-timeline/z-timeline.component.html","../../../../libs/core-ui/components/z-timeline/shival99-z-ui-components-z-timeline.ts"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\n\n// Host container\nexport const zTimelineVariants = cva(['z-timeline relative block min-w-0'], {\n variants: {\n zSize: {\n sm: 'text-sm',\n default: 'text-base',\n lg: 'text-lg',\n },\n },\n defaultVariants: {\n zSize: 'default',\n },\n});\n\n// Outer dot ring\nexport const zTimelineDotVariants = cva(\n ['flex shrink-0 items-center justify-center rounded-full bg-primary/10 transition-colors duration-300'],\n {\n variants: {\n zSize: {\n sm: 'size-4.5',\n default: 'size-6',\n lg: 'size-7',\n },\n },\n defaultVariants: {\n zSize: 'default',\n },\n }\n);\n\n// Inner dot\nexport const zTimelineInnerDotVariants = cva(['rounded-full bg-primary transition-colors duration-300'], {\n variants: {\n zSize: {\n sm: 'size-2',\n default: 'size-3',\n lg: 'size-3.5',\n },\n },\n defaultVariants: {\n zSize: 'default',\n },\n});\n\n// Time badge\nexport const zTimelineTimeBadgeVariants = cva(\n [\n 'inline-flex w-fit max-w-full shrink-0 items-center justify-center rounded-md bg-primary px-2 py-0.5 text-sm font-semibold leading-tight text-primary-foreground transition-colors duration-300',\n ],\n {\n variants: {\n zSize: {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-sm',\n },\n },\n defaultVariants: {\n zSize: 'default',\n },\n }\n);\n\n// Title\nexport const zTimelineTitleVariants = cva(['font-medium leading-snug text-foreground'], {\n variants: {\n zSize: {\n sm: 'text-sm',\n default: 'text-base md:text-lg',\n lg: 'text-lg md:text-xl',\n },\n },\n defaultVariants: {\n zSize: 'default',\n },\n});\n\n// Description\nexport const zTimelineDescriptionVariants = cva(['text-muted-foreground leading-relaxed'], {\n variants: {\n zSize: {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-base',\n },\n },\n defaultVariants: {\n zSize: 'default',\n },\n});\n\nexport type ZTimelineVariants = VariantProps<typeof zTimelineVariants>;\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n effect,\n ElementRef,\n inject,\n input,\n signal,\n viewChildren,\n ViewEncapsulation,\n} from '@angular/core';\nimport { ZIconComponent } from '@shival99/z-ui/components/z-icon';\nimport { zMergeClasses } from '@shival99/z-ui/utils';\nimport type { ClassValue } from 'clsx';\nimport type { ZTimelineItem, ZTimelineLayout, ZTimelineSize } from './z-timeline.types';\nimport {\n zTimelineDescriptionVariants,\n zTimelineDotVariants,\n zTimelineInnerDotVariants,\n zTimelineTimeBadgeVariants,\n zTimelineTitleVariants,\n zTimelineVariants,\n} from './z-timeline.variants';\n\n@Component({\n selector: 'z-timeline',\n imports: [NgTemplateOutlet, ZIconComponent],\n standalone: true,\n templateUrl: './z-timeline.component.html',\n styles: `\n .z-timeline {\n container-type: inline-size;\n }\n\n .z-timeline-default-mobile-meta {\n display: none;\n }\n\n .z-timeline-progress-dot {\n background: var(--primary);\n transition:\n background-color 180ms ease,\n border-color 180ms ease,\n box-shadow 180ms ease;\n }\n\n .z-timeline-progress-dot-ring {\n background: color-mix(in oklab, var(--primary) 14%, transparent);\n transition: background-color 180ms ease;\n }\n\n .z-timeline-progress-line {\n background: var(--primary);\n transition: height 120ms linear;\n }\n\n .z-timeline-progress-inactive .z-timeline-progress-dot-ring {\n background: var(--border);\n }\n\n .z-timeline-progress-inactive .z-timeline-progress-dot {\n background: var(--muted-foreground);\n border-color: var(--border);\n }\n\n @container (max-width: 34rem) {\n .z-timeline-default-item {\n grid-template-columns: 1.5rem minmax(0, 1fr);\n }\n\n .z-timeline-default-meta {\n display: none;\n }\n\n .z-timeline-default-mobile-meta {\n display: flex;\n }\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': 'hostClasses()',\n },\n})\nexport class ZTimelineComponent {\n public readonly class = input<ClassValue>('');\n public readonly zItems = input<ZTimelineItem[]>([]);\n public readonly zSize = input<ZTimelineSize>('default');\n public readonly zLayout = input<ZTimelineLayout>('default');\n public readonly zScrollProgress = input(false, { transform: booleanAttribute });\n\n private readonly _destroyRef = inject(DestroyRef);\n private readonly _timelineItems = viewChildren<ElementRef<HTMLElement>>('timelineItem');\n private readonly _progressRatio = signal(0);\n\n protected readonly hostClasses = computed(() =>\n zMergeClasses(zTimelineVariants({ zSize: this.zSize() }), this.class())\n );\n\n protected readonly dotClasses = computed(() => zTimelineDotVariants({ zSize: this.zSize() }));\n\n protected readonly innerDotClasses = computed(() => zTimelineInnerDotVariants({ zSize: this.zSize() }));\n\n protected readonly badgeClasses = computed(() => zTimelineTimeBadgeVariants({ zSize: this.zSize() }));\n\n protected readonly titleClasses = computed(() => zTimelineTitleVariants({ zSize: this.zSize() }));\n\n protected readonly descriptionClasses = computed(() => zTimelineDescriptionVariants({ zSize: this.zSize() }));\n\n protected readonly isCareer = computed(() => this.zLayout() === 'career');\n\n protected readonly isAlternate = computed(() => this.zLayout() === 'alternate');\n\n protected readonly progressStates = computed(() => {\n const items = this.zItems();\n\n if (!this.zScrollProgress()) {\n return items.map(() => true);\n }\n\n const lastIndex = items.length - 1;\n const progressRatio = this._progressRatio();\n if (lastIndex <= 0) {\n return items.map(() => progressRatio > 0);\n }\n\n return items.map((_item, index) => {\n if (index === 0) {\n return progressRatio > 0;\n }\n\n return progressRatio >= index / lastIndex;\n });\n });\n\n protected readonly progressLineHeight = computed(() => {\n if (!this.zScrollProgress()) {\n return '100%';\n }\n\n return `${this._progressRatio() * 100}%`;\n });\n\n protected readonly progressSegments = computed(() => {\n const items = this.zItems();\n const lastIndex = items.length - 1;\n\n if (!this.zScrollProgress()) {\n return items.map(() => '100%');\n }\n\n if (lastIndex <= 0) {\n return items.map(() => `${this._progressRatio() * 100}%`);\n }\n\n const progressRatio = this._progressRatio();\n return items.map((_item, index) => {\n const segmentStart = index / lastIndex;\n const segmentEnd = (index + 1) / lastIndex;\n const segmentProgress = (progressRatio - segmentStart) / (segmentEnd - segmentStart);\n const boundedProgress = Math.min(Math.max(segmentProgress, 0), 1);\n\n return `${boundedProgress * 100}%`;\n });\n });\n\n constructor() {\n effect(onCleanup => {\n if (!this.zScrollProgress()) {\n this._progressRatio.set(0);\n return;\n }\n\n if (typeof window === 'undefined') {\n this._progressRatio.set(1);\n return;\n }\n\n const elements = this._timelineItems().map(item => item.nativeElement);\n if (!elements.length) {\n this._progressRatio.set(0);\n return;\n }\n\n let animationFrame: number | null = null;\n\n const updateProgress = (): void => {\n this._progressRatio.set(this._calculateProgressRatio(elements));\n };\n\n const scheduleUpdate = (): void => {\n if (animationFrame !== null) {\n return;\n }\n\n animationFrame = window.requestAnimationFrame(() => {\n animationFrame = null;\n updateProgress();\n });\n };\n\n scheduleUpdate();\n window.addEventListener('scroll', scheduleUpdate, { passive: true });\n window.addEventListener('resize', scheduleUpdate);\n\n onCleanup(() => {\n window.removeEventListener('scroll', scheduleUpdate);\n window.removeEventListener('resize', scheduleUpdate);\n\n if (animationFrame === null) {\n return;\n }\n\n window.cancelAnimationFrame(animationFrame);\n });\n });\n\n this._destroyRef.onDestroy(() => this._progressRatio.set(0));\n }\n\n private _calculateProgressRatio(elements: HTMLElement[]): number {\n if (!elements.length) {\n return 0;\n }\n\n const triggerY = window.innerHeight * 0.55;\n const itemTops = elements.map(element => element.getBoundingClientRect().top);\n const firstTop = itemTops[0];\n const lastTop = itemTops[itemTops.length - 1];\n\n if (triggerY <= firstTop) {\n return 0;\n }\n\n if (triggerY >= lastTop) {\n return 1;\n }\n\n const activeSegmentIndex = itemTops.findIndex((top, index) => {\n const nextTop = itemTops[index + 1];\n if (nextTop === undefined) {\n return false;\n }\n\n return triggerY >= top && triggerY < nextTop;\n });\n\n if (activeSegmentIndex < 0) {\n return 0;\n }\n\n const segmentStart = itemTops[activeSegmentIndex];\n const segmentEnd = itemTops[activeSegmentIndex + 1];\n const segmentDistance = segmentEnd - segmentStart;\n if (segmentDistance <= 0) {\n return 0;\n }\n\n const localProgress = (triggerY - segmentStart) / segmentDistance;\n return (activeSegmentIndex + localProgress) / (itemTops.length - 1);\n }\n}\n","@if (isCareer()) {\n <!-- ══════════════════════════════════════════════════════════ -->\n <!-- CAREER / EXPERIENCE LAYOUT -->\n <!-- ══════════════════════════════════════════════════════════ -->\n @let progress = progressStates();\n <div class=\"mx-auto w-full max-w-3xl px-2 sm:px-4\">\n <div class=\"relative ml-3\">\n <div class=\"bg-border absolute top-3 bottom-3 left-0 w-0.5 overflow-hidden\">\n <div\n class=\"z-timeline-progress-line absolute inset-x-0 top-0 w-0.5\"\n [style.height]=\"zScrollProgress() ? progressLineHeight() : '0%'\"></div>\n </div>\n\n @for (item of zItems(); track item.id ?? $index; let isLast = $last) {\n @let isActive = progress[$index];\n <article\n #timelineItem\n class=\"relative pb-10 pl-8\"\n [class.pb-0]=\"isLast\"\n [class.z-timeline-progress-inactive]=\"zScrollProgress() && !isActive\">\n <span\n class=\"bg-background border-primary absolute top-2 left-0 z-[1] size-3 -translate-x-1/2 rounded-full border-2\"\n [class.z-timeline-progress-dot]=\"zScrollProgress()\"></span>\n\n <div class=\"space-y-3\">\n <div class=\"flex items-center gap-2.5\">\n <div class=\"bg-accent flex size-9 shrink-0 items-center justify-center rounded-full\">\n <z-icon [zType]=\"item.icon ?? 'lucideBuilding2'\" zSize=\"18\" class=\"text-muted-foreground\" />\n </div>\n <span class=\"text-base font-medium\">{{ item.company ?? item.subtitle ?? 'Experience' }}</span>\n </div>\n\n <div class=\"space-y-2\">\n <h3 class=\"text-foreground text-xl leading-tight font-semibold tracking-[-0.01em]\">{{ item.title }}</h3>\n @if (item.period || item.time) {\n <div class=\"text-muted-foreground flex items-center gap-2 text-sm\">\n <z-icon zType=\"lucideCalendar\" zSize=\"15\" class=\"shrink-0\" />\n <span>{{ item.period ?? item.time }}</span>\n </div>\n }\n </div>\n\n @if (item.description) {\n <p class=\"text-muted-foreground text-sm leading-relaxed sm:text-base\">{{ item.description }}</p>\n }\n\n @if (item.technologies?.length) {\n <div class=\"flex flex-wrap gap-2\">\n @for (tech of item.technologies; track tech) {\n <span\n class=\"bg-secondary text-secondary-foreground inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-medium\">\n {{ tech }}\n </span>\n }\n </div>\n }\n\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </article>\n }\n </div>\n </div>\n} @else if (isAlternate()) {\n <!-- ══════════════════════════════════════════════════════════ -->\n <!-- ALTERNATE / ZIGZAG LAYOUT -->\n <!-- ══════════════════════════════════════════════════════════ -->\n @let progress = progressStates();\n <div class=\"relative mx-auto max-w-7xl space-y-4\">\n @for (item of zItems(); track item.id ?? $index; let isEven = $even) {\n @let isActive = progress[$index];\n <div\n #timelineItem\n class=\"flex items-start md:flex-row\"\n [class.md:flex-row-reverse]=\"!isEven\"\n [class.z-timeline-progress-inactive]=\"zScrollProgress() && !isActive\">\n <!-- Opposite-side badge (desktop only) -->\n <div\n class=\"hidden w-full md:flex md:flex-1 md:items-start\"\n [class.md:justify-end]=\"isEven\"\n [class.md:justify-start]=\"!isEven\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\">{{ item.time }}</span>\n }\n </div>\n\n <!-- Center marker column -->\n <div class=\"relative flex flex-col items-center pr-4 md:px-4\">\n <div class=\"z-40 flex items-center justify-center\">\n <span [class]=\"dotClasses()\" [class.z-timeline-progress-dot-ring]=\"true\">\n <span [class]=\"innerDotClasses()\" [class.z-timeline-progress-dot]=\"true\"></span>\n </span>\n </div>\n </div>\n\n <!-- Content side -->\n <div class=\"w-full md:flex md:flex-1\" [class.md:justify-start]=\"isEven\" [class.md:justify-end]=\"!isEven\">\n <!-- Mobile badge -->\n @if (item.time) {\n <span [class]=\"badgeClasses()\" class=\"mb-4 block text-left md:hidden\">{{ item.time }}</span>\n }\n\n <div>\n <!-- Card -->\n <div\n class=\"bg-card text-card-foreground mb-8 flex flex-col gap-6 overflow-hidden rounded-xl border py-6 shadow-sm md:max-w-136\">\n <div class=\"space-y-4 px-6\">\n <div [class]=\"titleClasses()\">{{ item.title }}</div>\n @if (item.description) {\n <p [class]=\"descriptionClasses()\">{{ item.description }}</p>\n }\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- Vertical line (absolute, behind everything) -->\n <div class=\"bg-border absolute top-3 bottom-3 left-3 w-0.5 overflow-hidden md:left-1/2 md:-translate-x-1/2\">\n <div\n class=\"z-timeline-progress-line absolute inset-x-0 top-0 w-0.5 rounded-full\"\n [style.height]=\"progressLineHeight()\"></div>\n </div>\n </div>\n} @else {\n <!-- ══════════════════════════════════════════════════════════ -->\n <!-- DEFAULT / CHANGELOG LAYOUT -->\n <!-- ══════════════════════════════════════════════════════════ -->\n @let progress = progressStates();\n @let segments = progressSegments();\n @for (item of zItems(); track item.id ?? $index; let isLast = $last) {\n @let isActive = progress[$index];\n <article\n #timelineItem\n class=\"z-timeline-default-item relative grid grid-cols-[7rem_1.5rem_minmax(0,1fr)] gap-x-3\"\n [class.z-timeline-progress-inactive]=\"zScrollProgress() && !isActive\">\n <!-- Left: badge + subtitle (desktop only) -->\n <div class=\"z-timeline-default-meta flex min-w-0 flex-col items-end gap-2 self-start pb-4\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\">{{ item.time }}</span>\n }\n @if (item.subtitle) {\n <div class=\"text-muted-foreground max-w-full text-right text-sm leading-snug font-medium\">\n {{ item.subtitle }}\n </div>\n }\n </div>\n\n <!-- Center: dot + line -->\n <div class=\"relative flex flex-col items-center\">\n <div class=\"bg-background relative z-[1] flex size-6 items-center justify-center rounded-full\">\n <span [class]=\"dotClasses()\" [class.z-timeline-progress-dot-ring]=\"true\">\n <span [class]=\"innerDotClasses()\" [class.z-timeline-progress-dot]=\"true\"></span>\n </span>\n </div>\n @if (!isLast) {\n <span class=\"bg-border absolute top-6 bottom-0 left-1/2 w-px -translate-x-1/2 overflow-hidden rounded-full\">\n @if (zScrollProgress()) {\n <span\n class=\"z-timeline-progress-line absolute inset-x-0 top-0 w-px rounded-full\"\n [style.height]=\"segments[$index]\"></span>\n }\n </span>\n <span class=\"w-px flex-1\"></span>\n }\n </div>\n\n <!-- Right: content -->\n <div class=\"z-timeline-default-content flex min-w-0 flex-col gap-4 pb-10 pl-1\">\n <!-- Mobile badge + subtitle -->\n <div class=\"z-timeline-default-mobile-meta flex-col gap-2\">\n @if (item.time) {\n <span [class]=\"badgeClasses()\" class=\"w-fit\">{{ item.time }}</span>\n }\n @if (item.subtitle) {\n <div class=\"text-muted-foreground text-sm font-medium\">{{ item.subtitle }}</div>\n }\n </div>\n\n <!-- Content -->\n <div class=\"min-w-0 space-y-4\">\n <div class=\"space-y-3\">\n <h3 [class]=\"titleClasses()\">{{ item.title }}</h3>\n @if (item.description) {\n <p [class]=\"descriptionClasses()\">{{ item.description }}</p>\n }\n </div>\n @if (item.contentTemplate) {\n <ng-container [ngTemplateOutlet]=\"item.contentTemplate\" />\n }\n </div>\n </div>\n </article>\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shival99/z-ui",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.20",
|
|
4
4
|
"description": "Z-UI: Modern Angular UI Component Library - A comprehensive, high-performance design system built with Angular 20+, featuring 40+ customizable components with dark mode, accessibility, and enterprise-ready features.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -260,6 +260,7 @@ declare class ZAutocompleteComponent<T = unknown> implements OnInit, ControlValu
|
|
|
260
260
|
private _getAsyncOptionsScrollTop;
|
|
261
261
|
private _restoreAsyncOptionsScrollTop;
|
|
262
262
|
private _resetOptionsScrollTop;
|
|
263
|
+
private _getOptionsScrollElement;
|
|
263
264
|
private _resetAsyncOptions;
|
|
264
265
|
private _clearLocalLoadingTimer;
|
|
265
266
|
private _setupLoadMoreObserver;
|
|
@@ -279,6 +280,7 @@ declare const zAutocompleteInputVariants: (props?: ({
|
|
|
279
280
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
280
281
|
type ZAutocompleteInputVariants = VariantProps<typeof zAutocompleteInputVariants>;
|
|
281
282
|
declare const zAutocompleteOptionVariants: (props?: ({
|
|
283
|
+
customTemplate?: boolean | null | undefined;
|
|
282
284
|
active?: boolean | null | undefined;
|
|
283
285
|
disabled?: boolean | null | undefined;
|
|
284
286
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
@@ -30,6 +30,7 @@ declare class ZPopoverComponent implements OnInit, OnDestroy {
|
|
|
30
30
|
private readonly _platformId;
|
|
31
31
|
private readonly _document;
|
|
32
32
|
private readonly _overlayContainerService;
|
|
33
|
+
private readonly _zIndexService;
|
|
33
34
|
private readonly _trigger;
|
|
34
35
|
readonly zShow: _angular_core.OutputEmitterRef<void>;
|
|
35
36
|
readonly zHide: _angular_core.OutputEmitterRef<void>;
|
|
@@ -139,6 +140,7 @@ declare class ZPopoverDirective implements OnInit, OnDestroy {
|
|
|
139
140
|
private readonly _platformId;
|
|
140
141
|
private readonly _document;
|
|
141
142
|
private readonly _overlayContainerService;
|
|
143
|
+
private readonly _zIndexService;
|
|
142
144
|
private _overlayRef;
|
|
143
145
|
private _componentRef;
|
|
144
146
|
private _delaySubject;
|
|
@@ -111,6 +111,7 @@ declare class ZSelectComponent<T = unknown> implements OnInit, ControlValueAcces
|
|
|
111
111
|
protected readonly optionsContainerRef: _angular_core.Signal<ElementRef<HTMLDivElement> | undefined>;
|
|
112
112
|
protected readonly virtualScrollRef: _angular_core.Signal<ElementRef<HTMLDivElement> | undefined>;
|
|
113
113
|
protected readonly loadMoreSentinelRef: _angular_core.Signal<ElementRef<HTMLDivElement> | undefined>;
|
|
114
|
+
protected readonly virtualOptionElements: _angular_core.Signal<readonly ElementRef<HTMLDivElement>[]>;
|
|
114
115
|
protected readonly customSelectedDirective: _angular_core.Signal<ZSelectSelectedDirective<any> | undefined>;
|
|
115
116
|
protected readonly customOptionDirective: _angular_core.Signal<ZSelectOptionDirective<any> | undefined>;
|
|
116
117
|
readonly zOnSearch: _angular_core.OutputEmitterRef<string>;
|
|
@@ -132,6 +133,7 @@ declare class ZSelectComponent<T = unknown> implements OnInit, ControlValueAcces
|
|
|
132
133
|
readonly zLoadingOutline: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
133
134
|
readonly zPrefix: _angular_core.InputSignal<"" | ZIcon>;
|
|
134
135
|
readonly zAllowClear: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
136
|
+
readonly zShowCheck: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
135
137
|
readonly zWrap: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
136
138
|
readonly zShowSearch: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
137
139
|
readonly zPlaceholderSearch: _angular_core.InputSignal<string>;
|
|
@@ -143,6 +145,7 @@ declare class ZSelectComponent<T = unknown> implements OnInit, ControlValueAcces
|
|
|
143
145
|
readonly zDropdownMaxHeight: _angular_core.InputSignal<number>;
|
|
144
146
|
readonly zOptionHeight: _angular_core.InputSignal<number>;
|
|
145
147
|
readonly zVirtualScroll: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
148
|
+
readonly zDynamicSize: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
146
149
|
readonly zShowAction: _angular_core.InputSignalWithTransform<boolean, string | boolean>;
|
|
147
150
|
readonly zOptions: _angular_core.InputSignal<ZSelectOption<T>[]>;
|
|
148
151
|
readonly zConfig: _angular_core.InputSignal<Partial<ZSelectConfig<T>>>;
|
|
@@ -199,6 +202,7 @@ declare class ZSelectComponent<T = unknown> implements OnInit, ControlValueAcces
|
|
|
199
202
|
protected readonly canLoadMore: _angular_core.Signal<boolean>;
|
|
200
203
|
protected readonly effectiveDebounceTime: _angular_core.Signal<number>;
|
|
201
204
|
protected readonly virtualizer: _shival99_angular_virtual.AngularVirtualizer<HTMLDivElement, Element>;
|
|
205
|
+
private readonly _measureVirtualItems;
|
|
202
206
|
protected readonly isDisabled: _angular_core.Signal<boolean>;
|
|
203
207
|
protected readonly isReadonly: _angular_core.Signal<boolean>;
|
|
204
208
|
protected readonly isInteractionDisabled: _angular_core.Signal<boolean>;
|
|
@@ -290,6 +294,7 @@ declare class ZSelectComponent<T = unknown> implements OnInit, ControlValueAcces
|
|
|
290
294
|
private _getAsyncOptionsScrollTop;
|
|
291
295
|
private _restoreAsyncOptionsScrollTop;
|
|
292
296
|
private _resetOptionsScrollTop;
|
|
297
|
+
private _getOptionsScrollElement;
|
|
293
298
|
private _resetAsyncOptions;
|
|
294
299
|
private _setupLoadMoreObserver;
|
|
295
300
|
private _cleanupLoadMoreObserver;
|
|
@@ -301,7 +306,7 @@ declare class ZSelectComponent<T = unknown> implements OnInit, ControlValueAcces
|
|
|
301
306
|
private _cancelAsyncValidation;
|
|
302
307
|
private _triggerAsyncValidation;
|
|
303
308
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ZSelectComponent<any>, never>;
|
|
304
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ZSelectComponent<any>, "z-select", ["zSelect"], { "class": { "alias": "class"; "required": false; "isSignal": true; }; "zMode": { "alias": "zMode"; "required": false; "isSignal": true; }; "zSize": { "alias": "zSize"; "required": false; "isSignal": true; }; "zLabel": { "alias": "zLabel"; "required": false; "isSignal": true; }; "zLabelClass": { "alias": "zLabelClass"; "required": false; "isSignal": true; }; "zPlaceholder": { "alias": "zPlaceholder"; "required": false; "isSignal": true; }; "zRequired": { "alias": "zRequired"; "required": false; "isSignal": true; }; "zDisabled": { "alias": "zDisabled"; "required": false; "isSignal": true; }; "zReadonly": { "alias": "zReadonly"; "required": false; "isSignal": true; }; "zLoading": { "alias": "zLoading"; "required": false; "isSignal": true; }; "zLoadingOutline": { "alias": "zLoadingOutline"; "required": false; "isSignal": true; }; "zPrefix": { "alias": "zPrefix"; "required": false; "isSignal": true; }; "zAllowClear": { "alias": "zAllowClear"; "required": false; "isSignal": true; }; "zWrap": { "alias": "zWrap"; "required": false; "isSignal": true; }; "zShowSearch": { "alias": "zShowSearch"; "required": false; "isSignal": true; }; "zPlaceholderSearch": { "alias": "zPlaceholderSearch"; "required": false; "isSignal": true; }; "zDebounce": { "alias": "zDebounce"; "required": false; "isSignal": true; }; "zNotFoundText": { "alias": "zNotFoundText"; "required": false; "isSignal": true; }; "zEmptyText": { "alias": "zEmptyText"; "required": false; "isSignal": true; }; "zEmptyIcon": { "alias": "zEmptyIcon"; "required": false; "isSignal": true; }; "zMaxTagCount": { "alias": "zMaxTagCount"; "required": false; "isSignal": true; }; "zDropdownMaxHeight": { "alias": "zDropdownMaxHeight"; "required": false; "isSignal": true; }; "zOptionHeight": { "alias": "zOptionHeight"; "required": false; "isSignal": true; }; "zVirtualScroll": { "alias": "zVirtualScroll"; "required": false; "isSignal": true; }; "zShowAction": { "alias": "zShowAction"; "required": false; "isSignal": true; }; "zOptions": { "alias": "zOptions"; "required": false; "isSignal": true; }; "zConfig": { "alias": "zConfig"; "required": false; "isSignal": true; }; "zTranslateLabels": { "alias": "zTranslateLabels"; "required": false; "isSignal": true; }; "zKey": { "alias": "zKey"; "required": false; "isSignal": true; }; "zSearchServer": { "alias": "zSearchServer"; "required": false; "isSignal": true; }; "zLoadingMore": { "alias": "zLoadingMore"; "required": false; "isSignal": true; }; "zEnableLoadMore": { "alias": "zEnableLoadMore"; "required": false; "isSignal": true; }; "zScrollDistance": { "alias": "zScrollDistance"; "required": false; "isSignal": true; }; "zMaxVisible": { "alias": "zMaxVisible"; "required": false; "isSignal": true; }; "zScrollClose": { "alias": "zScrollClose"; "required": false; "isSignal": true; }; "zSticky": { "alias": "zSticky"; "required": false; "isSignal": true; }; "zPosition": { "alias": "zPosition"; "required": false; "isSignal": true; }; "zSelectedTemplate": { "alias": "zSelectedTemplate"; "required": false; "isSignal": true; }; "zOptionTemplate": { "alias": "zOptionTemplate"; "required": false; "isSignal": true; }; "zActionTemplate": { "alias": "zActionTemplate"; "required": false; "isSignal": true; }; "zAsyncValidators": { "alias": "zAsyncValidators"; "required": false; "isSignal": true; }; "zAsyncDebounce": { "alias": "zAsyncDebounce"; "required": false; "isSignal": true; }; "zAsyncValidateOn": { "alias": "zAsyncValidateOn"; "required": false; "isSignal": true; }; "zValidators": { "alias": "zValidators"; "required": false; "isSignal": true; }; }, { "zOnSearch": "zOnSearch"; "zOnLoadMore": "zOnLoadMore"; "zOnBlur": "zOnBlur"; "zOnFocus": "zOnFocus"; "zControl": "zControl"; "zEvent": "zEvent"; }, ["customSelectedDirective", "customOptionDirective"], never, true, never>;
|
|
309
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ZSelectComponent<any>, "z-select", ["zSelect"], { "class": { "alias": "class"; "required": false; "isSignal": true; }; "zMode": { "alias": "zMode"; "required": false; "isSignal": true; }; "zSize": { "alias": "zSize"; "required": false; "isSignal": true; }; "zLabel": { "alias": "zLabel"; "required": false; "isSignal": true; }; "zLabelClass": { "alias": "zLabelClass"; "required": false; "isSignal": true; }; "zPlaceholder": { "alias": "zPlaceholder"; "required": false; "isSignal": true; }; "zRequired": { "alias": "zRequired"; "required": false; "isSignal": true; }; "zDisabled": { "alias": "zDisabled"; "required": false; "isSignal": true; }; "zReadonly": { "alias": "zReadonly"; "required": false; "isSignal": true; }; "zLoading": { "alias": "zLoading"; "required": false; "isSignal": true; }; "zLoadingOutline": { "alias": "zLoadingOutline"; "required": false; "isSignal": true; }; "zPrefix": { "alias": "zPrefix"; "required": false; "isSignal": true; }; "zAllowClear": { "alias": "zAllowClear"; "required": false; "isSignal": true; }; "zShowCheck": { "alias": "zShowCheck"; "required": false; "isSignal": true; }; "zWrap": { "alias": "zWrap"; "required": false; "isSignal": true; }; "zShowSearch": { "alias": "zShowSearch"; "required": false; "isSignal": true; }; "zPlaceholderSearch": { "alias": "zPlaceholderSearch"; "required": false; "isSignal": true; }; "zDebounce": { "alias": "zDebounce"; "required": false; "isSignal": true; }; "zNotFoundText": { "alias": "zNotFoundText"; "required": false; "isSignal": true; }; "zEmptyText": { "alias": "zEmptyText"; "required": false; "isSignal": true; }; "zEmptyIcon": { "alias": "zEmptyIcon"; "required": false; "isSignal": true; }; "zMaxTagCount": { "alias": "zMaxTagCount"; "required": false; "isSignal": true; }; "zDropdownMaxHeight": { "alias": "zDropdownMaxHeight"; "required": false; "isSignal": true; }; "zOptionHeight": { "alias": "zOptionHeight"; "required": false; "isSignal": true; }; "zVirtualScroll": { "alias": "zVirtualScroll"; "required": false; "isSignal": true; }; "zDynamicSize": { "alias": "zDynamicSize"; "required": false; "isSignal": true; }; "zShowAction": { "alias": "zShowAction"; "required": false; "isSignal": true; }; "zOptions": { "alias": "zOptions"; "required": false; "isSignal": true; }; "zConfig": { "alias": "zConfig"; "required": false; "isSignal": true; }; "zTranslateLabels": { "alias": "zTranslateLabels"; "required": false; "isSignal": true; }; "zKey": { "alias": "zKey"; "required": false; "isSignal": true; }; "zSearchServer": { "alias": "zSearchServer"; "required": false; "isSignal": true; }; "zLoadingMore": { "alias": "zLoadingMore"; "required": false; "isSignal": true; }; "zEnableLoadMore": { "alias": "zEnableLoadMore"; "required": false; "isSignal": true; }; "zScrollDistance": { "alias": "zScrollDistance"; "required": false; "isSignal": true; }; "zMaxVisible": { "alias": "zMaxVisible"; "required": false; "isSignal": true; }; "zScrollClose": { "alias": "zScrollClose"; "required": false; "isSignal": true; }; "zSticky": { "alias": "zSticky"; "required": false; "isSignal": true; }; "zPosition": { "alias": "zPosition"; "required": false; "isSignal": true; }; "zSelectedTemplate": { "alias": "zSelectedTemplate"; "required": false; "isSignal": true; }; "zOptionTemplate": { "alias": "zOptionTemplate"; "required": false; "isSignal": true; }; "zActionTemplate": { "alias": "zActionTemplate"; "required": false; "isSignal": true; }; "zAsyncValidators": { "alias": "zAsyncValidators"; "required": false; "isSignal": true; }; "zAsyncDebounce": { "alias": "zAsyncDebounce"; "required": false; "isSignal": true; }; "zAsyncValidateOn": { "alias": "zAsyncValidateOn"; "required": false; "isSignal": true; }; "zValidators": { "alias": "zValidators"; "required": false; "isSignal": true; }; }, { "zOnSearch": "zOnSearch"; "zOnLoadMore": "zOnLoadMore"; "zOnBlur": "zOnBlur"; "zOnFocus": "zOnFocus"; "zControl": "zControl"; "zEvent": "zEvent"; }, ["customSelectedDirective", "customOptionDirective"], never, true, never>;
|
|
305
310
|
}
|
|
306
311
|
|
|
307
312
|
declare class ZIsSelectedPipe implements PipeTransform {
|
|
@@ -311,7 +316,7 @@ declare class ZIsSelectedPipe implements PipeTransform {
|
|
|
311
316
|
}
|
|
312
317
|
|
|
313
318
|
declare class ZOptionClassesPipe implements PipeTransform {
|
|
314
|
-
transform(isSelected: boolean, isDisabled?: boolean): string;
|
|
319
|
+
transform(isSelected: boolean, isDisabled?: boolean, customTemplate?: boolean): string;
|
|
315
320
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ZOptionClassesPipe, never>;
|
|
316
321
|
static ɵpipe: _angular_core.ɵɵPipeDeclaration<ZOptionClassesPipe, "zOptionClasses", true>;
|
|
317
322
|
}
|
|
@@ -330,6 +335,7 @@ declare const zSelectTagVariants: (props?: ({
|
|
|
330
335
|
zSize?: "sm" | "default" | "lg" | null | undefined;
|
|
331
336
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
332
337
|
declare const zSelectOptionVariants: (props?: ({
|
|
338
|
+
customTemplate?: boolean | null | undefined;
|
|
333
339
|
selected?: boolean | null | undefined;
|
|
334
340
|
disabled?: boolean | null | undefined;
|
|
335
341
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
@@ -26,6 +26,10 @@ declare class ZTimelineComponent {
|
|
|
26
26
|
readonly zItems: _angular_core.InputSignal<ZTimelineItem[]>;
|
|
27
27
|
readonly zSize: _angular_core.InputSignal<ZTimelineSize>;
|
|
28
28
|
readonly zLayout: _angular_core.InputSignal<ZTimelineLayout>;
|
|
29
|
+
readonly zScrollProgress: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
30
|
+
private readonly _destroyRef;
|
|
31
|
+
private readonly _timelineItems;
|
|
32
|
+
private readonly _progressRatio;
|
|
29
33
|
protected readonly hostClasses: _angular_core.Signal<string>;
|
|
30
34
|
protected readonly dotClasses: _angular_core.Signal<string>;
|
|
31
35
|
protected readonly innerDotClasses: _angular_core.Signal<string>;
|
|
@@ -34,8 +38,13 @@ declare class ZTimelineComponent {
|
|
|
34
38
|
protected readonly descriptionClasses: _angular_core.Signal<string>;
|
|
35
39
|
protected readonly isCareer: _angular_core.Signal<boolean>;
|
|
36
40
|
protected readonly isAlternate: _angular_core.Signal<boolean>;
|
|
41
|
+
protected readonly progressStates: _angular_core.Signal<boolean[]>;
|
|
42
|
+
protected readonly progressLineHeight: _angular_core.Signal<string>;
|
|
43
|
+
protected readonly progressSegments: _angular_core.Signal<string[]>;
|
|
44
|
+
constructor();
|
|
45
|
+
private _calculateProgressRatio;
|
|
37
46
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ZTimelineComponent, never>;
|
|
38
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ZTimelineComponent, "z-timeline", never, { "class": { "alias": "class"; "required": false; "isSignal": true; }; "zItems": { "alias": "zItems"; "required": false; "isSignal": true; }; "zSize": { "alias": "zSize"; "required": false; "isSignal": true; }; "zLayout": { "alias": "zLayout"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
47
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ZTimelineComponent, "z-timeline", never, { "class": { "alias": "class"; "required": false; "isSignal": true; }; "zItems": { "alias": "zItems"; "required": false; "isSignal": true; }; "zSize": { "alias": "zSize"; "required": false; "isSignal": true; }; "zLayout": { "alias": "zLayout"; "required": false; "isSignal": true; }; "zScrollProgress": { "alias": "zScrollProgress"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
39
48
|
}
|
|
40
49
|
|
|
41
50
|
declare const zTimelineVariants: (props?: ({
|