@acorex/components 21.0.3-next.39 → 21.0.3-next.40
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/{conversation2 → conversation}/README.md +23 -23
- package/fesm2022/acorex-components-button.mjs +4 -4
- package/fesm2022/acorex-components-button.mjs.map +1 -1
- package/fesm2022/acorex-components-conversation-acorex-components-conversation-YhVa42TC.mjs +13711 -0
- package/fesm2022/acorex-components-conversation-acorex-components-conversation-YhVa42TC.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-audio-attachment.component-CLvS3W8F.mjs +119 -0
- package/fesm2022/acorex-components-conversation-audio-attachment.component-CLvS3W8F.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-audio-composer.payload-BHQJNyXz.mjs +59 -0
- package/fesm2022/acorex-components-conversation-audio-composer.payload-BHQJNyXz.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-audio-picker.component-BD_fN2Ip.mjs +432 -0
- package/fesm2022/acorex-components-conversation-audio-picker.component-BD_fN2Ip.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-audio-renderer.component-CcxVVprx.mjs +177 -0
- package/fesm2022/acorex-components-conversation-audio-renderer.component-CcxVVprx.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-audio.payload-Bag4aTut.mjs +54 -0
- package/fesm2022/acorex-components-conversation-audio.payload-Bag4aTut.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-C28hl7iD.mjs +101 -0
- package/fesm2022/acorex-components-conversation-composer-action-choice-dialog.component-C28hl7iD.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-conversation-audio.file-type-CfGSVnMA.mjs +100 -0
- package/fesm2022/acorex-components-conversation-conversation-audio.file-type-CfGSVnMA.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-conversation-file.file-type-DB-2xhaC.mjs +121 -0
- package/fesm2022/acorex-components-conversation-conversation-file.file-type-DB-2xhaC.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-conversation-image.file-type-C02OzZZB.mjs +84 -0
- package/fesm2022/acorex-components-conversation-conversation-image.file-type-C02OzZZB.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-conversation-info-media-view.component-Mhk7JE6K.mjs +238 -0
- package/fesm2022/acorex-components-conversation-conversation-info-media-view.component-Mhk7JE6K.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-conversation-info-panel.component-CNaM5ajR.mjs +1080 -0
- package/fesm2022/acorex-components-conversation-conversation-info-panel.component-CNaM5ajR.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-conversation-video.file-type-Pescv4Vu.mjs +102 -0
- package/fesm2022/acorex-components-conversation-conversation-video.file-type-Pescv4Vu.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-conversation-voice.file-type-DDd47o4r.mjs +90 -0
- package/fesm2022/acorex-components-conversation-conversation-voice.file-type-DDd47o4r.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-emoji-categories-C7Gm95V0.mjs +1840 -0
- package/fesm2022/acorex-components-conversation-emoji-categories-C7Gm95V0.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-fallback-renderer.component-CYh_6O6j.mjs +44 -0
- package/fesm2022/acorex-components-conversation-fallback-renderer.component-CYh_6O6j.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-file-composer.payload-Dy7aG-EH.mjs +64 -0
- package/fesm2022/acorex-components-conversation-file-composer.payload-Dy7aG-EH.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-file-picker.component-DCVgl33l.mjs +468 -0
- package/fesm2022/acorex-components-conversation-file-picker.component-DCVgl33l.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-file-renderer.component-DgCi06Mg.mjs +125 -0
- package/fesm2022/acorex-components-conversation-file-renderer.component-DgCi06Mg.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-file.payload-DyFxTQYn.mjs +50 -0
- package/fesm2022/acorex-components-conversation-file.payload-DyFxTQYn.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-format-media-DUD4vA6F.mjs +21 -0
- package/fesm2022/acorex-components-conversation-format-media-DUD4vA6F.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-image-attachment.component-CLMGxXPl.mjs +77 -0
- package/fesm2022/acorex-components-conversation-image-attachment.component-CLMGxXPl.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-image-picker.component-CS343UDa.mjs +407 -0
- package/fesm2022/acorex-components-conversation-image-picker.component-CS343UDa.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-image-renderer.component-Cy0TA6cL.mjs +83 -0
- package/fesm2022/acorex-components-conversation-image-renderer.component-Cy0TA6cL.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-index-3V2b14I0.mjs +184 -0
- package/fesm2022/acorex-components-conversation-index-3V2b14I0.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-index-MCvfr9Zd.mjs +266 -0
- package/fesm2022/acorex-components-conversation-index-MCvfr9Zd.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-location-picker.component-DcNQzuoU.mjs +149 -0
- package/fesm2022/acorex-components-conversation-location-picker.component-DcNQzuoU.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-location-renderer.component-Cw2PB0LM.mjs +118 -0
- package/fesm2022/acorex-components-conversation-location-renderer.component-Cw2PB0LM.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-media-formatters-DV3wEEno.mjs +17 -0
- package/fesm2022/acorex-components-conversation-media-formatters-DV3wEEno.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-media-playback-info-bar-banner.component-DbWUl6M2.mjs +140 -0
- package/fesm2022/acorex-components-conversation-media-playback-info-bar-banner.component-DbWUl6M2.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-message-renderer-copy-host.component-oXTr_Lfq.mjs +33 -0
- package/fesm2022/acorex-components-conversation-message-renderer-copy-host.component-oXTr_Lfq.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-message-renderer-state.component-Dp-JdHWr.mjs +172 -0
- package/fesm2022/acorex-components-conversation-message-renderer-state.component-Dp-JdHWr.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-open-composer-picker-for-files-Du8Lj9Sp.mjs +224 -0
- package/fesm2022/acorex-components-conversation-open-composer-picker-for-files-Du8Lj9Sp.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-pagination-demo-data-oIT_YJmN.mjs +81 -0
- package/fesm2022/acorex-components-conversation-pagination-demo-data-oIT_YJmN.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-picker-header.component-BneIFjXq.mjs +91 -0
- package/fesm2022/acorex-components-conversation-picker-header.component-BneIFjXq.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-picker-toolbar.component-BthRvEeE.mjs +537 -0
- package/fesm2022/acorex-components-conversation-picker-toolbar.component-BthRvEeE.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-picker-upload-C-PlKPaU.mjs +163 -0
- package/fesm2022/acorex-components-conversation-picker-upload-C-PlKPaU.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-playback-banner-sync-D8FFKde6.mjs +68 -0
- package/fesm2022/acorex-components-conversation-playback-banner-sync-D8FFKde6.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-renderer-shared.styles-Digah3Zn.mjs +95 -0
- package/fesm2022/acorex-components-conversation-renderer-shared.styles-Digah3Zn.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-search.component-B-nc6xiA.mjs +187 -0
- package/fesm2022/acorex-components-conversation-search.component-B-nc6xiA.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-send-message-media-BRklgfV7.mjs +170 -0
- package/fesm2022/acorex-components-conversation-send-message-media-BRklgfV7.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-shared-storage.seed-J9PA4l3c.mjs +750 -0
- package/fesm2022/acorex-components-conversation-shared-storage.seed-J9PA4l3c.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-sticker-renderer.component-BmBwy7Ig.mjs +103 -0
- package/fesm2022/acorex-components-conversation-sticker-renderer.component-BmBwy7Ig.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-system-renderer.component-uie3tm5N.mjs +55 -0
- package/fesm2022/acorex-components-conversation-system-renderer.component-uie3tm5N.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-text-renderer.component-DNAquHYK.mjs +109 -0
- package/fesm2022/acorex-components-conversation-text-renderer.component-DNAquHYK.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-video-attachment.component-CGaUhnSb.mjs +105 -0
- package/fesm2022/acorex-components-conversation-video-attachment.component-CGaUhnSb.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-video-composer.payload-DMqRkafr.mjs +62 -0
- package/fesm2022/acorex-components-conversation-video-composer.payload-DMqRkafr.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-video-picker.component-DPwSBnoH.mjs +446 -0
- package/fesm2022/acorex-components-conversation-video-picker.component-DPwSBnoH.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-video-renderer.component-DKa9mUe2.mjs +181 -0
- package/fesm2022/acorex-components-conversation-video-renderer.component-DKa9mUe2.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-video.payload-C8QaqxuX.mjs +54 -0
- package/fesm2022/acorex-components-conversation-video.payload-C8QaqxuX.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-voice-composer.payload-DLVow7ex.mjs +17 -0
- package/fesm2022/acorex-components-conversation-voice-composer.payload-DLVow7ex.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-voice-recorder.component-D_rdANZN.mjs +344 -0
- package/fesm2022/acorex-components-conversation-voice-recorder.component-D_rdANZN.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation-voice-renderer.component-BY5FJcT8.mjs +270 -0
- package/fesm2022/acorex-components-conversation-voice-renderer.component-BY5FJcT8.mjs.map +1 -0
- package/fesm2022/acorex-components-conversation.mjs +2 -0
- package/fesm2022/acorex-components-conversation.mjs.map +1 -0
- package/fesm2022/acorex-components-kbd.mjs +2 -2
- package/fesm2022/acorex-components-kbd.mjs.map +1 -1
- package/fesm2022/acorex-components-scheduler-picker.mjs +22 -14
- package/fesm2022/acorex-components-scheduler-picker.mjs.map +1 -1
- package/fesm2022/acorex-components-side-menu.mjs +4 -13
- package/fesm2022/acorex-components-side-menu.mjs.map +1 -1
- package/fesm2022/acorex-components-tree-view.mjs +2 -2
- package/fesm2022/acorex-components-tree-view.mjs.map +1 -1
- package/package.json +6 -10
- package/types/{acorex-components-conversation2.d.ts → acorex-components-conversation.d.ts} +1127 -1928
- package/types/acorex-components-scheduler-picker.d.ts +2 -0
- package/types/acorex-components-side-menu.d.ts +1 -3
- package/fesm2022/acorex-components-conversation2.mjs +0 -22347
- package/fesm2022/acorex-components-conversation2.mjs.map +0 -1
- package/fesm2022/acorex-components-sidebar.mjs +0 -275
- package/fesm2022/acorex-components-sidebar.mjs.map +0 -1
- package/sidebar/README.md +0 -5
- package/types/acorex-components-sidebar.d.ts +0 -132
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import * as i1 from '@acorex/components/search-box';
|
|
2
|
+
import { AXSearchBoxModule } from '@acorex/components/search-box';
|
|
3
|
+
import * as i3 from '@acorex/core/translation';
|
|
4
|
+
import { AXTranslationModule } from '@acorex/core/translation';
|
|
5
|
+
import * as i2 from '@angular/common';
|
|
6
|
+
import { CommonModule } from '@angular/common';
|
|
7
|
+
import * as i0 from '@angular/core';
|
|
8
|
+
import { output, signal, computed, Component } from '@angular/core';
|
|
9
|
+
import { FormsModule } from '@angular/forms';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Emoji Tab Component
|
|
13
|
+
* Emoji picker for composer popup
|
|
14
|
+
*/
|
|
15
|
+
let emojiCategoriesCache = null;
|
|
16
|
+
async function loadEmojiCategories() {
|
|
17
|
+
if (emojiCategoriesCache) {
|
|
18
|
+
return emojiCategoriesCache;
|
|
19
|
+
}
|
|
20
|
+
const module = await import('./acorex-components-conversation-emoji-categories-C7Gm95V0.mjs');
|
|
21
|
+
emojiCategoriesCache =
|
|
22
|
+
module.default ??
|
|
23
|
+
module;
|
|
24
|
+
return emojiCategoriesCache;
|
|
25
|
+
}
|
|
26
|
+
class AXConversationEmojiTabComponent {
|
|
27
|
+
constructor() {
|
|
28
|
+
/** Emoji selected event */
|
|
29
|
+
this.itemSelected = output();
|
|
30
|
+
/** Search query */
|
|
31
|
+
this.searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : /* istanbul ignore next */ []));
|
|
32
|
+
/** Active category */
|
|
33
|
+
this.activeCategoryId = signal('smileys', ...(ngDevMode ? [{ debugName: "activeCategoryId" }] : /* istanbul ignore next */ []));
|
|
34
|
+
/** Categories */
|
|
35
|
+
this.categories = signal([], ...(ngDevMode ? [{ debugName: "categories" }] : /* istanbul ignore next */ []));
|
|
36
|
+
/** Filtered emojis */
|
|
37
|
+
this.filteredEmojis = computed(() => {
|
|
38
|
+
const query = this.searchQuery().toLowerCase().trim();
|
|
39
|
+
const categoryId = this.activeCategoryId();
|
|
40
|
+
if (query) {
|
|
41
|
+
// Search across all categories by name and keywords
|
|
42
|
+
return this.categories()
|
|
43
|
+
.flatMap((cat) => cat.emojis)
|
|
44
|
+
.filter((emoji) => {
|
|
45
|
+
const searchText = `${emoji.name} ${emoji.keywords.join(' ')}`.toLowerCase();
|
|
46
|
+
return searchText.includes(query);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Show active category
|
|
51
|
+
const category = this.categories().find((c) => c.id === categoryId);
|
|
52
|
+
return category ? category.emojis : [];
|
|
53
|
+
}
|
|
54
|
+
}, ...(ngDevMode ? [{ debugName: "filteredEmojis" }] : /* istanbul ignore next */ []));
|
|
55
|
+
void loadEmojiCategories().then((categories) => this.categories.set(categories));
|
|
56
|
+
}
|
|
57
|
+
/** Select category */
|
|
58
|
+
selectCategory(categoryId) {
|
|
59
|
+
this.activeCategoryId.set(categoryId);
|
|
60
|
+
this.searchQuery.set('');
|
|
61
|
+
}
|
|
62
|
+
/** Get category CSS classes */
|
|
63
|
+
getCategoryClasses(categoryId) {
|
|
64
|
+
const classes = ['category-button'];
|
|
65
|
+
if (this.activeCategoryId() === categoryId) {
|
|
66
|
+
classes.push('category-button-active');
|
|
67
|
+
}
|
|
68
|
+
return classes.join(' ');
|
|
69
|
+
}
|
|
70
|
+
onSearchChange(event) {
|
|
71
|
+
this.searchQuery.set(event?.value || '');
|
|
72
|
+
}
|
|
73
|
+
/** Select emoji */
|
|
74
|
+
selectEmoji(emoji) {
|
|
75
|
+
this.itemSelected.emit(emoji);
|
|
76
|
+
}
|
|
77
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXConversationEmojiTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
78
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXConversationEmojiTabComponent, isStandalone: true, selector: "ax-conversation-emoji-tab", outputs: { itemSelected: "itemSelected" }, ngImport: i0, template: `
|
|
79
|
+
<div class="emoji-tab">
|
|
80
|
+
<!-- Search -->
|
|
81
|
+
<div class="emoji-search">
|
|
82
|
+
<ax-search-box
|
|
83
|
+
[value]="searchQuery()"
|
|
84
|
+
[placeholder]="'Search emoji...'"
|
|
85
|
+
(onValueChanged)="onSearchChange($event)"
|
|
86
|
+
></ax-search-box>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<!-- Categories -->
|
|
90
|
+
<div class="emoji-categories">
|
|
91
|
+
@for (category of categories(); track category.id) {
|
|
92
|
+
<button
|
|
93
|
+
type="button"
|
|
94
|
+
[class]="getCategoryClasses(category.id)"
|
|
95
|
+
(click)="selectCategory(category.id)"
|
|
96
|
+
[attr.aria-label]="category.name"
|
|
97
|
+
[title]="category.name"
|
|
98
|
+
>
|
|
99
|
+
{{ category.icon }}
|
|
100
|
+
</button>
|
|
101
|
+
}
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<!-- Emoji Grid -->
|
|
105
|
+
<div class="emoji-grid">
|
|
106
|
+
@for (emoji of filteredEmojis(); track emoji.char) {
|
|
107
|
+
<button
|
|
108
|
+
type="button"
|
|
109
|
+
class="emoji-button"
|
|
110
|
+
(click)="selectEmoji(emoji.char)"
|
|
111
|
+
[attr.aria-label]="emoji.name"
|
|
112
|
+
[title]="emoji.name"
|
|
113
|
+
>
|
|
114
|
+
{{ emoji.char }}
|
|
115
|
+
</button>
|
|
116
|
+
}
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
@if (filteredEmojis().length === 0) {
|
|
120
|
+
<div class="emoji-empty">
|
|
121
|
+
<p>{{ '@acorex:chat.empty.no-emojis-found' | translate | async }}</p>
|
|
122
|
+
</div>
|
|
123
|
+
}
|
|
124
|
+
</div>
|
|
125
|
+
`, isInline: true, styles: [".emoji-tab{display:flex;flex-direction:column;height:100%}.emoji-search{position:sticky;top:0;z-index:10;padding-block:.75rem}.emoji-categories{display:flex;align-items:center;flex-shrink:0;gap:.25rem;margin-bottom:.75rem;padding-bottom:.75rem;overflow-x:auto;border-bottom:1px solid rgb(var(--ax-sys-color-border-light-surface))}.category-button{height:2rem;width:2rem;display:flex;justify-content:center;align-items:center;padding:.25rem;border:none;background:transparent;border-radius:.375rem;cursor:pointer;font-size:1.25rem;transition:all .15s;font-family:\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\",\"Apple Color Emoji\",Twemoji Mozilla,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.category-button:hover{background:rgb(var(--ax-sys-color-light-surface))}.category-button-active{background:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface))}.emoji-grid{display:grid;grid-template-columns:repeat(auto-fill,32px);gap:.25rem;max-height:240px}.emoji-button{width:2rem;height:2rem;padding:.25rem;border:none;background:transparent;border-radius:.375rem;cursor:pointer;font-size:1.5rem;transition:all .15s;display:flex;align-items:center;justify-content:center;font-family:\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\",\"Apple Color Emoji\",Twemoji Mozilla,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.emoji-button:hover{background:rgb(var(--ax-sys-color-light-surface))}.emoji-empty{padding:2rem;text-align:center;opacity:.6}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i1.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }] }); }
|
|
126
|
+
}
|
|
127
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXConversationEmojiTabComponent, decorators: [{
|
|
128
|
+
type: Component,
|
|
129
|
+
args: [{ selector: 'ax-conversation-emoji-tab', imports: [CommonModule, FormsModule, AXSearchBoxModule, AXTranslationModule], template: `
|
|
130
|
+
<div class="emoji-tab">
|
|
131
|
+
<!-- Search -->
|
|
132
|
+
<div class="emoji-search">
|
|
133
|
+
<ax-search-box
|
|
134
|
+
[value]="searchQuery()"
|
|
135
|
+
[placeholder]="'Search emoji...'"
|
|
136
|
+
(onValueChanged)="onSearchChange($event)"
|
|
137
|
+
></ax-search-box>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<!-- Categories -->
|
|
141
|
+
<div class="emoji-categories">
|
|
142
|
+
@for (category of categories(); track category.id) {
|
|
143
|
+
<button
|
|
144
|
+
type="button"
|
|
145
|
+
[class]="getCategoryClasses(category.id)"
|
|
146
|
+
(click)="selectCategory(category.id)"
|
|
147
|
+
[attr.aria-label]="category.name"
|
|
148
|
+
[title]="category.name"
|
|
149
|
+
>
|
|
150
|
+
{{ category.icon }}
|
|
151
|
+
</button>
|
|
152
|
+
}
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
<!-- Emoji Grid -->
|
|
156
|
+
<div class="emoji-grid">
|
|
157
|
+
@for (emoji of filteredEmojis(); track emoji.char) {
|
|
158
|
+
<button
|
|
159
|
+
type="button"
|
|
160
|
+
class="emoji-button"
|
|
161
|
+
(click)="selectEmoji(emoji.char)"
|
|
162
|
+
[attr.aria-label]="emoji.name"
|
|
163
|
+
[title]="emoji.name"
|
|
164
|
+
>
|
|
165
|
+
{{ emoji.char }}
|
|
166
|
+
</button>
|
|
167
|
+
}
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
@if (filteredEmojis().length === 0) {
|
|
171
|
+
<div class="emoji-empty">
|
|
172
|
+
<p>{{ '@acorex:chat.empty.no-emojis-found' | translate | async }}</p>
|
|
173
|
+
</div>
|
|
174
|
+
}
|
|
175
|
+
</div>
|
|
176
|
+
`, styles: [".emoji-tab{display:flex;flex-direction:column;height:100%}.emoji-search{position:sticky;top:0;z-index:10;padding-block:.75rem}.emoji-categories{display:flex;align-items:center;flex-shrink:0;gap:.25rem;margin-bottom:.75rem;padding-bottom:.75rem;overflow-x:auto;border-bottom:1px solid rgb(var(--ax-sys-color-border-light-surface))}.category-button{height:2rem;width:2rem;display:flex;justify-content:center;align-items:center;padding:.25rem;border:none;background:transparent;border-radius:.375rem;cursor:pointer;font-size:1.25rem;transition:all .15s;font-family:\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\",\"Apple Color Emoji\",Twemoji Mozilla,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.category-button:hover{background:rgb(var(--ax-sys-color-light-surface))}.category-button-active{background:rgb(var(--ax-sys-color-primary-lightest-surface));color:rgb(var(--ax-sys-color-on-primary-lightest-surface))}.emoji-grid{display:grid;grid-template-columns:repeat(auto-fill,32px);gap:.25rem;max-height:240px}.emoji-button{width:2rem;height:2rem;padding:.25rem;border:none;background:transparent;border-radius:.375rem;cursor:pointer;font-size:1.5rem;transition:all .15s;display:flex;align-items:center;justify-content:center;font-family:\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\",\"Apple Color Emoji\",Twemoji Mozilla,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.emoji-button:hover{background:rgb(var(--ax-sys-color-light-surface))}.emoji-empty{padding:2rem;text-align:center;opacity:.6}\n"] }]
|
|
177
|
+
}], ctorParameters: () => [], propDecorators: { itemSelected: [{ type: i0.Output, args: ["itemSelected"] }] } });
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Emoji Tab Component
|
|
181
|
+
*/
|
|
182
|
+
|
|
183
|
+
export { AXConversationEmojiTabComponent };
|
|
184
|
+
//# sourceMappingURL=acorex-components-conversation-index-3V2b14I0.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acorex-components-conversation-index-3V2b14I0.mjs","sources":["../../../../packages/components/conversation/src/lib/plugins/composer/components/emoji-tab/emoji-tab.component.ts","../../../../packages/components/conversation/src/lib/plugins/composer/components/emoji-tab/index.ts"],"sourcesContent":["/**\n * Emoji Tab Component\n * Emoji picker for composer popup\n */\n\nimport { AXSearchBoxModule } from '@acorex/components/search-box';\nimport { AXTranslationModule } from '@acorex/core/translation';\nimport { CommonModule } from '@angular/common';\nimport { Component, computed, output, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\ninterface AXConversationEmoji {\n char: string;\n name: string;\n keywords: string[];\n}\n\ninterface AXConversationEmojiCategory {\n id: string;\n name: string;\n icon: string;\n emojis: AXConversationEmoji[];\n}\n\nlet emojiCategoriesCache: AXConversationEmojiCategory[] | null = null;\n\nasync function loadEmojiCategories(): Promise<AXConversationEmojiCategory[]> {\n if (emojiCategoriesCache) {\n return emojiCategoriesCache;\n }\n const module = await import('./emoji-categories.json');\n emojiCategoriesCache =\n (module as { default: AXConversationEmojiCategory[] }).default ??\n (module as unknown as AXConversationEmojiCategory[]);\n return emojiCategoriesCache;\n}\n\n@Component({\n selector: 'ax-conversation-emoji-tab',\n imports: [CommonModule, FormsModule, AXSearchBoxModule, AXTranslationModule],\n template: `\n <div class=\"emoji-tab\">\n <!-- Search -->\n <div class=\"emoji-search\">\n <ax-search-box\n [value]=\"searchQuery()\"\n [placeholder]=\"'Search emoji...'\"\n (onValueChanged)=\"onSearchChange($event)\"\n ></ax-search-box>\n </div>\n\n <!-- Categories -->\n <div class=\"emoji-categories\">\n @for (category of categories(); track category.id) {\n <button\n type=\"button\"\n [class]=\"getCategoryClasses(category.id)\"\n (click)=\"selectCategory(category.id)\"\n [attr.aria-label]=\"category.name\"\n [title]=\"category.name\"\n >\n {{ category.icon }}\n </button>\n }\n </div>\n\n <!-- Emoji Grid -->\n <div class=\"emoji-grid\">\n @for (emoji of filteredEmojis(); track emoji.char) {\n <button\n type=\"button\"\n class=\"emoji-button\"\n (click)=\"selectEmoji(emoji.char)\"\n [attr.aria-label]=\"emoji.name\"\n [title]=\"emoji.name\"\n >\n {{ emoji.char }}\n </button>\n }\n </div>\n\n @if (filteredEmojis().length === 0) {\n <div class=\"emoji-empty\">\n <p>{{ '@acorex:chat.empty.no-emojis-found' | translate | async }}</p>\n </div>\n }\n </div>\n `,\n styles: [\n `\n .emoji-tab {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .emoji-search {\n position: sticky;\n top: 0;\n z-index: 10;\n padding-block: 0.75rem;\n }\n\n .emoji-categories {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n gap: 0.25rem;\n margin-bottom: 0.75rem;\n padding-bottom: 0.75rem;\n overflow-x: auto;\n border-bottom: 1px solid rgb(var(--ax-sys-color-border-light-surface));\n }\n\n .category-button {\n height: 2rem;\n width: 2rem;\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 0.25rem;\n border: none;\n background: transparent;\n border-radius: 0.375rem;\n cursor: pointer;\n font-size: 1.25rem;\n transition: all 0.15s;\n font-family:\n 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji', 'Apple Color Emoji', 'Twemoji Mozilla', sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n .category-button:hover {\n background: rgb(var(--ax-sys-color-light-surface));\n }\n\n .category-button-active {\n background: rgb(var(--ax-sys-color-primary-lightest-surface));\n color: rgb(var(--ax-sys-color-on-primary-lightest-surface));\n }\n\n .emoji-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, 32px);\n gap: 0.25rem;\n max-height: 240px;\n }\n\n .emoji-button {\n width: 2rem;\n height: 2rem;\n padding: 0.25rem;\n border: none;\n background: transparent;\n border-radius: 0.375rem;\n cursor: pointer;\n font-size: 1.5rem;\n transition: all 0.15s;\n display: flex;\n align-items: center;\n justify-content: center;\n font-family:\n 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji', 'Apple Color Emoji', 'Twemoji Mozilla', sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n .emoji-button:hover {\n background: rgb(var(--ax-sys-color-light-surface));\n }\n\n .emoji-empty {\n padding: 2rem;\n text-align: center;\n opacity: 0.6;\n }\n `,\n ],\n})\nexport class AXConversationEmojiTabComponent {\n /** Emoji selected event */\n readonly itemSelected = output<string>();\n\n /** Search query */\n readonly searchQuery = signal('');\n\n /** Active category */\n private readonly activeCategoryId = signal<string>('smileys');\n\n /** Categories */\n readonly categories = signal<AXConversationEmojiCategory[]>([]);\n\n constructor() {\n void loadEmojiCategories().then((categories) => this.categories.set(categories));\n }\n\n /** Filtered emojis */\n readonly filteredEmojis = computed(() => {\n const query = this.searchQuery().toLowerCase().trim();\n const categoryId = this.activeCategoryId();\n\n if (query) {\n // Search across all categories by name and keywords\n return this.categories()\n .flatMap((cat) => cat.emojis)\n .filter((emoji) => {\n const searchText = `${emoji.name} ${emoji.keywords.join(' ')}`.toLowerCase();\n return searchText.includes(query);\n });\n } else {\n // Show active category\n const category = this.categories().find((c) => c.id === categoryId);\n return category ? category.emojis : [];\n }\n });\n\n /** Select category */\n selectCategory(categoryId: string): void {\n this.activeCategoryId.set(categoryId);\n this.searchQuery.set('');\n }\n\n /** Get category CSS classes */\n getCategoryClasses(categoryId: string): string {\n const classes = ['category-button'];\n if (this.activeCategoryId() === categoryId) {\n classes.push('category-button-active');\n }\n return classes.join(' ');\n }\n\n onSearchChange(event: { value?: string }): void {\n this.searchQuery.set(event?.value || '');\n }\n\n /** Select emoji */\n selectEmoji(emoji: string): void {\n this.itemSelected.emit(emoji);\n }\n}\n","/**\n * Emoji Tab Component\n */\n\nexport { AXConversationEmojiTabComponent } from './emoji-tab.component';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import * as i1$1 from '@acorex/components/search-box';
|
|
2
|
+
import { AXSearchBoxModule } from '@acorex/components/search-box';
|
|
3
|
+
import * as i1 from '@acorex/components/skeleton';
|
|
4
|
+
import { AXSkeletonModule } from '@acorex/components/skeleton';
|
|
5
|
+
import * as i3 from '@acorex/core/translation';
|
|
6
|
+
import { AXTranslationModule } from '@acorex/core/translation';
|
|
7
|
+
import * as i2 from '@angular/common';
|
|
8
|
+
import { CommonModule } from '@angular/common';
|
|
9
|
+
import { HttpClient } from '@angular/common/http';
|
|
10
|
+
import * as i0 from '@angular/core';
|
|
11
|
+
import { InjectionToken, inject, DestroyRef, output, signal, effect, Component } from '@angular/core';
|
|
12
|
+
import { FormsModule } from '@angular/forms';
|
|
13
|
+
import { firstValueFrom } from 'rxjs';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Sticker Tab Component
|
|
17
|
+
* Sticker picker for composer popup
|
|
18
|
+
*/
|
|
19
|
+
const AX_CONVERSATION_STICKER_API_KEY = new InjectionToken('AX_CONVERSATION_STICKER_API_KEY', {
|
|
20
|
+
providedIn: 'root',
|
|
21
|
+
factory: () => 'sXpGFDGZs0Dv1mmNFvYaGUvYwKX0PWIh',
|
|
22
|
+
});
|
|
23
|
+
// Sticker categories using Giphy API
|
|
24
|
+
const AX_CONVERSATION_STICKER_CATEGORIES = [
|
|
25
|
+
{ id: 'trending', name: 'Trending', icon: '🔥', searchTerm: 'trending' },
|
|
26
|
+
{ id: 'happy', name: 'Happy', icon: '😊', searchTerm: 'happy' },
|
|
27
|
+
{ id: 'love', name: 'Love', icon: '❤️', searchTerm: 'love' },
|
|
28
|
+
{ id: 'funny', name: 'Funny', icon: '😂', searchTerm: 'funny' },
|
|
29
|
+
{ id: 'cool', name: 'Cool', icon: '😎', searchTerm: 'cool' },
|
|
30
|
+
{ id: 'party', name: 'Party', icon: '🎉', searchTerm: 'party' },
|
|
31
|
+
];
|
|
32
|
+
class AXConversationStickerTabComponent {
|
|
33
|
+
constructor() {
|
|
34
|
+
this.http = inject(HttpClient);
|
|
35
|
+
this.destroyRef = inject(DestroyRef);
|
|
36
|
+
this.apiKey = inject(AX_CONVERSATION_STICKER_API_KEY);
|
|
37
|
+
this.itemSelected = output();
|
|
38
|
+
this.searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : /* istanbul ignore next */ []));
|
|
39
|
+
this.activeStickers = signal([], ...(ngDevMode ? [{ debugName: "activeStickers" }] : /* istanbul ignore next */ []));
|
|
40
|
+
this.loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
41
|
+
this.stickerCategories = AX_CONVERSATION_STICKER_CATEGORIES;
|
|
42
|
+
this.skeletonItems = Array.from({ length: 20 }, (_, i) => i);
|
|
43
|
+
this.activeCategoryId = signal('trending', ...(ngDevMode ? [{ debugName: "activeCategoryId" }] : /* istanbul ignore next */ []));
|
|
44
|
+
effect(() => {
|
|
45
|
+
const categoryId = this.activeCategoryId();
|
|
46
|
+
const query = this.searchQuery();
|
|
47
|
+
if (query.trim()) {
|
|
48
|
+
this.searchStickers(query);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
this.loadStickers(categoryId);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
this.destroyRef.onDestroy(() => {
|
|
55
|
+
if (this.searchTimeout)
|
|
56
|
+
clearTimeout(this.searchTimeout);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async loadStickers(categoryId) {
|
|
60
|
+
this.loading.set(true);
|
|
61
|
+
try {
|
|
62
|
+
const category = AX_CONVERSATION_STICKER_CATEGORIES.find((c) => c.id === categoryId);
|
|
63
|
+
if (!category)
|
|
64
|
+
return;
|
|
65
|
+
const endpoint = categoryId === 'trending'
|
|
66
|
+
? `https://api.giphy.com/v1/stickers/trending?api_key=${this.apiKey}&limit=20`
|
|
67
|
+
: `https://api.giphy.com/v1/stickers/search?api_key=${this.apiKey}&q=${category.searchTerm}&limit=20`;
|
|
68
|
+
const response = await firstValueFrom(this.http.get(endpoint));
|
|
69
|
+
this.activeStickers.set(this.mapGiphyStickers(response, categoryId));
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error('Failed to load stickers:', error);
|
|
73
|
+
this.activeStickers.set([]);
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
this.loading.set(false);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** Select category */
|
|
80
|
+
selectPack(categoryId) {
|
|
81
|
+
this.activeCategoryId.set(categoryId);
|
|
82
|
+
this.searchQuery.set('');
|
|
83
|
+
}
|
|
84
|
+
async searchStickers(query) {
|
|
85
|
+
if (!query.trim()) {
|
|
86
|
+
this.loadStickers(this.activeCategoryId());
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
this.loading.set(true);
|
|
90
|
+
try {
|
|
91
|
+
const endpoint = `https://api.giphy.com/v1/stickers/search?api_key=${this.apiKey}&q=${encodeURIComponent(query)}&limit=20`;
|
|
92
|
+
const response = await firstValueFrom(this.http.get(endpoint));
|
|
93
|
+
this.activeStickers.set(this.mapGiphyStickers(response, 'search'));
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
console.error('Failed to search stickers:', error);
|
|
97
|
+
this.activeStickers.set([]);
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
this.loading.set(false);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
onSearchChange(event) {
|
|
104
|
+
const query = event?.value || '';
|
|
105
|
+
if (this.searchTimeout) {
|
|
106
|
+
clearTimeout(this.searchTimeout);
|
|
107
|
+
}
|
|
108
|
+
this.searchTimeout = setTimeout(() => {
|
|
109
|
+
this.searchQuery.set(query);
|
|
110
|
+
}, 500);
|
|
111
|
+
}
|
|
112
|
+
/** Get category CSS classes */
|
|
113
|
+
getPackClasses(categoryId) {
|
|
114
|
+
const classes = ['pack-button'];
|
|
115
|
+
if (this.activeCategoryId() === categoryId) {
|
|
116
|
+
classes.push('pack-button-active');
|
|
117
|
+
}
|
|
118
|
+
return classes.join(' ');
|
|
119
|
+
}
|
|
120
|
+
mapGiphyStickers(response, packId) {
|
|
121
|
+
if (!response?.data)
|
|
122
|
+
return [];
|
|
123
|
+
return response.data.map((item) => ({
|
|
124
|
+
type: 'sticker',
|
|
125
|
+
id: item.id,
|
|
126
|
+
packId,
|
|
127
|
+
url: item.images.fixed_height.url,
|
|
128
|
+
animated: item.images.fixed_height.url.endsWith('.gif'),
|
|
129
|
+
width: Number(item.images.fixed_height.width),
|
|
130
|
+
height: Number(item.images.fixed_height.height),
|
|
131
|
+
emoji: item.title || 'Sticker',
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
134
|
+
selectSticker(sticker) {
|
|
135
|
+
this.itemSelected.emit(sticker);
|
|
136
|
+
}
|
|
137
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXConversationStickerTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
138
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: AXConversationStickerTabComponent, isStandalone: true, selector: "ax-conversation-sticker-tab", outputs: { itemSelected: "itemSelected" }, ngImport: i0, template: `
|
|
139
|
+
<div class="sticker-tab">
|
|
140
|
+
<!-- Search -->
|
|
141
|
+
<div class="sticker-search">
|
|
142
|
+
<ax-search-box
|
|
143
|
+
[value]="searchQuery()"
|
|
144
|
+
[placeholder]="'Search stickers...'"
|
|
145
|
+
(onValueChanged)="onSearchChange($event)"
|
|
146
|
+
></ax-search-box>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<!-- Categories -->
|
|
150
|
+
<div class="sticker-packs">
|
|
151
|
+
@for (category of stickerCategories; track category.id) {
|
|
152
|
+
<button
|
|
153
|
+
type="button"
|
|
154
|
+
[class]="getPackClasses(category.id)"
|
|
155
|
+
(click)="selectPack(category.id)"
|
|
156
|
+
[attr.aria-label]="category.name"
|
|
157
|
+
[title]="category.name"
|
|
158
|
+
>
|
|
159
|
+
{{ category.icon }}
|
|
160
|
+
</button>
|
|
161
|
+
}
|
|
162
|
+
</div>
|
|
163
|
+
|
|
164
|
+
<!-- Loading State -->
|
|
165
|
+
@if (loading()) {
|
|
166
|
+
<div class="sticker-grid">
|
|
167
|
+
@for (i of skeletonItems; track i) {
|
|
168
|
+
<div class="sticker-skeleton">
|
|
169
|
+
<ax-skeleton [animated]="true" class="skeleton-item"></ax-skeleton>
|
|
170
|
+
</div>
|
|
171
|
+
}
|
|
172
|
+
</div>
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
<!-- Stickers Grid -->
|
|
176
|
+
@if (!loading() && activeStickers().length > 0) {
|
|
177
|
+
<div class="sticker-grid">
|
|
178
|
+
@for (sticker of activeStickers(); track sticker.id) {
|
|
179
|
+
<button
|
|
180
|
+
type="button"
|
|
181
|
+
class="sticker-button"
|
|
182
|
+
(click)="selectSticker(sticker)"
|
|
183
|
+
[attr.aria-label]="sticker.emoji"
|
|
184
|
+
>
|
|
185
|
+
<img [src]="sticker.url" [alt]="sticker.emoji || 'Sticker'" class="sticker-image" loading="lazy" />
|
|
186
|
+
</button>
|
|
187
|
+
}
|
|
188
|
+
</div>
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
<!-- Empty State -->
|
|
192
|
+
@if (!loading() && activeStickers().length === 0) {
|
|
193
|
+
<div class="sticker-empty">
|
|
194
|
+
<p>{{ '@acorex:chat.empty.no-stickers-available' | translate | async }}</p>
|
|
195
|
+
</div>
|
|
196
|
+
}
|
|
197
|
+
</div>
|
|
198
|
+
`, isInline: true, styles: [".sticker-tab{display:flex;flex-direction:column;height:100%}.sticker-search{position:sticky;top:0;z-index:10;padding-block:.75rem}.sticker-packs{display:flex;gap:.25rem;padding-top:.75rem;margin-bottom:.75rem;padding-bottom:.75rem;border-bottom:1px solid rgb(var(--ax-sys-color-border-light-surface))}.pack-button{width:3rem;height:3rem;padding:.5rem;border:none;background:transparent;border-radius:.375rem;cursor:pointer;font-size:1.25rem;transition:all .15s;font-family:\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\",\"Apple Color Emoji\",Twemoji Mozilla,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.pack-button:hover{background:rgb(var(--ax-sys-color-light-surface))}.pack-button-active{background:rgb(var(--ax-sys-color-primary-lightest-surface))}.sticker-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:.5rem;overflow-y:auto;max-height:240px}.sticker-button{padding:.5rem;border:none;background:transparent;border-radius:.375rem;cursor:pointer;transition:all .15s;aspect-ratio:1}.sticker-button:hover{background:rgb(var(--ax-sys-color-light-surface))}.sticker-image{width:100%;height:100%;object-fit:contain}.sticker-empty{padding:2rem;text-align:center;opacity:.6}.sticker-skeleton{height:5rem;aspect-ratio:1;border-radius:.375rem;overflow:hidden}.skeleton-item{width:100%;height:100%;border-radius:.375rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i1.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }, { kind: "ngmodule", type: AXSearchBoxModule }, { kind: "component", type: i1$1.AXSearchBoxComponent, selector: "ax-search-box", inputs: ["disabled", "readonly", "tabIndex", "placeholder", "value", "state", "name", "id", "look", "class", "delayTime", "type", "autoSearch"], outputs: ["valueChange", "stateChange", "onValueChanged", "onBlur", "onFocus", "readonlyChange", "disabledChange", "onKeyDown", "onKeyUp", "onKeyPress"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.AXTranslatorPipe, name: "translate" }] }); }
|
|
199
|
+
}
|
|
200
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXConversationStickerTabComponent, decorators: [{
|
|
201
|
+
type: Component,
|
|
202
|
+
args: [{ selector: 'ax-conversation-sticker-tab', imports: [CommonModule, FormsModule, AXSkeletonModule, AXSearchBoxModule, AXTranslationModule], template: `
|
|
203
|
+
<div class="sticker-tab">
|
|
204
|
+
<!-- Search -->
|
|
205
|
+
<div class="sticker-search">
|
|
206
|
+
<ax-search-box
|
|
207
|
+
[value]="searchQuery()"
|
|
208
|
+
[placeholder]="'Search stickers...'"
|
|
209
|
+
(onValueChanged)="onSearchChange($event)"
|
|
210
|
+
></ax-search-box>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<!-- Categories -->
|
|
214
|
+
<div class="sticker-packs">
|
|
215
|
+
@for (category of stickerCategories; track category.id) {
|
|
216
|
+
<button
|
|
217
|
+
type="button"
|
|
218
|
+
[class]="getPackClasses(category.id)"
|
|
219
|
+
(click)="selectPack(category.id)"
|
|
220
|
+
[attr.aria-label]="category.name"
|
|
221
|
+
[title]="category.name"
|
|
222
|
+
>
|
|
223
|
+
{{ category.icon }}
|
|
224
|
+
</button>
|
|
225
|
+
}
|
|
226
|
+
</div>
|
|
227
|
+
|
|
228
|
+
<!-- Loading State -->
|
|
229
|
+
@if (loading()) {
|
|
230
|
+
<div class="sticker-grid">
|
|
231
|
+
@for (i of skeletonItems; track i) {
|
|
232
|
+
<div class="sticker-skeleton">
|
|
233
|
+
<ax-skeleton [animated]="true" class="skeleton-item"></ax-skeleton>
|
|
234
|
+
</div>
|
|
235
|
+
}
|
|
236
|
+
</div>
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
<!-- Stickers Grid -->
|
|
240
|
+
@if (!loading() && activeStickers().length > 0) {
|
|
241
|
+
<div class="sticker-grid">
|
|
242
|
+
@for (sticker of activeStickers(); track sticker.id) {
|
|
243
|
+
<button
|
|
244
|
+
type="button"
|
|
245
|
+
class="sticker-button"
|
|
246
|
+
(click)="selectSticker(sticker)"
|
|
247
|
+
[attr.aria-label]="sticker.emoji"
|
|
248
|
+
>
|
|
249
|
+
<img [src]="sticker.url" [alt]="sticker.emoji || 'Sticker'" class="sticker-image" loading="lazy" />
|
|
250
|
+
</button>
|
|
251
|
+
}
|
|
252
|
+
</div>
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
<!-- Empty State -->
|
|
256
|
+
@if (!loading() && activeStickers().length === 0) {
|
|
257
|
+
<div class="sticker-empty">
|
|
258
|
+
<p>{{ '@acorex:chat.empty.no-stickers-available' | translate | async }}</p>
|
|
259
|
+
</div>
|
|
260
|
+
}
|
|
261
|
+
</div>
|
|
262
|
+
`, styles: [".sticker-tab{display:flex;flex-direction:column;height:100%}.sticker-search{position:sticky;top:0;z-index:10;padding-block:.75rem}.sticker-packs{display:flex;gap:.25rem;padding-top:.75rem;margin-bottom:.75rem;padding-bottom:.75rem;border-bottom:1px solid rgb(var(--ax-sys-color-border-light-surface))}.pack-button{width:3rem;height:3rem;padding:.5rem;border:none;background:transparent;border-radius:.375rem;cursor:pointer;font-size:1.25rem;transition:all .15s;font-family:\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\",\"Apple Color Emoji\",Twemoji Mozilla,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.pack-button:hover{background:rgb(var(--ax-sys-color-light-surface))}.pack-button-active{background:rgb(var(--ax-sys-color-primary-lightest-surface))}.sticker-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:.5rem;overflow-y:auto;max-height:240px}.sticker-button{padding:.5rem;border:none;background:transparent;border-radius:.375rem;cursor:pointer;transition:all .15s;aspect-ratio:1}.sticker-button:hover{background:rgb(var(--ax-sys-color-light-surface))}.sticker-image{width:100%;height:100%;object-fit:contain}.sticker-empty{padding:2rem;text-align:center;opacity:.6}.sticker-skeleton{height:5rem;aspect-ratio:1;border-radius:.375rem;overflow:hidden}.skeleton-item{width:100%;height:100%;border-radius:.375rem}\n"] }]
|
|
263
|
+
}], ctorParameters: () => [], propDecorators: { itemSelected: [{ type: i0.Output, args: ["itemSelected"] }] } });
|
|
264
|
+
|
|
265
|
+
export { AXConversationStickerTabComponent, AX_CONVERSATION_STICKER_API_KEY };
|
|
266
|
+
//# sourceMappingURL=acorex-components-conversation-index-MCvfr9Zd.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acorex-components-conversation-index-MCvfr9Zd.mjs","sources":["../../../../packages/components/conversation/src/lib/plugins/composer/components/sticker-tab/sticker-tab.component.ts"],"sourcesContent":["/**\n * Sticker Tab Component\n * Sticker picker for composer popup\n */\n\nimport { AXSearchBoxModule } from '@acorex/components/search-box';\nimport { AXSkeletonModule } from '@acorex/components/skeleton';\nimport { AXTranslationModule } from '@acorex/core/translation';\nimport { CommonModule } from '@angular/common';\nimport { HttpClient } from '@angular/common/http';\nimport { Component, DestroyRef, InjectionToken, effect, inject, output, signal } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { firstValueFrom } from 'rxjs';\nimport { AXConversationStickerPayload } from '../../../../models';\n\ninterface AXConversationGiphyImage {\n url: string;\n width: string;\n height: string;\n}\n\ninterface AXConversationGiphySticker {\n id: string;\n title: string;\n images: {\n fixed_height: AXConversationGiphyImage;\n };\n}\n\ninterface AXConversationGiphyResponse {\n data: AXConversationGiphySticker[];\n}\n\nexport const AX_CONVERSATION_STICKER_API_KEY = new InjectionToken<string>('AX_CONVERSATION_STICKER_API_KEY', {\n providedIn: 'root',\n factory: () => 'sXpGFDGZs0Dv1mmNFvYaGUvYwKX0PWIh',\n});\n\ninterface AXConversationStickerCategory {\n id: string;\n name: string;\n icon: string;\n searchTerm: string;\n}\n\n// Sticker categories using Giphy API\nconst AX_CONVERSATION_STICKER_CATEGORIES: AXConversationStickerCategory[] = [\n { id: 'trending', name: 'Trending', icon: '🔥', searchTerm: 'trending' },\n { id: 'happy', name: 'Happy', icon: '😊', searchTerm: 'happy' },\n { id: 'love', name: 'Love', icon: '❤️', searchTerm: 'love' },\n { id: 'funny', name: 'Funny', icon: '😂', searchTerm: 'funny' },\n { id: 'cool', name: 'Cool', icon: '😎', searchTerm: 'cool' },\n { id: 'party', name: 'Party', icon: '🎉', searchTerm: 'party' },\n];\n\n@Component({\n selector: 'ax-conversation-sticker-tab',\n imports: [CommonModule, FormsModule, AXSkeletonModule, AXSearchBoxModule, AXTranslationModule],\n template: `\n <div class=\"sticker-tab\">\n <!-- Search -->\n <div class=\"sticker-search\">\n <ax-search-box\n [value]=\"searchQuery()\"\n [placeholder]=\"'Search stickers...'\"\n (onValueChanged)=\"onSearchChange($event)\"\n ></ax-search-box>\n </div>\n\n <!-- Categories -->\n <div class=\"sticker-packs\">\n @for (category of stickerCategories; track category.id) {\n <button\n type=\"button\"\n [class]=\"getPackClasses(category.id)\"\n (click)=\"selectPack(category.id)\"\n [attr.aria-label]=\"category.name\"\n [title]=\"category.name\"\n >\n {{ category.icon }}\n </button>\n }\n </div>\n\n <!-- Loading State -->\n @if (loading()) {\n <div class=\"sticker-grid\">\n @for (i of skeletonItems; track i) {\n <div class=\"sticker-skeleton\">\n <ax-skeleton [animated]=\"true\" class=\"skeleton-item\"></ax-skeleton>\n </div>\n }\n </div>\n }\n\n <!-- Stickers Grid -->\n @if (!loading() && activeStickers().length > 0) {\n <div class=\"sticker-grid\">\n @for (sticker of activeStickers(); track sticker.id) {\n <button\n type=\"button\"\n class=\"sticker-button\"\n (click)=\"selectSticker(sticker)\"\n [attr.aria-label]=\"sticker.emoji\"\n >\n <img [src]=\"sticker.url\" [alt]=\"sticker.emoji || 'Sticker'\" class=\"sticker-image\" loading=\"lazy\" />\n </button>\n }\n </div>\n }\n\n <!-- Empty State -->\n @if (!loading() && activeStickers().length === 0) {\n <div class=\"sticker-empty\">\n <p>{{ '@acorex:chat.empty.no-stickers-available' | translate | async }}</p>\n </div>\n }\n </div>\n `,\n styles: [\n `\n .sticker-tab {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .sticker-search {\n position: sticky;\n top: 0;\n z-index: 10;\n padding-block: 0.75rem;\n }\n\n .sticker-packs {\n display: flex;\n gap: 0.25rem;\n padding-top: 0.75rem;\n margin-bottom: 0.75rem;\n padding-bottom: 0.75rem;\n border-bottom: 1px solid rgb(var(--ax-sys-color-border-light-surface));\n }\n\n .pack-button {\n width: 3rem;\n height: 3rem;\n padding: 0.5rem;\n border: none;\n background: transparent;\n border-radius: 0.375rem;\n cursor: pointer;\n font-size: 1.25rem;\n transition: all 0.15s;\n font-family:\n 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji', 'Apple Color Emoji', 'Twemoji Mozilla', sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n .pack-button:hover {\n background: rgb(var(--ax-sys-color-light-surface));\n }\n\n .pack-button-active {\n background: rgb(var(--ax-sys-color-primary-lightest-surface));\n }\n\n .sticker-grid {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 0.5rem;\n overflow-y: auto;\n max-height: 240px;\n }\n\n .sticker-button {\n padding: 0.5rem;\n border: none;\n background: transparent;\n border-radius: 0.375rem;\n cursor: pointer;\n transition: all 0.15s;\n aspect-ratio: 1;\n }\n\n .sticker-button:hover {\n background: rgb(var(--ax-sys-color-light-surface));\n }\n\n .sticker-image {\n width: 100%;\n height: 100%;\n object-fit: contain;\n }\n\n .sticker-empty {\n padding: 2rem;\n text-align: center;\n opacity: 0.6;\n }\n\n .sticker-skeleton {\n height: 5rem;\n aspect-ratio: 1;\n border-radius: 0.375rem;\n overflow: hidden;\n }\n\n .skeleton-item {\n width: 100%;\n height: 100%;\n border-radius: 0.375rem;\n }\n `,\n ],\n})\nexport class AXConversationStickerTabComponent {\n private readonly http = inject(HttpClient);\n private readonly destroyRef = inject(DestroyRef);\n private readonly apiKey = inject(AX_CONVERSATION_STICKER_API_KEY);\n\n readonly itemSelected = output<AXConversationStickerPayload>();\n readonly searchQuery = signal('');\n readonly activeStickers = signal<AXConversationStickerPayload[]>([]);\n readonly loading = signal(false);\n readonly stickerCategories = AX_CONVERSATION_STICKER_CATEGORIES;\n readonly skeletonItems = Array.from({ length: 20 }, (_, i) => i);\n\n private readonly activeCategoryId = signal<string>('trending');\n private searchTimeout?: ReturnType<typeof setTimeout>;\n\n constructor() {\n effect(() => {\n const categoryId = this.activeCategoryId();\n const query = this.searchQuery();\n\n if (query.trim()) {\n this.searchStickers(query);\n } else {\n this.loadStickers(categoryId);\n }\n });\n\n this.destroyRef.onDestroy(() => {\n if (this.searchTimeout) clearTimeout(this.searchTimeout);\n });\n }\n\n private async loadStickers(categoryId: string): Promise<void> {\n this.loading.set(true);\n try {\n const category = AX_CONVERSATION_STICKER_CATEGORIES.find((c) => c.id === categoryId);\n if (!category) return;\n\n const endpoint =\n categoryId === 'trending'\n ? `https://api.giphy.com/v1/stickers/trending?api_key=${this.apiKey}&limit=20`\n : `https://api.giphy.com/v1/stickers/search?api_key=${this.apiKey}&q=${category.searchTerm}&limit=20`;\n\n const response = await firstValueFrom(this.http.get<AXConversationGiphyResponse>(endpoint));\n this.activeStickers.set(this.mapGiphyStickers(response, categoryId));\n } catch (error) {\n console.error('Failed to load stickers:', error);\n this.activeStickers.set([]);\n } finally {\n this.loading.set(false);\n }\n }\n\n /** Select category */\n selectPack(categoryId: string): void {\n this.activeCategoryId.set(categoryId);\n this.searchQuery.set('');\n }\n\n private async searchStickers(query: string): Promise<void> {\n if (!query.trim()) {\n this.loadStickers(this.activeCategoryId());\n return;\n }\n\n this.loading.set(true);\n try {\n const endpoint = `https://api.giphy.com/v1/stickers/search?api_key=${this.apiKey}&q=${encodeURIComponent(query)}&limit=20`;\n const response = await firstValueFrom(this.http.get<AXConversationGiphyResponse>(endpoint));\n this.activeStickers.set(this.mapGiphyStickers(response, 'search'));\n } catch (error) {\n console.error('Failed to search stickers:', error);\n this.activeStickers.set([]);\n } finally {\n this.loading.set(false);\n }\n }\n\n onSearchChange(event: { value?: string }): void {\n const query = event?.value || '';\n\n if (this.searchTimeout) {\n clearTimeout(this.searchTimeout);\n }\n\n this.searchTimeout = setTimeout(() => {\n this.searchQuery.set(query);\n }, 500);\n }\n\n /** Get category CSS classes */\n getPackClasses(categoryId: string): string {\n const classes = ['pack-button'];\n if (this.activeCategoryId() === categoryId) {\n classes.push('pack-button-active');\n }\n return classes.join(' ');\n }\n\n private mapGiphyStickers(response: AXConversationGiphyResponse, packId: string): AXConversationStickerPayload[] {\n if (!response?.data) return [];\n return response.data.map((item) => ({\n type: 'sticker' as const,\n id: item.id,\n packId,\n url: item.images.fixed_height.url,\n animated: item.images.fixed_height.url.endsWith('.gif'),\n width: Number(item.images.fixed_height.width),\n height: Number(item.images.fixed_height.height),\n emoji: item.title || 'Sticker',\n }));\n }\n\n selectSticker(sticker: AXConversationStickerPayload): void {\n this.itemSelected.emit(sticker);\n }\n}\n"],"names":["i3","i4"],"mappings":"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"}
|