@masterteam/discussion 0.0.3 → 0.0.4

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.
@@ -1,2 +1,2 @@
1
- /*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-200:oklch(88.5% .062 18.334);--color-red-300:oklch(80.8% .114 19.571);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-emerald-100:oklch(95% .052 163.051);--color-emerald-600:oklch(59.6% .145 163.225);--color-emerald-700:oklch(50.8% .118 165.612);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-semibold:600;--font-weight-bold:700;--radius-sm:.25rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.mx-1{margin-inline:calc(var(--spacing) * 1)}.my-1{margin-block:calc(var(--spacing) * 1)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-px{margin-top:1px}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.ml-1{margin-left:calc(var(--spacing) * 1)}.line-clamp-1{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.flex{display:flex}.hidden{display:none}.inline-flex{display:inline-flex}.h-6{height:calc(var(--spacing) * 6)}.h-12{height:calc(var(--spacing) * 12)}.h-16{height:calc(var(--spacing) * 16)}.h-\[1\.9rem\]{height:1.9rem}.h-full{height:100%}.max-h-48{max-height:calc(var(--spacing) * 48)}.max-h-\[55vh\]{max-height:55vh}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-\[5\.5rem\]{min-height:5.5rem}.min-h-\[5\.25rem\]{min-height:5.25rem}.w-6{width:calc(var(--spacing) * 6)}.w-\[1\.9rem\]{width:1.9rem}.w-full{width:100%}.max-w-\[12rem\]{max-width:12rem}.max-w-\[88\%\]{max-width:88%}.max-w-full{max-width:100%}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-56{min-width:calc(var(--spacing) * 56)}.min-w-\[16rem\]{min-width:16rem}.flex-1{flex:1}.shrink-0{flex-shrink:0}.origin-bottom-left{transform-origin:0 100%}.animate-pulse{animation:var(--animate-pulse)}.cursor-pointer{cursor:pointer}.resize{resize:both}.resize-y{resize:vertical}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\[0\.65rem\]{border-radius:.65rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_18\%\,transparent\)\]{border-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_18\%\,transparent\)\]{border-color:color-mix(in srgb,var(--p-primary-color) 18%,transparent)}}.border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_20\%\,transparent\)\]{border-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_20\%\,transparent\)\]{border-color:color-mix(in srgb,var(--p-primary-color) 20%,transparent)}}.border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_26\%\,transparent\)\]{border-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_26\%\,transparent\)\]{border-color:color-mix(in srgb,var(--p-primary-color) 26%,transparent)}}.border-red-200{border-color:var(--color-red-200)}.border-red-300{border-color:var(--color-red-300)}.border-surface-200{border-color:var(--p-surface-200)}@supports (color:color-mix(in lab, red, red)){.border-surface-200{border-color:color-mix(in srgb, var(--p-surface-200) calc(100% * 1), transparent)}}.border-surface-300{border-color:var(--p-surface-300)}@supports (color:color-mix(in lab, red, red)){.border-surface-300{border-color:color-mix(in srgb, var(--p-surface-300) calc(100% * 1), transparent)}}.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_7\%\,white\)\]{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_7\%\,white\)\]{background-color:color-mix(in srgb,var(--p-primary-color) 7%,white)}}.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_11\%\,white\)\]{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_11\%\,white\)\]{background-color:color-mix(in srgb,var(--p-primary-color) 11%,white)}}.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_12\%\,white\)\]{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_12\%\,white\)\]{background-color:color-mix(in srgb,var(--p-primary-color) 12%,white)}}.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_16\%\,white\)\]{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_16\%\,white\)\]{background-color:color-mix(in srgb,var(--p-primary-color) 16%,white)}}.bg-emerald-100{background-color:var(--color-emerald-100)}.bg-primary-50{background-color:var(--p-primary-50)}@supports (color:color-mix(in lab, red, red)){.bg-primary-50{background-color:color-mix(in srgb, var(--p-primary-50) calc(100% * 1), transparent)}}.bg-red-50{background-color:var(--color-red-50)}.bg-red-100{background-color:var(--color-red-100)}.bg-surface-50{background-color:var(--p-surface-50)}@supports (color:color-mix(in lab, red, red)){.bg-surface-50{background-color:color-mix(in srgb, var(--p-surface-50) calc(100% * 1), transparent)}}.bg-surface-100{background-color:var(--p-surface-100)}@supports (color:color-mix(in lab, red, red)){.bg-surface-100{background-color:color-mix(in srgb, var(--p-surface-100) calc(100% * 1), transparent)}}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-8{padding:calc(var(--spacing) * 8)}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pr-1{padding-right:calc(var(--spacing) * 1)}.text-center{text-align:center}.text-left{text-align:left}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[0\.7rem\]{font-size:.7rem}.text-\[0\.9rem\]{font-size:.9rem}.text-\[0\.67rem\]{font-size:.67rem}.text-\[0\.72rem\]{font-size:.72rem}.text-\[0\.73rem\]{font-size:.73rem}.text-\[0\.74rem\]{font-size:.74rem}.text-\[0\.78rem\]{font-size:.78rem}.text-\[0\.79rem\]{font-size:.79rem}.text-\[0\.86rem\]{font-size:.86rem}.text-\[11px\]{font-size:11px}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.leading-\[1\.2\]{--tw-leading:1.2;line-height:1.2}.leading-\[1\.25\]{--tw-leading:1.25;line-height:1.25}.leading-\[1\.45\]{--tw-leading:1.45;line-height:1.45}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.08em\]{--tw-tracking:.08em;letter-spacing:.08em}.break-words{overflow-wrap:break-word}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_74\%\,black\)\]{color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_74\%\,black\)\]{color:color-mix(in srgb,var(--p-primary-color) 74%,black)}}.text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_75\%\,black\)\]{color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_75\%\,black\)\]{color:color-mix(in srgb,var(--p-primary-color) 75%,black)}}.text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_76\%\,black\)\]{color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_76\%\,black\)\]{color:color-mix(in srgb,var(--p-primary-color) 76%,black)}}.text-emerald-600{color:var(--color-emerald-600)}.text-emerald-700{color:var(--color-emerald-700)}.text-primary-700{color:var(--p-primary-700)}@supports (color:color-mix(in lab, red, red)){.text-primary-700{color:color-mix(in srgb, var(--p-primary-700) calc(100% * 1), transparent)}}.text-red-600{color:var(--color-red-600)}.text-red-700{color:var(--color-red-700)}.text-surface-500{color:var(--p-surface-500)}@supports (color:color-mix(in lab, red, red)){.text-surface-500{color:color-mix(in srgb, var(--p-surface-500) calc(100% * 1), transparent)}}.text-surface-600{color:var(--p-surface-600)}@supports (color:color-mix(in lab, red, red)){.text-surface-600{color:color-mix(in srgb, var(--p-surface-600) calc(100% * 1), transparent)}}.text-surface-700{color:var(--p-surface-700)}@supports (color:color-mix(in lab, red, red)){.text-surface-700{color:color-mix(in srgb, var(--p-surface-700) calc(100% * 1), transparent)}}.text-surface-900{color:var(--p-surface-900)}@supports (color:color-mix(in lab, red, red)){.text-surface-900{color:color-mix(in srgb, var(--p-surface-900) calc(100% * 1), transparent)}}.uppercase{text-transform:uppercase}.opacity-100{opacity:1}.shadow-\[0_10px_40px_color-mix\(in_srgb\,black_14\%\,transparent\)\]{--tw-shadow:0 10px 40px var(--tw-shadow-color,#00000024);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.outline-none{--tw-outline-style:none;outline-style:none}@media (hover:hover){.hover\:border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_24\%\,transparent\)\]:hover{border-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.hover\:border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_24\%\,transparent\)\]:hover{border-color:color-mix(in srgb,var(--p-primary-color) 24%,transparent)}}.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_8\%\,white\)\]:hover{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_8\%\,white\)\]:hover{background-color:color-mix(in srgb,var(--p-primary-color) 8%,white)}}.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_10\%\,white\)\]:hover{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_10\%\,white\)\]:hover{background-color:color-mix(in srgb,var(--p-primary-color) 10%,white)}}.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_11\%\,white\)\]:hover{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_11\%\,white\)\]:hover{background-color:color-mix(in srgb,var(--p-primary-color) 11%,white)}}.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_17\%\,white\)\]:hover{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_17\%\,white\)\]:hover{background-color:color-mix(in srgb,var(--p-primary-color) 17%,white)}}.hover\:bg-surface-50:hover{background-color:var(--p-surface-50)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-surface-50:hover{background-color:color-mix(in srgb, var(--p-surface-50) calc(100% * 1), transparent)}}.hover\:text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_74\%\,black\)\]:hover{color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.hover\:text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_74\%\,black\)\]:hover{color:color-mix(in srgb,var(--p-primary-color) 74%,black)}}}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:outline-offset-1:focus-visible{outline-offset:1px}.focus-visible\:outline-\[color-mix\(in_srgb\,var\(--p-primary-color\)_32\%\,transparent\)\]:focus-visible{outline-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:outline-\[color-mix\(in_srgb\,var\(--p-primary-color\)_32\%\,transparent\)\]:focus-visible{outline-color:color-mix(in srgb,var(--p-primary-color) 32%,transparent)}}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-55:disabled{opacity:.55}@media (min-width:48rem){.md\:opacity-0{opacity:0}@media (hover:hover){.md\:group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}}}@keyframes enter{0%{opacity:var(--p-enter-opacity,1);transform:translate3d(var(--p-enter-translate-x,0), var(--p-enter-translate-y,0), 0) scale3d(var(--p-enter-scale,1), var(--p-enter-scale,1), var(--p-enter-scale,1)) rotate(var(--p-enter-rotate,0))}}@keyframes leave{to{opacity:var(--p-leave-opacity,1);transform:translate3d(var(--p-leave-translate-x,0), var(--p-leave-translate-y,0), 0) scale3d(var(--p-leave-scale,1), var(--p-leave-scale,1), var(--p-leave-scale,1)) rotate(var(--p-leave-rotate,0))}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@keyframes pulse{50%{opacity:.5}}
1
+ /*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-200:oklch(88.5% .062 18.334);--color-red-300:oklch(80.8% .114 19.571);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-emerald-600:oklch(59.6% .145 163.225);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--radius-sm:.25rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.right-1{right:calc(var(--spacing) * 1)}.bottom-1{bottom:calc(var(--spacing) * 1)}.left-0{left:calc(var(--spacing) * 0)}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.mx-1{margin-inline:calc(var(--spacing) * 1)}.my-1{margin-block:calc(var(--spacing) * 1)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-px{margin-top:1px}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.ml-1{margin-left:calc(var(--spacing) * 1)}.line-clamp-1{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.flex{display:flex}.hidden{display:none}.inline-flex{display:inline-flex}.h-6{height:calc(var(--spacing) * 6)}.h-12{height:calc(var(--spacing) * 12)}.h-16{height:calc(var(--spacing) * 16)}.h-\[1\.9rem\]{height:1.9rem}.h-full{height:100%}.max-h-48{max-height:calc(var(--spacing) * 48)}.max-h-\[55vh\]{max-height:55vh}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-\[3\.75rem\]{min-height:3.75rem}.min-h-\[5\.25rem\]{min-height:5.25rem}.w-6{width:calc(var(--spacing) * 6)}.w-\[1\.9rem\]{width:1.9rem}.w-full{width:100%}.max-w-\[12rem\]{max-width:12rem}.max-w-\[90\%\]{max-width:90%}.max-w-full{max-width:100%}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-44{min-width:calc(var(--spacing) * 44)}.min-w-56{min-width:calc(var(--spacing) * 56)}.min-w-\[30rem\]{min-width:30rem}.flex-1{flex:1}.shrink-0{flex-shrink:0}.origin-bottom-left{transform-origin:0 100%}.animate-pulse{animation:var(--animate-pulse)}.cursor-pointer{cursor:pointer}.resize{resize:both}.resize-none{resize:none}.resize-y{resize:vertical}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\[0\.65rem\]{border-radius:.65rem}.rounded-\[1\.5rem\]{border-radius:1.5rem}.rounded-\[1\.35rem\]{border-radius:1.35rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_18\%\,transparent\)\]{border-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_18\%\,transparent\)\]{border-color:color-mix(in srgb,var(--p-primary-color) 18%,transparent)}}.border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_20\%\,transparent\)\]{border-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_20\%\,transparent\)\]{border-color:color-mix(in srgb,var(--p-primary-color) 20%,transparent)}}.border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_26\%\,transparent\)\]{border-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_26\%\,transparent\)\]{border-color:color-mix(in srgb,var(--p-primary-color) 26%,transparent)}}.border-red-200{border-color:var(--color-red-200)}.border-red-300{border-color:var(--color-red-300)}.border-surface-200{border-color:var(--p-surface-200)}@supports (color:color-mix(in lab, red, red)){.border-surface-200{border-color:color-mix(in srgb, var(--p-surface-200) calc(100% * 1), transparent)}}.border-surface-300{border-color:var(--p-surface-300)}@supports (color:color-mix(in lab, red, red)){.border-surface-300{border-color:color-mix(in srgb, var(--p-surface-300) calc(100% * 1), transparent)}}.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_7\%\,white\)\]{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_7\%\,white\)\]{background-color:color-mix(in srgb,var(--p-primary-color) 7%,white)}}.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_11\%\,white\)\]{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_11\%\,white\)\]{background-color:color-mix(in srgb,var(--p-primary-color) 11%,white)}}.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_12\%\,white\)\]{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_12\%\,white\)\]{background-color:color-mix(in srgb,var(--p-primary-color) 12%,white)}}.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_16\%\,white\)\]{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_16\%\,white\)\]{background-color:color-mix(in srgb,var(--p-primary-color) 16%,white)}}.bg-primary-50{background-color:var(--p-primary-50)}@supports (color:color-mix(in lab, red, red)){.bg-primary-50{background-color:color-mix(in srgb, var(--p-primary-50) calc(100% * 1), transparent)}}.bg-red-50{background-color:var(--color-red-50)}.bg-surface-0{background-color:var(--p-surface-0)}@supports (color:color-mix(in lab, red, red)){.bg-surface-0{background-color:color-mix(in srgb, var(--p-surface-0) calc(100% * 1), transparent)}}.bg-surface-50{background-color:var(--p-surface-50)}@supports (color:color-mix(in lab, red, red)){.bg-surface-50{background-color:color-mix(in srgb, var(--p-surface-50) calc(100% * 1), transparent)}}.bg-surface-50\/60{background-color:var(--p-surface-50)}@supports (color:color-mix(in lab, red, red)){.bg-surface-50\/60{background-color:color-mix(in oklab, color-mix(in srgb, var(--p-surface-50) calc(100% * 1), transparent) 60%, transparent)}}.bg-surface-100{background-color:var(--p-surface-100)}@supports (color:color-mix(in lab, red, red)){.bg-surface-100{background-color:color-mix(in srgb, var(--p-surface-100) calc(100% * 1), transparent)}}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-3{padding:calc(var(--spacing) * 3)}.p-8{padding:calc(var(--spacing) * 8)}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-3\.5{padding-block:calc(var(--spacing) * 3.5)}.pt-1{padding-top:calc(var(--spacing) * 1)}.pr-1{padding-right:calc(var(--spacing) * 1)}.pr-24{padding-right:calc(var(--spacing) * 24)}.pb-10{padding-bottom:calc(var(--spacing) * 10)}.text-center{text-align:center}.text-left{text-align:left}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[0\.7rem\]{font-size:.7rem}.text-\[0\.9rem\]{font-size:.9rem}.text-\[0\.67rem\]{font-size:.67rem}.text-\[0\.72rem\]{font-size:.72rem}.text-\[0\.73rem\]{font-size:.73rem}.text-\[0\.74rem\]{font-size:.74rem}.text-\[0\.78rem\]{font-size:.78rem}.text-\[0\.79rem\]{font-size:.79rem}.text-\[0\.86rem\]{font-size:.86rem}.text-\[11px\]{font-size:11px}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.leading-\[1\.2\]{--tw-leading:1.2;line-height:1.2}.leading-\[1\.25\]{--tw-leading:1.25;line-height:1.25}.leading-\[1\.45\]{--tw-leading:1.45;line-height:1.45}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.break-words{overflow-wrap:break-word}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_74\%\,black\)\]{color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_74\%\,black\)\]{color:color-mix(in srgb,var(--p-primary-color) 74%,black)}}.text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_75\%\,black\)\]{color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_75\%\,black\)\]{color:color-mix(in srgb,var(--p-primary-color) 75%,black)}}.text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_76\%\,black\)\]{color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_76\%\,black\)\]{color:color-mix(in srgb,var(--p-primary-color) 76%,black)}}.text-emerald-600{color:var(--color-emerald-600)}.text-primary-700{color:var(--p-primary-700)}@supports (color:color-mix(in lab, red, red)){.text-primary-700{color:color-mix(in srgb, var(--p-primary-700) calc(100% * 1), transparent)}}.text-red-600{color:var(--color-red-600)}.text-red-700{color:var(--color-red-700)}.text-surface-500{color:var(--p-surface-500)}@supports (color:color-mix(in lab, red, red)){.text-surface-500{color:color-mix(in srgb, var(--p-surface-500) calc(100% * 1), transparent)}}.text-surface-600{color:var(--p-surface-600)}@supports (color:color-mix(in lab, red, red)){.text-surface-600{color:color-mix(in srgb, var(--p-surface-600) calc(100% * 1), transparent)}}.text-surface-700{color:var(--p-surface-700)}@supports (color:color-mix(in lab, red, red)){.text-surface-700{color:color-mix(in srgb, var(--p-surface-700) calc(100% * 1), transparent)}}.text-surface-900{color:var(--p-surface-900)}@supports (color:color-mix(in lab, red, red)){.text-surface-900{color:color-mix(in srgb, var(--p-surface-900) calc(100% * 1), transparent)}}.shadow-\[0_8px_24px_color-mix\(in_srgb\,black_4\%\,transparent\)\]{--tw-shadow:0 8px 24px var(--tw-shadow-color,#0000000a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_10px_40px_color-mix\(in_srgb\,black_14\%\,transparent\)\]{--tw-shadow:0 10px 40px var(--tw-shadow-color,#00000024);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.outline-none{--tw-outline-style:none;outline-style:none}@media (hover:hover){.hover\:border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_24\%\,transparent\)\]:hover{border-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.hover\:border-\[color-mix\(in_srgb\,var\(--p-primary-color\)_24\%\,transparent\)\]:hover{border-color:color-mix(in srgb,var(--p-primary-color) 24%,transparent)}}.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_8\%\,white\)\]:hover{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_8\%\,white\)\]:hover{background-color:color-mix(in srgb,var(--p-primary-color) 8%,white)}}.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_10\%\,white\)\]:hover{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_10\%\,white\)\]:hover{background-color:color-mix(in srgb,var(--p-primary-color) 10%,white)}}.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_11\%\,white\)\]:hover{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_11\%\,white\)\]:hover{background-color:color-mix(in srgb,var(--p-primary-color) 11%,white)}}.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_17\%\,white\)\]:hover{background-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-\[color-mix\(in_srgb\,var\(--p-primary-color\)_17\%\,white\)\]:hover{background-color:color-mix(in srgb,var(--p-primary-color) 17%,white)}}.hover\:bg-surface-50:hover{background-color:var(--p-surface-50)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-surface-50:hover{background-color:color-mix(in srgb, var(--p-surface-50) calc(100% * 1), transparent)}}.hover\:bg-surface-100:hover{background-color:var(--p-surface-100)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-surface-100:hover{background-color:color-mix(in srgb, var(--p-surface-100) calc(100% * 1), transparent)}}.hover\:text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_74\%\,black\)\]:hover{color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.hover\:text-\[color-mix\(in_srgb\,var\(--p-primary-color\)_74\%\,black\)\]:hover{color:color-mix(in srgb,var(--p-primary-color) 74%,black)}}}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:outline-offset-1:focus-visible{outline-offset:1px}.focus-visible\:outline-\[color-mix\(in_srgb\,var\(--p-primary-color\)_32\%\,transparent\)\]:focus-visible{outline-color:var(--p-primary-color)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:outline-\[color-mix\(in_srgb\,var\(--p-primary-color\)_32\%\,transparent\)\]:focus-visible{outline-color:color-mix(in srgb,var(--p-primary-color) 32%,transparent)}}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-55:disabled{opacity:.55}}@keyframes enter{0%{opacity:var(--p-enter-opacity,1);transform:translate3d(var(--p-enter-translate-x,0), var(--p-enter-translate-y,0), 0) scale3d(var(--p-enter-scale,1), var(--p-enter-scale,1), var(--p-enter-scale,1)) rotate(var(--p-enter-rotate,0))}}@keyframes leave{to{opacity:var(--p-leave-opacity,1);transform:translate3d(var(--p-leave-translate-x,0), var(--p-leave-translate-y,0), 0) scale3d(var(--p-leave-scale,1), var(--p-leave-scale,1), var(--p-leave-scale,1)) rotate(var(--p-leave-rotate,0))}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@keyframes pulse{50%{opacity:.5}}
@@ -10,9 +10,12 @@ import { Card } from '@masterteam/components/card';
10
10
  import { EntitiesPreview } from '@masterteam/components/entities';
11
11
  import * as i3 from 'primeng/dialog';
12
12
  import { DialogModule } from 'primeng/dialog';
13
+ import * as i4 from 'primeng/popover';
14
+ import { PopoverModule } from 'primeng/popover';
13
15
  import { map, filter, Subject, firstValueFrom, debounceTime, distinctUntilChanged, switchMap, of, catchError, finalize } from 'rxjs';
14
16
  import { HttpClient, HttpContext, HttpParams, HttpEventType, HttpHeaders } from '@angular/common/http';
15
17
  import { REQUEST_CONTEXT } from '@masterteam/components';
18
+ import { Icon } from '@masterteam/icons';
16
19
 
17
20
  const MODULE_TYPE_ALIASES = {
18
21
  leveldata: 'Level',
@@ -505,7 +508,6 @@ class DiscussionThread {
505
508
  return summary ? mapSummaryToReadState(summary) : null;
506
509
  }, ...(ngDevMode ? [{ debugName: "readStateLike" }] : []));
507
510
  hasUnread = computed(() => this.readStateLike()?.hasUnread ?? false, ...(ngDevMode ? [{ debugName: "hasUnread" }] : []));
508
- unreadCount = computed(() => this.readStateLike()?.unreadCount ?? 0, ...(ngDevMode ? [{ debugName: "unreadCount" }] : []));
509
511
  firstUnreadCommentId = computed(() => this.resolveFirstUnreadCommentId(this.commentsAsc(), this.readStateLike()), ...(ngDevMode ? [{ debugName: "firstUnreadCommentId" }] : []));
510
512
  mentionPool = computed(() => dedupeMentionUsers([
511
513
  ...this.mentionableUsers(),
@@ -548,7 +550,6 @@ class DiscussionThread {
548
550
  const text = this.editText();
549
551
  return text.trim().length > 0 && text.length <= 10000;
550
552
  }, ...(ngDevMode ? [{ debugName: "canSaveEdit" }] : []));
551
- charactersLeft = computed(() => 10000 - this.composerText().length, ...(ngDevMode ? [{ debugName: "charactersLeft" }] : []));
552
553
  visibleRevisions = computed(() => {
553
554
  const commentId = this.selectedRevisionComment()?.id;
554
555
  if (commentId == null) {
@@ -847,22 +848,6 @@ class DiscussionThread {
847
848
  this.markingRead.set(false);
848
849
  }
849
850
  }
850
- async markUnread() {
851
- if (this.markingRead()) {
852
- return;
853
- }
854
- this.markingRead.set(true);
855
- try {
856
- await firstValueFrom(this.api.clearReadState(this.resolvedModuleType(), this.resolvedRecordId(), this.requestContext()));
857
- await this.refreshReadState();
858
- }
859
- catch (error) {
860
- this.handleError(error, 'Unable to update read state.');
861
- }
862
- finally {
863
- this.markingRead.set(false);
864
- }
865
- }
866
851
  onViewportScroll() {
867
852
  const viewport = this.viewportRef()?.nativeElement;
868
853
  if (!viewport) {
@@ -1633,7 +1618,7 @@ class DiscussionThread {
1633
1618
  return `${fileName}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
1634
1619
  }
1635
1620
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DiscussionThread, deps: [], target: i0.ɵɵFactoryTarget.Component });
1636
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: DiscussionThread, isStandalone: true, selector: "mt-discussion-thread", inputs: { moduleType: { classPropertyName: "moduleType", publicName: "moduleType", isSignal: true, isRequired: true, transformFunction: null }, recordId: { classPropertyName: "recordId", publicName: "recordId", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, currentUserId: { classPropertyName: "currentUserId", publicName: "currentUserId", isSignal: true, isRequired: false, transformFunction: null }, requestContext: { classPropertyName: "requestContext", publicName: "requestContext", isSignal: true, isRequired: false, transformFunction: null }, mentionableUsers: { classPropertyName: "mentionableUsers", publicName: "mentionableUsers", isSignal: true, isRequired: false, transformFunction: null }, mentionSearchEndpoint: { classPropertyName: "mentionSearchEndpoint", publicName: "mentionSearchEndpoint", isSignal: true, isRequired: false, transformFunction: null }, mentionSearchParam: { classPropertyName: "mentionSearchParam", publicName: "mentionSearchParam", isSignal: true, isRequired: false, transformFunction: null }, mentionSearchDataPath: { classPropertyName: "mentionSearchDataPath", publicName: "mentionSearchDataPath", isSignal: true, isRequired: false, transformFunction: null }, allowAttachments: { classPropertyName: "allowAttachments", publicName: "allowAttachments", isSignal: true, isRequired: false, transformFunction: null }, uploadEndpoint: { classPropertyName: "uploadEndpoint", publicName: "uploadEndpoint", isSignal: true, isRequired: false, transformFunction: null }, attachmentDownloadEndpoint: { classPropertyName: "attachmentDownloadEndpoint", publicName: "attachmentDownloadEndpoint", isSignal: true, isRequired: false, transformFunction: null }, showParticipants: { classPropertyName: "showParticipants", publicName: "showParticipants", isSignal: true, isRequired: false, transformFunction: null }, autoMarkRead: { classPropertyName: "autoMarkRead", publicName: "autoMarkRead", isSignal: true, isRequired: false, transformFunction: null }, refreshIntervalMs: { classPropertyName: "refreshIntervalMs", publicName: "refreshIntervalMs", isSignal: true, isRequired: false, transformFunction: null }, styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loaded: "loaded", errored: "errored", commentCreated: "commentCreated", commentUpdated: "commentUpdated", commentDeleted: "commentDeleted", readStateChanged: "readStateChanged" }, host: { classAttribute: "block h-full min-h-0" }, viewQueries: [{ propertyName: "viewportRef", first: true, predicate: ["viewport"], descendants: true, isSignal: true }, { propertyName: "composerInputRef", first: true, predicate: ["composerInput"], descendants: true, isSignal: true }, { propertyName: "attachmentInputRef", first: true, predicate: ["attachmentInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<mt-card\r\n class=\"mt-discussion-card h-full min-h-0 w-full overflow-hidden shadow-sm\"\r\n [paddingless]=\"true\"\r\n [ngClass]=\"styleClass()\"\r\n>\r\n <div class=\"flex h-full min-h-0 flex-col overflow-hidden\">\r\n <input\r\n #attachmentInput\r\n type=\"file\"\r\n class=\"hidden\"\r\n multiple\r\n (change)=\"onAttachmentSelected($event)\"\r\n />\r\n\r\n <header\r\n class=\"flex flex-wrap items-start justify-between gap-3 border-b border-surface-200 px-4 py-3\"\r\n >\r\n <div class=\"min-w-0\">\r\n <h3 class=\"truncate text-sm font-semibold uppercase tracking-[0.08em]\">\r\n {{ title() }}\r\n </h3>\r\n @if (subtitle()) {\r\n <p class=\"mt-1 text-xs text-surface-500\">{{ subtitle() }}</p>\r\n }\r\n <p class=\"mt-1 text-xs text-surface-500\">\r\n {{ threadKey() || \"Discussion\" }}\r\n </p>\r\n </div>\r\n\r\n <div class=\"flex flex-wrap items-center gap-2\">\r\n @if (unreadCount() > 0) {\r\n <span\r\n class=\"inline-flex items-center rounded-full bg-red-100 px-2 py-0.5 text-xs font-semibold text-red-700\"\r\n >\r\n {{ unreadCount() }} unread\r\n </span>\r\n } @else {\r\n <span\r\n class=\"inline-flex items-center rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-semibold text-emerald-700\"\r\n >\r\n Up to date\r\n </span>\r\n }\r\n\r\n <mt-button\r\n icon=\"arrow.refresh-cw-01\"\r\n [label]=\"refreshing() ? 'Refreshing...' : 'Refresh'\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n [loading]=\"refreshing()\"\r\n [disabled]=\"loadingInitial()\"\r\n (onClick)=\"refreshThread()\"\r\n />\r\n <mt-button\r\n icon=\"general.check\"\r\n label=\"Mark read\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n [disabled]=\"markingRead() || !hasUnread()\"\r\n (onClick)=\"markRead()\"\r\n />\r\n <mt-button\r\n icon=\"communication.mail-01\"\r\n label=\"Mark unread\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n [disabled]=\"markingRead()\"\r\n (onClick)=\"markUnread()\"\r\n />\r\n @if (showParticipants()) {\r\n <mt-button\r\n icon=\"user.users-01\"\r\n [label]=\"'Participants (' + participants().length + ')'\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n (onClick)=\"toggleParticipantsPanel()\"\r\n />\r\n }\r\n </div>\r\n </header>\r\n\r\n @if (showParticipants() && participantsExpanded()) {\r\n <section class=\"border-b border-surface-200 px-4 py-3\">\r\n @if (participantsLoading()) {\r\n <span class=\"text-xs text-surface-500\">Loading participants...</span>\r\n } @else if (participantEntities().length === 0) {\r\n <span class=\"text-xs text-surface-500\">No participants yet.</span>\r\n } @else {\r\n <div class=\"max-h-48 overflow-y-auto pr-1\">\r\n <mt-entities-preview [entities]=\"participantEntities()\" />\r\n </div>\r\n }\r\n </section>\r\n }\r\n\r\n @if (errorMessage(); as error) {\r\n <div\r\n class=\"border-b border-red-200 bg-red-50 px-4 py-2 text-sm text-red-700\"\r\n >\r\n {{ error }}\r\n </div>\r\n }\r\n\r\n <div class=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\r\n <div\r\n #viewport\r\n class=\"min-h-0 flex-1 space-y-3 overflow-y-auto overscroll-contain px-3 py-3\"\r\n (scroll)=\"onViewportScroll()\"\r\n >\r\n @if (hasMore()) {\r\n <div class=\"flex justify-center py-1\">\r\n <mt-button\r\n icon=\"arrow.chevron-up\"\r\n [label]=\"loadingMore() ? 'Loading...' : 'Load older messages'\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n [loading]=\"loadingMore()\"\r\n (onClick)=\"loadOlder()\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (loadingInitial()) {\r\n <div class=\"space-y-2\">\r\n @for (item of [1, 2, 3, 4]; track item) {\r\n <div class=\"h-16 animate-pulse rounded-xl bg-surface-100\"></div>\r\n }\r\n </div>\r\n } @else if (commentsAsc().length === 0) {\r\n <div\r\n class=\"rounded-2xl border border-dashed border-surface-300 p-8 text-center\"\r\n >\r\n <h4 class=\"text-sm font-semibold text-surface-700\">\r\n No comments yet\r\n </h4>\r\n <p class=\"mt-1 text-xs text-surface-500\">Start the conversation.</p>\r\n </div>\r\n } @else {\r\n @for (comment of commentsAsc(); track trackComment($index, comment)) {\r\n @if (firstUnreadCommentId() === comment.id) {\r\n <div class=\"my-1 flex items-center justify-center gap-2\">\r\n <span\r\n class=\"flex-1 border-t border-dashed border-red-300\"\r\n ></span>\r\n <span\r\n class=\"rounded-full border border-red-200 bg-red-50 px-2 py-0.5 text-[0.67rem] font-bold leading-none text-red-700\"\r\n >Unread messages</span\r\n >\r\n <span\r\n class=\"flex-1 border-t border-dashed border-red-300\"\r\n ></span>\r\n </div>\r\n }\r\n\r\n <article\r\n class=\"group flex gap-2\"\r\n [class.justify-end]=\"isOwnComment(comment)\"\r\n >\r\n @if (!isOwnComment(comment)) {\r\n <div\r\n class=\"mt-0.5 inline-flex h-[1.9rem] w-[1.9rem] shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_20%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.74rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_75%,black)]\"\r\n >\r\n {{ getAvatarText(comment) }}\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"max-w-[88%] min-w-[16rem] rounded-2xl border border-surface-200 px-3 py-2\"\r\n [class.bg-[color-mix(in_srgb,var(--p-primary-color)_7%,white)]]=\"\r\n isOwnComment(comment)\r\n \"\r\n >\r\n <div\r\n class=\"mb-1 flex flex-wrap items-center justify-between gap-2\"\r\n >\r\n <div class=\"text-xs text-surface-600\">\r\n <span class=\"font-semibold text-surface-900\">{{\r\n comment.createdBy\r\n }}</span>\r\n <span class=\"mx-1\">&bull;</span>\r\n <span>{{\r\n comment.createdAt | date: \"MMM d, y h:mm a\"\r\n }}</span>\r\n @if (comment.updatedAt) {\r\n <span class=\"ml-1 text-[11px] text-surface-500\"\r\n >(edited)</span\r\n >\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (getParentComment(comment); as parentComment) {\r\n <button\r\n type=\"button\"\r\n class=\"mb-2 block w-full rounded-xl border border-surface-200 bg-surface-50 px-2 py-1 text-left text-xs text-surface-600\"\r\n (click)=\"openReply(parentComment)\"\r\n >\r\n <span class=\"font-semibold\">{{\r\n parentComment.createdBy\r\n }}</span>\r\n <span class=\"mx-1\">:</span>\r\n <span class=\"line-clamp-1\">{{\r\n parentComment.comment\r\n }}</span>\r\n </button>\r\n }\r\n\r\n @if (editingCommentId() === comment.id) {\r\n <div class=\"relative\">\r\n <textarea\r\n rows=\"3\"\r\n class=\"w-full min-h-[5.25rem] resize-y rounded-2xl border border-surface-300 bg-white px-3 py-2.5 text-[0.86rem] leading-[1.45] text-surface-900 outline-none focus-visible:outline-2 focus-visible:outline-[color-mix(in_srgb,var(--p-primary-color)_32%,transparent)] focus-visible:outline-offset-1\"\r\n [ngModel]=\"editText()\"\r\n (ngModelChange)=\"editText.set($event)\"\r\n (input)=\"onEditInput($event)\"\r\n (keyup)=\"onEditCaretEvent($event)\"\r\n (click)=\"onEditCaretEvent($event)\"\r\n (scroll)=\"onEditCaretEvent($event)\"\r\n (keydown)=\"onEditKeydown($event)\"\r\n ></textarea>\r\n\r\n @if (\r\n mentionSession()?.mode === \"edit\" &&\r\n mentionSession()?.editCommentId === comment.id\r\n ) {\r\n <div\r\n class=\"absolute top-0 left-0 z-20 min-w-56 overflow-auto rounded-xl border border-surface-300 bg-white shadow-[0_10px_40px_color-mix(in_srgb,black_14%,transparent)]\"\r\n [ngStyle]=\"mentionMenuStyle()\"\r\n [class.origin-bottom-left]=\"\r\n mentionMenuPosition()?.placement === 'above'\r\n \"\r\n >\r\n @if (mentionLoading()) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n Searching...\r\n </div>\r\n } @else if (mentionCandidates().length === 0) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n No matches\r\n </div>\r\n } @else {\r\n @for (\r\n candidate of mentionCandidates();\r\n track candidate.userId;\r\n let i = $index\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full cursor-pointer items-start gap-2 bg-transparent px-2.5 py-2 text-left text-[0.78rem] transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]\"\r\n [class.bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]]=\"\r\n mentionActiveIndex() === i\r\n \"\r\n (click)=\"selectMention(candidate)\"\r\n >\r\n <span\r\n class=\"mt-px inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_18%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.7rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)]\"\r\n >\r\n {{ getMentionAvatarText(candidate) }}\r\n </span>\r\n <span\r\n class=\"flex min-w-0 flex-1 flex-col gap-0.5\"\r\n >\r\n <span\r\n class=\"text-[0.79rem] leading-[1.25] font-semibold text-surface-900\"\r\n >{{\r\n candidate.displayName ||\r\n candidate.userName ||\r\n candidate.userId\r\n }}</span\r\n >\r\n <span\r\n class=\"inline-flex items-center text-[0.73rem] leading-[1.2] text-surface-500\"\r\n >\r\n @{{ candidate.userId }}\r\n </span>\r\n </span>\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"mt-2 flex flex-wrap items-center justify-between gap-2\"\r\n >\r\n <span class=\"text-xs text-surface-500\"\r\n >{{ editText().length }}/10000</span\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <button\r\n type=\"button\"\r\n class=\"rounded-[0.65rem] border border-surface-300 bg-transparent px-3 py-2 text-xs font-semibold leading-none text-surface-700 transition-colors hover:border-[color-mix(in_srgb,var(--p-primary-color)_24%,transparent)] hover:bg-[color-mix(in_srgb,var(--p-primary-color)_8%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"cancelEdit()\"\r\n >\r\n Cancel\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"rounded-[0.65rem] border border-[color-mix(in_srgb,var(--p-primary-color)_26%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_12%,white)] px-3 py-2 text-xs font-bold leading-none text-[color-mix(in_srgb,var(--p-primary-color)_76%,black)] transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_17%,white)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n [disabled]=\"!canSaveEdit()\"\r\n (click)=\"saveEdit()\"\r\n >\r\n {{ savingEdit() ? \"Saving...\" : \"Save\" }}\r\n </button>\r\n </div>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"whitespace-pre-wrap break-words text-sm leading-6\"\r\n >\r\n @for (\r\n segment of getCommentSegments(comment);\r\n track $index\r\n ) {\r\n <span\r\n [ngClass]=\"\r\n segment.isMention\r\n ? 'rounded-sm bg-primary-50 px-0.5 font-semibold text-primary-700'\r\n : ''\r\n \"\r\n [attr.data-user-id]=\"segment.userId || null\"\r\n >\r\n {{ segment.text }}\r\n </span>\r\n }\r\n </div>\r\n\r\n @if (comment.attachments.length > 0) {\r\n <div class=\"mt-2 flex flex-wrap gap-2\">\r\n @for (\r\n attachment of comment.attachments;\r\n track attachment.id\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"inline-flex max-w-full items-center gap-1.5 rounded-lg border border-surface-300 px-2 py-1 text-[0.72rem] hover:bg-surface-50\"\r\n (click)=\"downloadAttachment(comment, attachment)\"\r\n >\r\n <span class=\"truncate\">{{\r\n attachment.fileName\r\n }}</span>\r\n <span class=\"text-[11px] text-surface-500\"\r\n >({{ attachment.size | number }} bytes)</span\r\n >\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"mt-2 flex flex-wrap items-center gap-1 opacity-100 md:opacity-0 md:group-hover:opacity-100\"\r\n >\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"openReply(comment)\"\r\n >\r\n Reply\r\n </button>\r\n @if (canEditComment(comment)) {\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"startEdit(comment)\"\r\n >\r\n Edit\r\n </button>\r\n }\r\n @if (canDeleteComment(comment)) {\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-red-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n [disabled]=\"isDeleting(comment.id)\"\r\n (click)=\"deleteComment(comment)\"\r\n >\r\n {{ isDeleting(comment.id) ? \"Deleting...\" : \"Delete\" }}\r\n </button>\r\n }\r\n @if (comment.updatedAt) {\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"openRevisions(comment)\"\r\n >\r\n History\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (isOwnComment(comment)) {\r\n <div\r\n class=\"mt-0.5 inline-flex h-[1.9rem] w-[1.9rem] shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_20%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.74rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_75%,black)]\"\r\n >\r\n {{ getAvatarText(comment) }}\r\n </div>\r\n }\r\n </article>\r\n }\r\n }\r\n </div>\r\n\r\n <footer\r\n class=\"z-10 shrink-0 border-t border-surface-200 bg-content px-3 py-3\"\r\n >\r\n @if (replyToComment(); as replyComment) {\r\n <div\r\n class=\"mb-2 flex items-center justify-between rounded-xl border border-surface-200 bg-surface-50 px-2 py-1\"\r\n >\r\n <div class=\"min-w-0 text-xs text-surface-600\">\r\n <span class=\"font-semibold\"\r\n >Replying to {{ replyComment.createdBy }}</span\r\n >\r\n <p class=\"truncate\">{{ replyComment.comment }}</p>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"clearReply()\"\r\n >\r\n Cancel\r\n </button>\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"rounded-2xl border border-surface-300 bg-white p-2 shadow-sm\"\r\n >\r\n <div class=\"relative\">\r\n <textarea\r\n #composerInput\r\n rows=\"3\"\r\n class=\"w-full min-h-[5.5rem] resize-y border-0 bg-transparent px-2 py-1 text-[0.9rem] leading-[1.45] text-surface-900 outline-none\"\r\n [disabled]=\"disabled() || posting()\"\r\n [ngModel]=\"composerText()\"\r\n (ngModelChange)=\"composerText.set($event)\"\r\n (input)=\"onComposerInput($event)\"\r\n (keyup)=\"onComposerCaretEvent($event)\"\r\n (click)=\"onComposerCaretEvent($event)\"\r\n (scroll)=\"onComposerCaretEvent($event)\"\r\n (keydown)=\"onComposerKeydown($event)\"\r\n [placeholder]=\"placeholder()\"\r\n ></textarea>\r\n\r\n @if (mentionSession()?.mode === \"composer\") {\r\n <div\r\n class=\"absolute top-0 left-0 z-30 min-w-56 overflow-auto rounded-xl border border-surface-300 bg-white shadow-[0_10px_40px_color-mix(in_srgb,black_14%,transparent)]\"\r\n [ngStyle]=\"mentionMenuStyle()\"\r\n [class.origin-bottom-left]=\"\r\n mentionMenuPosition()?.placement === 'above'\r\n \"\r\n >\r\n @if (mentionLoading()) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n Searching...\r\n </div>\r\n } @else if (mentionCandidates().length === 0) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n No matches\r\n </div>\r\n } @else {\r\n @for (\r\n candidate of mentionCandidates();\r\n track candidate.userId;\r\n let i = $index\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full cursor-pointer items-start gap-2 bg-transparent px-2.5 py-2 text-left text-[0.78rem] transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]\"\r\n [class.bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]]=\"\r\n mentionActiveIndex() === i\r\n \"\r\n (click)=\"selectMention(candidate)\"\r\n >\r\n <span\r\n class=\"mt-px inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_18%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.7rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)]\"\r\n >\r\n {{ getMentionAvatarText(candidate) }}\r\n </span>\r\n <span class=\"flex min-w-0 flex-1 flex-col gap-0.5\">\r\n <span\r\n class=\"text-[0.79rem] leading-[1.25] font-semibold text-surface-900\"\r\n >{{\r\n candidate.displayName ||\r\n candidate.userName ||\r\n candidate.userId\r\n }}</span\r\n >\r\n <span\r\n class=\"inline-flex items-center text-[0.73rem] leading-[1.2] text-surface-500\"\r\n >\r\n @{{ candidate.userId }}\r\n </span>\r\n </span>\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (composerAttachments().length > 0) {\r\n <div class=\"mt-2 flex flex-wrap gap-2 px-1\">\r\n @for (attachment of composerAttachments(); track attachment.id) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-2 py-1 text-xs\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"max-w-[12rem] truncate\">{{\r\n attachment.fileName\r\n }}</span>\r\n @if (attachment.status === \"uploading\") {\r\n <span class=\"text-surface-500\"\r\n >{{ attachment.progress }}%</span\r\n >\r\n } @else if (attachment.status === \"failed\") {\r\n <span class=\"text-red-600\">Failed</span>\r\n } @else {\r\n <span class=\"text-emerald-600\">Ready</span>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"removeAttachment(attachment.id)\"\r\n >\r\n Remove\r\n </button>\r\n </div>\r\n @if (attachment.error) {\r\n <p class=\"text-[11px] text-red-600\">\r\n {{ attachment.error }}\r\n </p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"mt-2 flex flex-wrap items-center justify-between gap-2 border-t border-surface-200 px-1 pt-2\"\r\n >\r\n <div class=\"flex items-center gap-2 text-xs text-surface-500\">\r\n <span>Type @ to mention people</span>\r\n <span>&bull;</span>\r\n <span>{{ composerText().length }}/10000</span>\r\n @if (charactersLeft() < 0) {\r\n <span class=\"font-semibold text-red-600\">Too long</span>\r\n }\r\n </div>\r\n\r\n <div class=\"flex items-center gap-2\">\r\n @if (allowAttachments()) {\r\n <mt-button\r\n icon=\"file.paperclip\"\r\n label=\"Attach\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n [disabled]=\"disabled() || posting()\"\r\n (onClick)=\"browseAttachments()\"\r\n />\r\n }\r\n <mt-button\r\n icon=\"communication.send-01\"\r\n [label]=\"posting() ? 'Sending...' : 'Send'\"\r\n size=\"small\"\r\n [loading]=\"posting()\"\r\n [disabled]=\"!canSend()\"\r\n (onClick)=\"sendComment()\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </footer>\r\n </div>\r\n </div>\r\n</mt-card>\r\n\r\n<p-dialog\r\n [visible]=\"revisionsDialogVisible()\"\r\n (visibleChange)=\"revisionsDialogVisible.set($event)\"\r\n [modal]=\"true\"\r\n [dismissableMask]=\"true\"\r\n [draggable]=\"false\"\r\n [resizable]=\"false\"\r\n [style]=\"{ width: 'min(42rem, 92vw)' }\"\r\n header=\"Comment history\"\r\n>\r\n @if (revisionLoading()) {\r\n <div class=\"space-y-2\">\r\n @for (row of [1, 2, 3]; track row) {\r\n <div class=\"h-12 animate-pulse rounded-xl bg-surface-100\"></div>\r\n }\r\n </div>\r\n } @else if (visibleRevisions().length === 0) {\r\n <p class=\"text-sm text-surface-500\">No revision snapshots.</p>\r\n } @else {\r\n <div class=\"max-h-[55vh] space-y-2 overflow-y-auto pr-1\">\r\n @for (revision of visibleRevisions(); track revision.id) {\r\n <article class=\"rounded-xl border border-surface-200 p-3\">\r\n <div class=\"mb-1 text-xs text-surface-500\">\r\n Revision #{{ revision.revisionNumber }} &bull;\r\n {{ revision.createdAt | date: \"MMM d, y h:mm a\" }} &bull;\r\n {{ revision.createdBy }}\r\n </div>\r\n <div class=\"whitespace-pre-wrap break-words text-sm leading-6\">\r\n @for (\r\n segment of getCommentSegments({\r\n id: revision.id,\r\n moduleType: selectedRevisionComment()?.moduleType || \"\",\r\n recordId: selectedRevisionComment()?.recordId || 0,\r\n parentCommentId: null,\r\n comment: revision.comment,\r\n isSystem: false,\r\n createdAt: revision.createdAt,\r\n updatedAt: null,\r\n createdBy: revision.createdBy,\r\n updatedBy: null,\r\n attachments: [],\r\n mentions: revision.mentions,\r\n });\r\n track $index\r\n ) {\r\n <span\r\n [ngClass]=\"\r\n segment.isMention\r\n ? 'rounded-sm bg-primary-50 px-0.5 font-semibold text-primary-700'\r\n : ''\r\n \"\r\n >{{ segment.text }}</span\r\n >\r\n }\r\n </div>\r\n </article>\r\n }\r\n </div>\r\n }\r\n</p-dialog>\r\n", styles: [":host{display:block;height:100%;min-height:0}:host ::ng-deep .mt-discussion-card>div{display:flex;flex-direction:column;height:100%;min-height:0}:host ::ng-deep .mt-discussion-card>div>div.flex-1{display:flex;flex-direction:column;min-height:0;overflow:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i3.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: EntitiesPreview, selector: "mt-entities-preview", inputs: ["entities"] }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }, { kind: "pipe", type: i1.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1621
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: DiscussionThread, isStandalone: true, selector: "mt-discussion-thread", inputs: { moduleType: { classPropertyName: "moduleType", publicName: "moduleType", isSignal: true, isRequired: true, transformFunction: null }, recordId: { classPropertyName: "recordId", publicName: "recordId", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, subtitle: { classPropertyName: "subtitle", publicName: "subtitle", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, currentUserId: { classPropertyName: "currentUserId", publicName: "currentUserId", isSignal: true, isRequired: false, transformFunction: null }, requestContext: { classPropertyName: "requestContext", publicName: "requestContext", isSignal: true, isRequired: false, transformFunction: null }, mentionableUsers: { classPropertyName: "mentionableUsers", publicName: "mentionableUsers", isSignal: true, isRequired: false, transformFunction: null }, mentionSearchEndpoint: { classPropertyName: "mentionSearchEndpoint", publicName: "mentionSearchEndpoint", isSignal: true, isRequired: false, transformFunction: null }, mentionSearchParam: { classPropertyName: "mentionSearchParam", publicName: "mentionSearchParam", isSignal: true, isRequired: false, transformFunction: null }, mentionSearchDataPath: { classPropertyName: "mentionSearchDataPath", publicName: "mentionSearchDataPath", isSignal: true, isRequired: false, transformFunction: null }, allowAttachments: { classPropertyName: "allowAttachments", publicName: "allowAttachments", isSignal: true, isRequired: false, transformFunction: null }, uploadEndpoint: { classPropertyName: "uploadEndpoint", publicName: "uploadEndpoint", isSignal: true, isRequired: false, transformFunction: null }, attachmentDownloadEndpoint: { classPropertyName: "attachmentDownloadEndpoint", publicName: "attachmentDownloadEndpoint", isSignal: true, isRequired: false, transformFunction: null }, showParticipants: { classPropertyName: "showParticipants", publicName: "showParticipants", isSignal: true, isRequired: false, transformFunction: null }, autoMarkRead: { classPropertyName: "autoMarkRead", publicName: "autoMarkRead", isSignal: true, isRequired: false, transformFunction: null }, refreshIntervalMs: { classPropertyName: "refreshIntervalMs", publicName: "refreshIntervalMs", isSignal: true, isRequired: false, transformFunction: null }, styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loaded: "loaded", errored: "errored", commentCreated: "commentCreated", commentUpdated: "commentUpdated", commentDeleted: "commentDeleted", readStateChanged: "readStateChanged" }, host: { classAttribute: "block h-full min-h-0" }, viewQueries: [{ propertyName: "viewportRef", first: true, predicate: ["viewport"], descendants: true, isSignal: true }, { propertyName: "composerInputRef", first: true, predicate: ["composerInput"], descendants: true, isSignal: true }, { propertyName: "attachmentInputRef", first: true, predicate: ["attachmentInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<mt-card\r\n class=\"mt-discussion-card h-full min-h-0 w-full overflow-hidden shadow-sm\"\r\n [paddingless]=\"true\"\r\n [ngClass]=\"styleClass()\"\r\n>\r\n <div class=\"flex h-full min-h-0 flex-col overflow-hidden\">\r\n <input\r\n #attachmentInput\r\n type=\"file\"\r\n class=\"hidden\"\r\n multiple\r\n (change)=\"onAttachmentSelected($event)\"\r\n />\r\n\r\n <header\r\n class=\"flex items-center justify-between gap-3 border-b border-surface-200 bg-surface-0 px-4 py-3.5\"\r\n >\r\n <div class=\"min-w-0 flex-1 flex items-center gap-2\">\r\n <div class=\"text-2xl text-surface-500 font-semibold\">\r\n <mt-icon icon=\"communication.message-chat-square\"></mt-icon>\r\n </div>\r\n <h3 class=\"truncate text-base font-semibold text-surface-900\">\r\n {{ title() }}\r\n </h3>\r\n </div>\r\n\r\n <div class=\"flex items-center gap-2\">\r\n <mt-button\r\n icon=\"general.dots-vertical\"\r\n severity=\"secondary\"\r\n variant=\"text\"\r\n [rounded]=\"true\"\r\n styleClass=\"mt-discussion-icon-btn\"\r\n [loading]=\"refreshing()\"\r\n [disabled]=\"loadingInitial() || markingRead()\"\r\n (onClick)=\"actionsPopover.toggle($event)\"\r\n />\r\n\r\n <p-popover\r\n #actionsPopover\r\n appendTo=\"body\"\r\n styleClass=\"mt-discussion-actions-popover\"\r\n >\r\n <div class=\"flex min-w-44 flex-col py-1\">\r\n <button\r\n type=\"button\"\r\n class=\"flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2 text-left text-sm text-surface-700 transition-colors hover:bg-surface-100 disabled:cursor-not-allowed disabled:opacity-50\"\r\n [disabled]=\"refreshing() || loadingInitial()\"\r\n (click)=\"actionsPopover.hide(); refreshThread()\"\r\n >\r\n <mt-icon icon=\"arrow.refresh-cw-01\"></mt-icon>\r\n\r\n <span>{{ refreshing() ? \"Refreshing...\" : \"Refresh\" }}</span>\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2 text-left text-sm text-surface-700 transition-colors hover:bg-surface-100 disabled:cursor-not-allowed disabled:opacity-50\"\r\n [disabled]=\"markingRead() || !hasUnread()\"\r\n (click)=\"actionsPopover.hide(); markRead()\"\r\n >\r\n <mt-icon icon=\"general.check\"></mt-icon>\r\n\r\n <span>Mark read</span>\r\n </button>\r\n\r\n @if (showParticipants()) {\r\n <button\r\n type=\"button\"\r\n class=\"flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2 text-left text-sm text-surface-700 transition-colors hover:bg-surface-100\"\r\n (click)=\"actionsPopover.hide(); toggleParticipantsPanel()\"\r\n >\r\n <mt-icon icon=\"user.users-01\"></mt-icon>\r\n\r\n <span>{{\r\n participantsExpanded()\r\n ? \"Hide participants\"\r\n : \"Show participants\"\r\n }}</span>\r\n </button>\r\n }\r\n </div>\r\n </p-popover>\r\n </div>\r\n </header>\r\n\r\n @if (showParticipants() && participantsExpanded()) {\r\n <section class=\"border-b border-surface-200 px-4 py-3\">\r\n @if (participantsLoading()) {\r\n <span class=\"text-xs text-surface-500\">Loading participants...</span>\r\n } @else if (participantEntities().length === 0) {\r\n <span class=\"text-xs text-surface-500\">No participants yet.</span>\r\n } @else {\r\n <div class=\"max-h-48 overflow-y-auto pr-1\">\r\n <mt-entities-preview [entities]=\"participantEntities()\" />\r\n </div>\r\n }\r\n </section>\r\n }\r\n\r\n @if (errorMessage(); as error) {\r\n <div\r\n class=\"border-b border-red-200 bg-red-50 px-4 py-2 text-sm text-red-700\"\r\n >\r\n {{ error }}\r\n </div>\r\n }\r\n\r\n <div class=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\r\n <div\r\n #viewport\r\n class=\"min-h-0 flex-1 space-y-3 overflow-y-auto overscroll-contain bg-surface-50/60 px-3 py-3\"\r\n (scroll)=\"onViewportScroll()\"\r\n >\r\n @if (hasMore()) {\r\n <div class=\"flex justify-center py-1\">\r\n <mt-button\r\n icon=\"arrow.chevron-up\"\r\n [label]=\"loadingMore() ? 'Loading...' : 'Load older messages'\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n [loading]=\"loadingMore()\"\r\n (onClick)=\"loadOlder()\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (loadingInitial()) {\r\n <div class=\"space-y-2\">\r\n @for (item of [1, 2, 3, 4]; track item) {\r\n <div class=\"h-16 animate-pulse rounded-xl bg-surface-100\"></div>\r\n }\r\n </div>\r\n } @else if (commentsAsc().length === 0) {\r\n <div class=\"rounded-2xl p-8 text-center\">\r\n <h4 class=\"text-sm font-semibold text-surface-700\">\r\n No comments yet\r\n </h4>\r\n <p class=\"mt-1 text-xs text-surface-500\">Start the conversation.</p>\r\n </div>\r\n } @else {\r\n @for (comment of commentsAsc(); track trackComment($index, comment)) {\r\n @if (firstUnreadCommentId() === comment.id) {\r\n <div class=\"my-1 flex items-center justify-center gap-2\">\r\n <span\r\n class=\"flex-1 border-t border-dashed border-red-300\"\r\n ></span>\r\n <span\r\n class=\"rounded-full border border-red-200 bg-red-50 px-2 py-0.5 text-[0.67rem] font-bold leading-none text-red-700\"\r\n >Unread messages</span\r\n >\r\n <span\r\n class=\"flex-1 border-t border-dashed border-red-300\"\r\n ></span>\r\n </div>\r\n }\r\n\r\n <article\r\n class=\"group flex gap-2\"\r\n [class.justify-end]=\"isOwnComment(comment)\"\r\n >\r\n @if (!isOwnComment(comment)) {\r\n <div\r\n class=\"mt-0.5 inline-flex h-[1.9rem] w-[1.9rem] shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_20%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.74rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_75%,black)]\"\r\n >\r\n {{ getAvatarText(comment) }}\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"max-w-[90%] min-w-[30rem] rounded-[1.35rem] border border-surface-200 bg-white px-3 py-2.5 shadow-[0_8px_24px_color-mix(in_srgb,black_4%,transparent)]\"\r\n [class.bg-[color-mix(in_srgb,var(--p-primary-color)_7%,white)]]=\"\r\n isOwnComment(comment)\r\n \"\r\n >\r\n <div\r\n class=\"mb-1 flex flex-wrap items-center justify-between gap-2\"\r\n >\r\n <div\r\n class=\"text-xs w-full text-surface-600 flex justify-between\"\r\n >\r\n <div class=\"font-semibold text-surface-900\">\r\n {{ comment.createdBy }}\r\n </div>\r\n <div>\r\n <span>{{\r\n comment.createdAt | date: \"MMM d, y h:mm a\"\r\n }}</span>\r\n @if (comment.updatedAt) {\r\n <span class=\"ml-1 text-[11px] text-surface-500\"\r\n >(edited)</span\r\n >\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n @if (getParentComment(comment); as parentComment) {\r\n <button\r\n type=\"button\"\r\n class=\"mb-2 block w-full rounded-xl border border-surface-200 bg-surface-50 px-2 py-1 text-left text-xs text-surface-600\"\r\n (click)=\"openReply(parentComment)\"\r\n >\r\n <span class=\"font-semibold\">{{\r\n parentComment.createdBy\r\n }}</span>\r\n <span class=\"mx-1\">:</span>\r\n <span class=\"line-clamp-1\">{{\r\n parentComment.comment\r\n }}</span>\r\n </button>\r\n }\r\n\r\n @if (editingCommentId() === comment.id) {\r\n <div class=\"relative\">\r\n <textarea\r\n rows=\"3\"\r\n class=\"w-full min-h-[5.25rem] resize-y rounded-2xl border border-surface-300 bg-white px-3 py-2.5 text-[0.86rem] leading-[1.45] text-surface-900 outline-none focus-visible:outline-2 focus-visible:outline-[color-mix(in_srgb,var(--p-primary-color)_32%,transparent)] focus-visible:outline-offset-1\"\r\n [ngModel]=\"editText()\"\r\n (ngModelChange)=\"editText.set($event)\"\r\n (input)=\"onEditInput($event)\"\r\n (keyup)=\"onEditCaretEvent($event)\"\r\n (click)=\"onEditCaretEvent($event)\"\r\n (scroll)=\"onEditCaretEvent($event)\"\r\n (keydown)=\"onEditKeydown($event)\"\r\n ></textarea>\r\n\r\n @if (\r\n mentionSession()?.mode === \"edit\" &&\r\n mentionSession()?.editCommentId === comment.id\r\n ) {\r\n <div\r\n class=\"absolute top-0 left-0 z-20 min-w-56 overflow-auto rounded-xl border border-surface-300 bg-white shadow-[0_10px_40px_color-mix(in_srgb,black_14%,transparent)]\"\r\n [ngStyle]=\"mentionMenuStyle()\"\r\n [class.origin-bottom-left]=\"\r\n mentionMenuPosition()?.placement === 'above'\r\n \"\r\n >\r\n @if (mentionLoading()) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n Searching...\r\n </div>\r\n } @else if (mentionCandidates().length === 0) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n No matches\r\n </div>\r\n } @else {\r\n @for (\r\n candidate of mentionCandidates();\r\n track candidate.userId;\r\n let i = $index\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full cursor-pointer items-start gap-2 bg-transparent px-2.5 py-2 text-left text-[0.78rem] transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]\"\r\n [class.bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]]=\"\r\n mentionActiveIndex() === i\r\n \"\r\n (click)=\"selectMention(candidate)\"\r\n >\r\n <span\r\n class=\"mt-px inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_18%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.7rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)]\"\r\n >\r\n {{ getMentionAvatarText(candidate) }}\r\n </span>\r\n <span\r\n class=\"flex min-w-0 flex-1 flex-col gap-0.5\"\r\n >\r\n <span\r\n class=\"text-[0.79rem] leading-[1.25] font-semibold text-surface-900\"\r\n >{{\r\n candidate.displayName ||\r\n candidate.userName ||\r\n candidate.userId\r\n }}</span\r\n >\r\n <span\r\n class=\"inline-flex items-center text-[0.73rem] leading-[1.2] text-surface-500\"\r\n >\r\n @{{ candidate.userId }}\r\n </span>\r\n </span>\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"mt-2 flex flex-wrap items-center justify-between gap-2\"\r\n >\r\n <span class=\"text-xs text-surface-500\"\r\n >{{ editText().length }}/10000</span\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <button\r\n type=\"button\"\r\n class=\"rounded-[0.65rem] border border-surface-300 bg-transparent px-3 py-2 text-xs font-semibold leading-none text-surface-700 transition-colors hover:border-[color-mix(in_srgb,var(--p-primary-color)_24%,transparent)] hover:bg-[color-mix(in_srgb,var(--p-primary-color)_8%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"cancelEdit()\"\r\n >\r\n Cancel\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"rounded-[0.65rem] border border-[color-mix(in_srgb,var(--p-primary-color)_26%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_12%,white)] px-3 py-2 text-xs font-bold leading-none text-[color-mix(in_srgb,var(--p-primary-color)_76%,black)] transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_17%,white)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n [disabled]=\"!canSaveEdit()\"\r\n (click)=\"saveEdit()\"\r\n >\r\n {{ savingEdit() ? \"Saving...\" : \"Save\" }}\r\n </button>\r\n </div>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"whitespace-pre-wrap pt-1 break-words text-sm leading-6\"\r\n >\r\n @for (\r\n segment of getCommentSegments(comment);\r\n track $index\r\n ) {\r\n <span\r\n [ngClass]=\"\r\n segment.isMention\r\n ? 'rounded-sm bg-primary-50 px-0.5 font-semibold text-primary-700'\r\n : ''\r\n \"\r\n [attr.data-user-id]=\"segment.userId || null\"\r\n >\r\n {{ segment.text }}\r\n </span>\r\n }\r\n </div>\r\n\r\n @if (comment.attachments.length > 0) {\r\n <div class=\"mt-2 flex flex-wrap gap-2\">\r\n @for (\r\n attachment of comment.attachments;\r\n track attachment.id\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"inline-flex max-w-full items-center gap-1.5 rounded-lg border border-surface-300 px-2 py-1 text-[0.72rem] hover:bg-surface-50\"\r\n (click)=\"downloadAttachment(comment, attachment)\"\r\n >\r\n <span class=\"truncate\">{{\r\n attachment.fileName\r\n }}</span>\r\n <span class=\"text-[11px] text-surface-500\"\r\n >({{ attachment.size | number }} bytes)</span\r\n >\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"mt-2 flex flex-wrap items-center gap-1\">\r\n @if (!comment.isSystem) {\r\n <button\r\n type=\"button\"\r\n class=\"cursor-pointer rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"openReply(comment)\"\r\n >\r\n Reply\r\n </button>\r\n }\r\n @if (canEditComment(comment)) {\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"startEdit(comment)\"\r\n >\r\n Edit\r\n </button>\r\n }\r\n @if (canDeleteComment(comment)) {\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-red-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n [disabled]=\"isDeleting(comment.id)\"\r\n (click)=\"deleteComment(comment)\"\r\n >\r\n {{ isDeleting(comment.id) ? \"Deleting...\" : \"Delete\" }}\r\n </button>\r\n }\r\n @if (comment.updatedAt) {\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"openRevisions(comment)\"\r\n >\r\n History\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (isOwnComment(comment)) {\r\n <div\r\n class=\"mt-0.5 inline-flex h-[1.9rem] w-[1.9rem] shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_20%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.74rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_75%,black)]\"\r\n >\r\n {{ getAvatarText(comment) }}\r\n </div>\r\n }\r\n </article>\r\n }\r\n }\r\n </div>\r\n\r\n <footer\r\n class=\"z-10 shrink-0 border-t border-surface-200 bg-content px-3 py-3\"\r\n >\r\n @if (replyToComment(); as replyComment) {\r\n <div\r\n class=\"mb-2 flex items-center justify-between rounded-xl border border-surface-200 bg-surface-50 px-2 py-1\"\r\n >\r\n <div class=\"min-w-0 text-xs text-surface-600\">\r\n <span class=\"font-semibold\"\r\n >Replying to {{ replyComment.createdBy }}</span\r\n >\r\n <p class=\"truncate\">{{ replyComment.comment }}</p>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"clearReply()\"\r\n >\r\n Cancel\r\n </button>\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"rounded-[1.5rem] border border-surface-300 bg-white p-2.5 shadow-sm\"\r\n >\r\n <div class=\"relative\">\r\n <textarea\r\n #composerInput\r\n rows=\"2\"\r\n class=\"w-full min-h-[3.75rem] resize-none border-0 bg-transparent px-2 pb-10 pr-24 pt-1 text-[0.9rem] leading-[1.45] text-surface-900 outline-none\"\r\n [disabled]=\"disabled() || posting()\"\r\n [ngModel]=\"composerText()\"\r\n (ngModelChange)=\"composerText.set($event)\"\r\n (input)=\"onComposerInput($event)\"\r\n (keyup)=\"onComposerCaretEvent($event)\"\r\n (click)=\"onComposerCaretEvent($event)\"\r\n (scroll)=\"onComposerCaretEvent($event)\"\r\n (keydown)=\"onComposerKeydown($event)\"\r\n [placeholder]=\"placeholder()\"\r\n ></textarea>\r\n\r\n <div class=\"absolute right-1 bottom-1 flex items-center gap-2\">\r\n @if (allowAttachments()) {\r\n <mt-button\r\n icon=\"file.paperclip\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n variant=\"text\"\r\n [rounded]=\"true\"\r\n styleClass=\"mt-discussion-icon-btn\"\r\n [disabled]=\"disabled() || posting()\"\r\n (onClick)=\"browseAttachments()\"\r\n />\r\n }\r\n\r\n <mt-button\r\n icon=\"communication.send-01\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n styleClass=\"mt-discussion-send-btn\"\r\n [loading]=\"posting()\"\r\n [disabled]=\"!canSend()\"\r\n (onClick)=\"sendComment()\"\r\n />\r\n </div>\r\n\r\n @if (mentionSession()?.mode === \"composer\") {\r\n <div\r\n class=\"absolute top-0 left-0 z-30 min-w-56 overflow-auto rounded-xl border border-surface-300 bg-white shadow-[0_10px_40px_color-mix(in_srgb,black_14%,transparent)]\"\r\n [ngStyle]=\"mentionMenuStyle()\"\r\n [class.origin-bottom-left]=\"\r\n mentionMenuPosition()?.placement === 'above'\r\n \"\r\n >\r\n @if (mentionLoading()) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n Searching...\r\n </div>\r\n } @else if (mentionCandidates().length === 0) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n No matches\r\n </div>\r\n } @else {\r\n @for (\r\n candidate of mentionCandidates();\r\n track candidate.userId;\r\n let i = $index\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full cursor-pointer items-start gap-2 bg-transparent px-2.5 py-2 text-left text-[0.78rem] transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]\"\r\n [class.bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]]=\"\r\n mentionActiveIndex() === i\r\n \"\r\n (click)=\"selectMention(candidate)\"\r\n >\r\n <span\r\n class=\"mt-px inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_18%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.7rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)]\"\r\n >\r\n {{ getMentionAvatarText(candidate) }}\r\n </span>\r\n <span class=\"flex min-w-0 flex-1 flex-col gap-0.5\">\r\n <span\r\n class=\"text-[0.79rem] leading-[1.25] font-semibold text-surface-900\"\r\n >{{\r\n candidate.displayName ||\r\n candidate.userName ||\r\n candidate.userId\r\n }}</span\r\n >\r\n <span\r\n class=\"inline-flex items-center text-[0.73rem] leading-[1.2] text-surface-500\"\r\n >\r\n @{{ candidate.userId }}\r\n </span>\r\n </span>\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (composerAttachments().length > 0) {\r\n <div class=\"mt-2 flex flex-wrap gap-2 px-1\">\r\n @for (attachment of composerAttachments(); track attachment.id) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-2.5 py-1.5 text-xs\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"max-w-[12rem] truncate\">{{\r\n attachment.fileName\r\n }}</span>\r\n @if (attachment.status === \"uploading\") {\r\n <span class=\"text-surface-500\"\r\n >{{ attachment.progress }}%</span\r\n >\r\n } @else if (attachment.status === \"failed\") {\r\n <span class=\"text-red-600\">Failed</span>\r\n } @else {\r\n <span class=\"text-emerald-600\">Ready</span>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"removeAttachment(attachment.id)\"\r\n >\r\n Remove\r\n </button>\r\n </div>\r\n @if (attachment.error) {\r\n <p class=\"text-[11px] text-red-600\">\r\n {{ attachment.error }}\r\n </p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (composerText().length > 10000) {\r\n <div class=\"mt-2 px-1 text-xs font-medium text-red-600\">\r\n Comment cannot exceed 10000 characters.\r\n </div>\r\n }\r\n </div>\r\n </footer>\r\n </div>\r\n </div>\r\n</mt-card>\r\n\r\n<p-dialog\r\n [visible]=\"revisionsDialogVisible()\"\r\n (visibleChange)=\"revisionsDialogVisible.set($event)\"\r\n [modal]=\"true\"\r\n [dismissableMask]=\"true\"\r\n [draggable]=\"false\"\r\n [resizable]=\"false\"\r\n [style]=\"{ width: 'min(42rem, 92vw)' }\"\r\n header=\"Comment history\"\r\n>\r\n @if (revisionLoading()) {\r\n <div class=\"space-y-2\">\r\n @for (row of [1, 2, 3]; track row) {\r\n <div class=\"h-12 animate-pulse rounded-xl bg-surface-100\"></div>\r\n }\r\n </div>\r\n } @else if (visibleRevisions().length === 0) {\r\n <p class=\"text-sm text-surface-500\">No revision snapshots.</p>\r\n } @else {\r\n <div class=\"max-h-[55vh] space-y-2 overflow-y-auto pr-1\">\r\n @for (revision of visibleRevisions(); track revision.id) {\r\n <article class=\"rounded-xl border border-surface-200 p-3\">\r\n <div class=\"mb-1 text-xs text-surface-500\">\r\n Revision #{{ revision.revisionNumber }} &bull;\r\n {{ revision.createdAt | date: \"MMM d, y h:mm a\" }} &bull;\r\n {{ revision.createdBy }}\r\n </div>\r\n <div class=\"whitespace-pre-wrap break-words text-sm leading-6\">\r\n @for (\r\n segment of getCommentSegments({\r\n id: revision.id,\r\n moduleType: selectedRevisionComment()?.moduleType || \"\",\r\n recordId: selectedRevisionComment()?.recordId || 0,\r\n parentCommentId: null,\r\n comment: revision.comment,\r\n isSystem: false,\r\n createdAt: revision.createdAt,\r\n updatedAt: null,\r\n createdBy: revision.createdBy,\r\n updatedBy: null,\r\n attachments: [],\r\n mentions: revision.mentions,\r\n });\r\n track $index\r\n ) {\r\n <span\r\n [ngClass]=\"\r\n segment.isMention\r\n ? 'rounded-sm bg-primary-50 px-0.5 font-semibold text-primary-700'\r\n : ''\r\n \"\r\n >{{ segment.text }}</span\r\n >\r\n }\r\n </div>\r\n </article>\r\n }\r\n </div>\r\n }\r\n</p-dialog>\r\n", styles: [":host{display:block;height:100%;min-height:0}:host ::ng-deep .mt-discussion-card>div{display:flex;flex-direction:column;height:100%;min-height:0}:host ::ng-deep .mt-discussion-card>div>div.flex-1{display:flex;flex-direction:column;min-height:0;overflow:hidden}:host ::ng-deep .mt-discussion-actions-popover .p-popover-content{padding:.25rem}:host ::ng-deep .mt-discussion-icon-btn,:host ::ng-deep .mt-discussion-send-btn{height:2.25rem;width:2.25rem;min-width:2.25rem}:host ::ng-deep .mt-discussion-send-btn{box-shadow:0 10px 24px color-mix(in srgb,var(--p-primary-color) 22%,transparent)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i3.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i4.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: EntitiesPreview, selector: "mt-entities-preview", inputs: ["entities"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }, { kind: "pipe", type: i1.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1637
1622
  }
1638
1623
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DiscussionThread, decorators: [{
1639
1624
  type: Component,
@@ -1642,12 +1627,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
1642
1627
  FormsModule,
1643
1628
  DatePipe,
1644
1629
  DialogModule,
1630
+ PopoverModule,
1645
1631
  Button,
1646
1632
  Card,
1647
1633
  EntitiesPreview,
1634
+ Icon,
1648
1635
  ], changeDetection: ChangeDetectionStrategy.OnPush, host: {
1649
1636
  class: 'block h-full min-h-0',
1650
- }, template: "<mt-card\r\n class=\"mt-discussion-card h-full min-h-0 w-full overflow-hidden shadow-sm\"\r\n [paddingless]=\"true\"\r\n [ngClass]=\"styleClass()\"\r\n>\r\n <div class=\"flex h-full min-h-0 flex-col overflow-hidden\">\r\n <input\r\n #attachmentInput\r\n type=\"file\"\r\n class=\"hidden\"\r\n multiple\r\n (change)=\"onAttachmentSelected($event)\"\r\n />\r\n\r\n <header\r\n class=\"flex flex-wrap items-start justify-between gap-3 border-b border-surface-200 px-4 py-3\"\r\n >\r\n <div class=\"min-w-0\">\r\n <h3 class=\"truncate text-sm font-semibold uppercase tracking-[0.08em]\">\r\n {{ title() }}\r\n </h3>\r\n @if (subtitle()) {\r\n <p class=\"mt-1 text-xs text-surface-500\">{{ subtitle() }}</p>\r\n }\r\n <p class=\"mt-1 text-xs text-surface-500\">\r\n {{ threadKey() || \"Discussion\" }}\r\n </p>\r\n </div>\r\n\r\n <div class=\"flex flex-wrap items-center gap-2\">\r\n @if (unreadCount() > 0) {\r\n <span\r\n class=\"inline-flex items-center rounded-full bg-red-100 px-2 py-0.5 text-xs font-semibold text-red-700\"\r\n >\r\n {{ unreadCount() }} unread\r\n </span>\r\n } @else {\r\n <span\r\n class=\"inline-flex items-center rounded-full bg-emerald-100 px-2 py-0.5 text-xs font-semibold text-emerald-700\"\r\n >\r\n Up to date\r\n </span>\r\n }\r\n\r\n <mt-button\r\n icon=\"arrow.refresh-cw-01\"\r\n [label]=\"refreshing() ? 'Refreshing...' : 'Refresh'\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n [loading]=\"refreshing()\"\r\n [disabled]=\"loadingInitial()\"\r\n (onClick)=\"refreshThread()\"\r\n />\r\n <mt-button\r\n icon=\"general.check\"\r\n label=\"Mark read\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n [disabled]=\"markingRead() || !hasUnread()\"\r\n (onClick)=\"markRead()\"\r\n />\r\n <mt-button\r\n icon=\"communication.mail-01\"\r\n label=\"Mark unread\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n [disabled]=\"markingRead()\"\r\n (onClick)=\"markUnread()\"\r\n />\r\n @if (showParticipants()) {\r\n <mt-button\r\n icon=\"user.users-01\"\r\n [label]=\"'Participants (' + participants().length + ')'\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n (onClick)=\"toggleParticipantsPanel()\"\r\n />\r\n }\r\n </div>\r\n </header>\r\n\r\n @if (showParticipants() && participantsExpanded()) {\r\n <section class=\"border-b border-surface-200 px-4 py-3\">\r\n @if (participantsLoading()) {\r\n <span class=\"text-xs text-surface-500\">Loading participants...</span>\r\n } @else if (participantEntities().length === 0) {\r\n <span class=\"text-xs text-surface-500\">No participants yet.</span>\r\n } @else {\r\n <div class=\"max-h-48 overflow-y-auto pr-1\">\r\n <mt-entities-preview [entities]=\"participantEntities()\" />\r\n </div>\r\n }\r\n </section>\r\n }\r\n\r\n @if (errorMessage(); as error) {\r\n <div\r\n class=\"border-b border-red-200 bg-red-50 px-4 py-2 text-sm text-red-700\"\r\n >\r\n {{ error }}\r\n </div>\r\n }\r\n\r\n <div class=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\r\n <div\r\n #viewport\r\n class=\"min-h-0 flex-1 space-y-3 overflow-y-auto overscroll-contain px-3 py-3\"\r\n (scroll)=\"onViewportScroll()\"\r\n >\r\n @if (hasMore()) {\r\n <div class=\"flex justify-center py-1\">\r\n <mt-button\r\n icon=\"arrow.chevron-up\"\r\n [label]=\"loadingMore() ? 'Loading...' : 'Load older messages'\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n [loading]=\"loadingMore()\"\r\n (onClick)=\"loadOlder()\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (loadingInitial()) {\r\n <div class=\"space-y-2\">\r\n @for (item of [1, 2, 3, 4]; track item) {\r\n <div class=\"h-16 animate-pulse rounded-xl bg-surface-100\"></div>\r\n }\r\n </div>\r\n } @else if (commentsAsc().length === 0) {\r\n <div\r\n class=\"rounded-2xl border border-dashed border-surface-300 p-8 text-center\"\r\n >\r\n <h4 class=\"text-sm font-semibold text-surface-700\">\r\n No comments yet\r\n </h4>\r\n <p class=\"mt-1 text-xs text-surface-500\">Start the conversation.</p>\r\n </div>\r\n } @else {\r\n @for (comment of commentsAsc(); track trackComment($index, comment)) {\r\n @if (firstUnreadCommentId() === comment.id) {\r\n <div class=\"my-1 flex items-center justify-center gap-2\">\r\n <span\r\n class=\"flex-1 border-t border-dashed border-red-300\"\r\n ></span>\r\n <span\r\n class=\"rounded-full border border-red-200 bg-red-50 px-2 py-0.5 text-[0.67rem] font-bold leading-none text-red-700\"\r\n >Unread messages</span\r\n >\r\n <span\r\n class=\"flex-1 border-t border-dashed border-red-300\"\r\n ></span>\r\n </div>\r\n }\r\n\r\n <article\r\n class=\"group flex gap-2\"\r\n [class.justify-end]=\"isOwnComment(comment)\"\r\n >\r\n @if (!isOwnComment(comment)) {\r\n <div\r\n class=\"mt-0.5 inline-flex h-[1.9rem] w-[1.9rem] shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_20%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.74rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_75%,black)]\"\r\n >\r\n {{ getAvatarText(comment) }}\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"max-w-[88%] min-w-[16rem] rounded-2xl border border-surface-200 px-3 py-2\"\r\n [class.bg-[color-mix(in_srgb,var(--p-primary-color)_7%,white)]]=\"\r\n isOwnComment(comment)\r\n \"\r\n >\r\n <div\r\n class=\"mb-1 flex flex-wrap items-center justify-between gap-2\"\r\n >\r\n <div class=\"text-xs text-surface-600\">\r\n <span class=\"font-semibold text-surface-900\">{{\r\n comment.createdBy\r\n }}</span>\r\n <span class=\"mx-1\">&bull;</span>\r\n <span>{{\r\n comment.createdAt | date: \"MMM d, y h:mm a\"\r\n }}</span>\r\n @if (comment.updatedAt) {\r\n <span class=\"ml-1 text-[11px] text-surface-500\"\r\n >(edited)</span\r\n >\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (getParentComment(comment); as parentComment) {\r\n <button\r\n type=\"button\"\r\n class=\"mb-2 block w-full rounded-xl border border-surface-200 bg-surface-50 px-2 py-1 text-left text-xs text-surface-600\"\r\n (click)=\"openReply(parentComment)\"\r\n >\r\n <span class=\"font-semibold\">{{\r\n parentComment.createdBy\r\n }}</span>\r\n <span class=\"mx-1\">:</span>\r\n <span class=\"line-clamp-1\">{{\r\n parentComment.comment\r\n }}</span>\r\n </button>\r\n }\r\n\r\n @if (editingCommentId() === comment.id) {\r\n <div class=\"relative\">\r\n <textarea\r\n rows=\"3\"\r\n class=\"w-full min-h-[5.25rem] resize-y rounded-2xl border border-surface-300 bg-white px-3 py-2.5 text-[0.86rem] leading-[1.45] text-surface-900 outline-none focus-visible:outline-2 focus-visible:outline-[color-mix(in_srgb,var(--p-primary-color)_32%,transparent)] focus-visible:outline-offset-1\"\r\n [ngModel]=\"editText()\"\r\n (ngModelChange)=\"editText.set($event)\"\r\n (input)=\"onEditInput($event)\"\r\n (keyup)=\"onEditCaretEvent($event)\"\r\n (click)=\"onEditCaretEvent($event)\"\r\n (scroll)=\"onEditCaretEvent($event)\"\r\n (keydown)=\"onEditKeydown($event)\"\r\n ></textarea>\r\n\r\n @if (\r\n mentionSession()?.mode === \"edit\" &&\r\n mentionSession()?.editCommentId === comment.id\r\n ) {\r\n <div\r\n class=\"absolute top-0 left-0 z-20 min-w-56 overflow-auto rounded-xl border border-surface-300 bg-white shadow-[0_10px_40px_color-mix(in_srgb,black_14%,transparent)]\"\r\n [ngStyle]=\"mentionMenuStyle()\"\r\n [class.origin-bottom-left]=\"\r\n mentionMenuPosition()?.placement === 'above'\r\n \"\r\n >\r\n @if (mentionLoading()) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n Searching...\r\n </div>\r\n } @else if (mentionCandidates().length === 0) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n No matches\r\n </div>\r\n } @else {\r\n @for (\r\n candidate of mentionCandidates();\r\n track candidate.userId;\r\n let i = $index\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full cursor-pointer items-start gap-2 bg-transparent px-2.5 py-2 text-left text-[0.78rem] transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]\"\r\n [class.bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]]=\"\r\n mentionActiveIndex() === i\r\n \"\r\n (click)=\"selectMention(candidate)\"\r\n >\r\n <span\r\n class=\"mt-px inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_18%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.7rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)]\"\r\n >\r\n {{ getMentionAvatarText(candidate) }}\r\n </span>\r\n <span\r\n class=\"flex min-w-0 flex-1 flex-col gap-0.5\"\r\n >\r\n <span\r\n class=\"text-[0.79rem] leading-[1.25] font-semibold text-surface-900\"\r\n >{{\r\n candidate.displayName ||\r\n candidate.userName ||\r\n candidate.userId\r\n }}</span\r\n >\r\n <span\r\n class=\"inline-flex items-center text-[0.73rem] leading-[1.2] text-surface-500\"\r\n >\r\n @{{ candidate.userId }}\r\n </span>\r\n </span>\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"mt-2 flex flex-wrap items-center justify-between gap-2\"\r\n >\r\n <span class=\"text-xs text-surface-500\"\r\n >{{ editText().length }}/10000</span\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <button\r\n type=\"button\"\r\n class=\"rounded-[0.65rem] border border-surface-300 bg-transparent px-3 py-2 text-xs font-semibold leading-none text-surface-700 transition-colors hover:border-[color-mix(in_srgb,var(--p-primary-color)_24%,transparent)] hover:bg-[color-mix(in_srgb,var(--p-primary-color)_8%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"cancelEdit()\"\r\n >\r\n Cancel\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"rounded-[0.65rem] border border-[color-mix(in_srgb,var(--p-primary-color)_26%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_12%,white)] px-3 py-2 text-xs font-bold leading-none text-[color-mix(in_srgb,var(--p-primary-color)_76%,black)] transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_17%,white)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n [disabled]=\"!canSaveEdit()\"\r\n (click)=\"saveEdit()\"\r\n >\r\n {{ savingEdit() ? \"Saving...\" : \"Save\" }}\r\n </button>\r\n </div>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"whitespace-pre-wrap break-words text-sm leading-6\"\r\n >\r\n @for (\r\n segment of getCommentSegments(comment);\r\n track $index\r\n ) {\r\n <span\r\n [ngClass]=\"\r\n segment.isMention\r\n ? 'rounded-sm bg-primary-50 px-0.5 font-semibold text-primary-700'\r\n : ''\r\n \"\r\n [attr.data-user-id]=\"segment.userId || null\"\r\n >\r\n {{ segment.text }}\r\n </span>\r\n }\r\n </div>\r\n\r\n @if (comment.attachments.length > 0) {\r\n <div class=\"mt-2 flex flex-wrap gap-2\">\r\n @for (\r\n attachment of comment.attachments;\r\n track attachment.id\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"inline-flex max-w-full items-center gap-1.5 rounded-lg border border-surface-300 px-2 py-1 text-[0.72rem] hover:bg-surface-50\"\r\n (click)=\"downloadAttachment(comment, attachment)\"\r\n >\r\n <span class=\"truncate\">{{\r\n attachment.fileName\r\n }}</span>\r\n <span class=\"text-[11px] text-surface-500\"\r\n >({{ attachment.size | number }} bytes)</span\r\n >\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"mt-2 flex flex-wrap items-center gap-1 opacity-100 md:opacity-0 md:group-hover:opacity-100\"\r\n >\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"openReply(comment)\"\r\n >\r\n Reply\r\n </button>\r\n @if (canEditComment(comment)) {\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"startEdit(comment)\"\r\n >\r\n Edit\r\n </button>\r\n }\r\n @if (canDeleteComment(comment)) {\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-red-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n [disabled]=\"isDeleting(comment.id)\"\r\n (click)=\"deleteComment(comment)\"\r\n >\r\n {{ isDeleting(comment.id) ? \"Deleting...\" : \"Delete\" }}\r\n </button>\r\n }\r\n @if (comment.updatedAt) {\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"openRevisions(comment)\"\r\n >\r\n History\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (isOwnComment(comment)) {\r\n <div\r\n class=\"mt-0.5 inline-flex h-[1.9rem] w-[1.9rem] shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_20%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.74rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_75%,black)]\"\r\n >\r\n {{ getAvatarText(comment) }}\r\n </div>\r\n }\r\n </article>\r\n }\r\n }\r\n </div>\r\n\r\n <footer\r\n class=\"z-10 shrink-0 border-t border-surface-200 bg-content px-3 py-3\"\r\n >\r\n @if (replyToComment(); as replyComment) {\r\n <div\r\n class=\"mb-2 flex items-center justify-between rounded-xl border border-surface-200 bg-surface-50 px-2 py-1\"\r\n >\r\n <div class=\"min-w-0 text-xs text-surface-600\">\r\n <span class=\"font-semibold\"\r\n >Replying to {{ replyComment.createdBy }}</span\r\n >\r\n <p class=\"truncate\">{{ replyComment.comment }}</p>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"clearReply()\"\r\n >\r\n Cancel\r\n </button>\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"rounded-2xl border border-surface-300 bg-white p-2 shadow-sm\"\r\n >\r\n <div class=\"relative\">\r\n <textarea\r\n #composerInput\r\n rows=\"3\"\r\n class=\"w-full min-h-[5.5rem] resize-y border-0 bg-transparent px-2 py-1 text-[0.9rem] leading-[1.45] text-surface-900 outline-none\"\r\n [disabled]=\"disabled() || posting()\"\r\n [ngModel]=\"composerText()\"\r\n (ngModelChange)=\"composerText.set($event)\"\r\n (input)=\"onComposerInput($event)\"\r\n (keyup)=\"onComposerCaretEvent($event)\"\r\n (click)=\"onComposerCaretEvent($event)\"\r\n (scroll)=\"onComposerCaretEvent($event)\"\r\n (keydown)=\"onComposerKeydown($event)\"\r\n [placeholder]=\"placeholder()\"\r\n ></textarea>\r\n\r\n @if (mentionSession()?.mode === \"composer\") {\r\n <div\r\n class=\"absolute top-0 left-0 z-30 min-w-56 overflow-auto rounded-xl border border-surface-300 bg-white shadow-[0_10px_40px_color-mix(in_srgb,black_14%,transparent)]\"\r\n [ngStyle]=\"mentionMenuStyle()\"\r\n [class.origin-bottom-left]=\"\r\n mentionMenuPosition()?.placement === 'above'\r\n \"\r\n >\r\n @if (mentionLoading()) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n Searching...\r\n </div>\r\n } @else if (mentionCandidates().length === 0) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n No matches\r\n </div>\r\n } @else {\r\n @for (\r\n candidate of mentionCandidates();\r\n track candidate.userId;\r\n let i = $index\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full cursor-pointer items-start gap-2 bg-transparent px-2.5 py-2 text-left text-[0.78rem] transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]\"\r\n [class.bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]]=\"\r\n mentionActiveIndex() === i\r\n \"\r\n (click)=\"selectMention(candidate)\"\r\n >\r\n <span\r\n class=\"mt-px inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_18%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.7rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)]\"\r\n >\r\n {{ getMentionAvatarText(candidate) }}\r\n </span>\r\n <span class=\"flex min-w-0 flex-1 flex-col gap-0.5\">\r\n <span\r\n class=\"text-[0.79rem] leading-[1.25] font-semibold text-surface-900\"\r\n >{{\r\n candidate.displayName ||\r\n candidate.userName ||\r\n candidate.userId\r\n }}</span\r\n >\r\n <span\r\n class=\"inline-flex items-center text-[0.73rem] leading-[1.2] text-surface-500\"\r\n >\r\n @{{ candidate.userId }}\r\n </span>\r\n </span>\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (composerAttachments().length > 0) {\r\n <div class=\"mt-2 flex flex-wrap gap-2 px-1\">\r\n @for (attachment of composerAttachments(); track attachment.id) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-2 py-1 text-xs\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"max-w-[12rem] truncate\">{{\r\n attachment.fileName\r\n }}</span>\r\n @if (attachment.status === \"uploading\") {\r\n <span class=\"text-surface-500\"\r\n >{{ attachment.progress }}%</span\r\n >\r\n } @else if (attachment.status === \"failed\") {\r\n <span class=\"text-red-600\">Failed</span>\r\n } @else {\r\n <span class=\"text-emerald-600\">Ready</span>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"removeAttachment(attachment.id)\"\r\n >\r\n Remove\r\n </button>\r\n </div>\r\n @if (attachment.error) {\r\n <p class=\"text-[11px] text-red-600\">\r\n {{ attachment.error }}\r\n </p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"mt-2 flex flex-wrap items-center justify-between gap-2 border-t border-surface-200 px-1 pt-2\"\r\n >\r\n <div class=\"flex items-center gap-2 text-xs text-surface-500\">\r\n <span>Type @ to mention people</span>\r\n <span>&bull;</span>\r\n <span>{{ composerText().length }}/10000</span>\r\n @if (charactersLeft() < 0) {\r\n <span class=\"font-semibold text-red-600\">Too long</span>\r\n }\r\n </div>\r\n\r\n <div class=\"flex items-center gap-2\">\r\n @if (allowAttachments()) {\r\n <mt-button\r\n icon=\"file.paperclip\"\r\n label=\"Attach\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n [disabled]=\"disabled() || posting()\"\r\n (onClick)=\"browseAttachments()\"\r\n />\r\n }\r\n <mt-button\r\n icon=\"communication.send-01\"\r\n [label]=\"posting() ? 'Sending...' : 'Send'\"\r\n size=\"small\"\r\n [loading]=\"posting()\"\r\n [disabled]=\"!canSend()\"\r\n (onClick)=\"sendComment()\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n </footer>\r\n </div>\r\n </div>\r\n</mt-card>\r\n\r\n<p-dialog\r\n [visible]=\"revisionsDialogVisible()\"\r\n (visibleChange)=\"revisionsDialogVisible.set($event)\"\r\n [modal]=\"true\"\r\n [dismissableMask]=\"true\"\r\n [draggable]=\"false\"\r\n [resizable]=\"false\"\r\n [style]=\"{ width: 'min(42rem, 92vw)' }\"\r\n header=\"Comment history\"\r\n>\r\n @if (revisionLoading()) {\r\n <div class=\"space-y-2\">\r\n @for (row of [1, 2, 3]; track row) {\r\n <div class=\"h-12 animate-pulse rounded-xl bg-surface-100\"></div>\r\n }\r\n </div>\r\n } @else if (visibleRevisions().length === 0) {\r\n <p class=\"text-sm text-surface-500\">No revision snapshots.</p>\r\n } @else {\r\n <div class=\"max-h-[55vh] space-y-2 overflow-y-auto pr-1\">\r\n @for (revision of visibleRevisions(); track revision.id) {\r\n <article class=\"rounded-xl border border-surface-200 p-3\">\r\n <div class=\"mb-1 text-xs text-surface-500\">\r\n Revision #{{ revision.revisionNumber }} &bull;\r\n {{ revision.createdAt | date: \"MMM d, y h:mm a\" }} &bull;\r\n {{ revision.createdBy }}\r\n </div>\r\n <div class=\"whitespace-pre-wrap break-words text-sm leading-6\">\r\n @for (\r\n segment of getCommentSegments({\r\n id: revision.id,\r\n moduleType: selectedRevisionComment()?.moduleType || \"\",\r\n recordId: selectedRevisionComment()?.recordId || 0,\r\n parentCommentId: null,\r\n comment: revision.comment,\r\n isSystem: false,\r\n createdAt: revision.createdAt,\r\n updatedAt: null,\r\n createdBy: revision.createdBy,\r\n updatedBy: null,\r\n attachments: [],\r\n mentions: revision.mentions,\r\n });\r\n track $index\r\n ) {\r\n <span\r\n [ngClass]=\"\r\n segment.isMention\r\n ? 'rounded-sm bg-primary-50 px-0.5 font-semibold text-primary-700'\r\n : ''\r\n \"\r\n >{{ segment.text }}</span\r\n >\r\n }\r\n </div>\r\n </article>\r\n }\r\n </div>\r\n }\r\n</p-dialog>\r\n", styles: [":host{display:block;height:100%;min-height:0}:host ::ng-deep .mt-discussion-card>div{display:flex;flex-direction:column;height:100%;min-height:0}:host ::ng-deep .mt-discussion-card>div>div.flex-1{display:flex;flex-direction:column;min-height:0;overflow:hidden}\n"] }]
1637
+ }, template: "<mt-card\r\n class=\"mt-discussion-card h-full min-h-0 w-full overflow-hidden shadow-sm\"\r\n [paddingless]=\"true\"\r\n [ngClass]=\"styleClass()\"\r\n>\r\n <div class=\"flex h-full min-h-0 flex-col overflow-hidden\">\r\n <input\r\n #attachmentInput\r\n type=\"file\"\r\n class=\"hidden\"\r\n multiple\r\n (change)=\"onAttachmentSelected($event)\"\r\n />\r\n\r\n <header\r\n class=\"flex items-center justify-between gap-3 border-b border-surface-200 bg-surface-0 px-4 py-3.5\"\r\n >\r\n <div class=\"min-w-0 flex-1 flex items-center gap-2\">\r\n <div class=\"text-2xl text-surface-500 font-semibold\">\r\n <mt-icon icon=\"communication.message-chat-square\"></mt-icon>\r\n </div>\r\n <h3 class=\"truncate text-base font-semibold text-surface-900\">\r\n {{ title() }}\r\n </h3>\r\n </div>\r\n\r\n <div class=\"flex items-center gap-2\">\r\n <mt-button\r\n icon=\"general.dots-vertical\"\r\n severity=\"secondary\"\r\n variant=\"text\"\r\n [rounded]=\"true\"\r\n styleClass=\"mt-discussion-icon-btn\"\r\n [loading]=\"refreshing()\"\r\n [disabled]=\"loadingInitial() || markingRead()\"\r\n (onClick)=\"actionsPopover.toggle($event)\"\r\n />\r\n\r\n <p-popover\r\n #actionsPopover\r\n appendTo=\"body\"\r\n styleClass=\"mt-discussion-actions-popover\"\r\n >\r\n <div class=\"flex min-w-44 flex-col py-1\">\r\n <button\r\n type=\"button\"\r\n class=\"flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2 text-left text-sm text-surface-700 transition-colors hover:bg-surface-100 disabled:cursor-not-allowed disabled:opacity-50\"\r\n [disabled]=\"refreshing() || loadingInitial()\"\r\n (click)=\"actionsPopover.hide(); refreshThread()\"\r\n >\r\n <mt-icon icon=\"arrow.refresh-cw-01\"></mt-icon>\r\n\r\n <span>{{ refreshing() ? \"Refreshing...\" : \"Refresh\" }}</span>\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2 text-left text-sm text-surface-700 transition-colors hover:bg-surface-100 disabled:cursor-not-allowed disabled:opacity-50\"\r\n [disabled]=\"markingRead() || !hasUnread()\"\r\n (click)=\"actionsPopover.hide(); markRead()\"\r\n >\r\n <mt-icon icon=\"general.check\"></mt-icon>\r\n\r\n <span>Mark read</span>\r\n </button>\r\n\r\n @if (showParticipants()) {\r\n <button\r\n type=\"button\"\r\n class=\"flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2 text-left text-sm text-surface-700 transition-colors hover:bg-surface-100\"\r\n (click)=\"actionsPopover.hide(); toggleParticipantsPanel()\"\r\n >\r\n <mt-icon icon=\"user.users-01\"></mt-icon>\r\n\r\n <span>{{\r\n participantsExpanded()\r\n ? \"Hide participants\"\r\n : \"Show participants\"\r\n }}</span>\r\n </button>\r\n }\r\n </div>\r\n </p-popover>\r\n </div>\r\n </header>\r\n\r\n @if (showParticipants() && participantsExpanded()) {\r\n <section class=\"border-b border-surface-200 px-4 py-3\">\r\n @if (participantsLoading()) {\r\n <span class=\"text-xs text-surface-500\">Loading participants...</span>\r\n } @else if (participantEntities().length === 0) {\r\n <span class=\"text-xs text-surface-500\">No participants yet.</span>\r\n } @else {\r\n <div class=\"max-h-48 overflow-y-auto pr-1\">\r\n <mt-entities-preview [entities]=\"participantEntities()\" />\r\n </div>\r\n }\r\n </section>\r\n }\r\n\r\n @if (errorMessage(); as error) {\r\n <div\r\n class=\"border-b border-red-200 bg-red-50 px-4 py-2 text-sm text-red-700\"\r\n >\r\n {{ error }}\r\n </div>\r\n }\r\n\r\n <div class=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\r\n <div\r\n #viewport\r\n class=\"min-h-0 flex-1 space-y-3 overflow-y-auto overscroll-contain bg-surface-50/60 px-3 py-3\"\r\n (scroll)=\"onViewportScroll()\"\r\n >\r\n @if (hasMore()) {\r\n <div class=\"flex justify-center py-1\">\r\n <mt-button\r\n icon=\"arrow.chevron-up\"\r\n [label]=\"loadingMore() ? 'Loading...' : 'Load older messages'\"\r\n size=\"small\"\r\n [outlined]=\"true\"\r\n [loading]=\"loadingMore()\"\r\n (onClick)=\"loadOlder()\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (loadingInitial()) {\r\n <div class=\"space-y-2\">\r\n @for (item of [1, 2, 3, 4]; track item) {\r\n <div class=\"h-16 animate-pulse rounded-xl bg-surface-100\"></div>\r\n }\r\n </div>\r\n } @else if (commentsAsc().length === 0) {\r\n <div class=\"rounded-2xl p-8 text-center\">\r\n <h4 class=\"text-sm font-semibold text-surface-700\">\r\n No comments yet\r\n </h4>\r\n <p class=\"mt-1 text-xs text-surface-500\">Start the conversation.</p>\r\n </div>\r\n } @else {\r\n @for (comment of commentsAsc(); track trackComment($index, comment)) {\r\n @if (firstUnreadCommentId() === comment.id) {\r\n <div class=\"my-1 flex items-center justify-center gap-2\">\r\n <span\r\n class=\"flex-1 border-t border-dashed border-red-300\"\r\n ></span>\r\n <span\r\n class=\"rounded-full border border-red-200 bg-red-50 px-2 py-0.5 text-[0.67rem] font-bold leading-none text-red-700\"\r\n >Unread messages</span\r\n >\r\n <span\r\n class=\"flex-1 border-t border-dashed border-red-300\"\r\n ></span>\r\n </div>\r\n }\r\n\r\n <article\r\n class=\"group flex gap-2\"\r\n [class.justify-end]=\"isOwnComment(comment)\"\r\n >\r\n @if (!isOwnComment(comment)) {\r\n <div\r\n class=\"mt-0.5 inline-flex h-[1.9rem] w-[1.9rem] shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_20%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.74rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_75%,black)]\"\r\n >\r\n {{ getAvatarText(comment) }}\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"max-w-[90%] min-w-[30rem] rounded-[1.35rem] border border-surface-200 bg-white px-3 py-2.5 shadow-[0_8px_24px_color-mix(in_srgb,black_4%,transparent)]\"\r\n [class.bg-[color-mix(in_srgb,var(--p-primary-color)_7%,white)]]=\"\r\n isOwnComment(comment)\r\n \"\r\n >\r\n <div\r\n class=\"mb-1 flex flex-wrap items-center justify-between gap-2\"\r\n >\r\n <div\r\n class=\"text-xs w-full text-surface-600 flex justify-between\"\r\n >\r\n <div class=\"font-semibold text-surface-900\">\r\n {{ comment.createdBy }}\r\n </div>\r\n <div>\r\n <span>{{\r\n comment.createdAt | date: \"MMM d, y h:mm a\"\r\n }}</span>\r\n @if (comment.updatedAt) {\r\n <span class=\"ml-1 text-[11px] text-surface-500\"\r\n >(edited)</span\r\n >\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n @if (getParentComment(comment); as parentComment) {\r\n <button\r\n type=\"button\"\r\n class=\"mb-2 block w-full rounded-xl border border-surface-200 bg-surface-50 px-2 py-1 text-left text-xs text-surface-600\"\r\n (click)=\"openReply(parentComment)\"\r\n >\r\n <span class=\"font-semibold\">{{\r\n parentComment.createdBy\r\n }}</span>\r\n <span class=\"mx-1\">:</span>\r\n <span class=\"line-clamp-1\">{{\r\n parentComment.comment\r\n }}</span>\r\n </button>\r\n }\r\n\r\n @if (editingCommentId() === comment.id) {\r\n <div class=\"relative\">\r\n <textarea\r\n rows=\"3\"\r\n class=\"w-full min-h-[5.25rem] resize-y rounded-2xl border border-surface-300 bg-white px-3 py-2.5 text-[0.86rem] leading-[1.45] text-surface-900 outline-none focus-visible:outline-2 focus-visible:outline-[color-mix(in_srgb,var(--p-primary-color)_32%,transparent)] focus-visible:outline-offset-1\"\r\n [ngModel]=\"editText()\"\r\n (ngModelChange)=\"editText.set($event)\"\r\n (input)=\"onEditInput($event)\"\r\n (keyup)=\"onEditCaretEvent($event)\"\r\n (click)=\"onEditCaretEvent($event)\"\r\n (scroll)=\"onEditCaretEvent($event)\"\r\n (keydown)=\"onEditKeydown($event)\"\r\n ></textarea>\r\n\r\n @if (\r\n mentionSession()?.mode === \"edit\" &&\r\n mentionSession()?.editCommentId === comment.id\r\n ) {\r\n <div\r\n class=\"absolute top-0 left-0 z-20 min-w-56 overflow-auto rounded-xl border border-surface-300 bg-white shadow-[0_10px_40px_color-mix(in_srgb,black_14%,transparent)]\"\r\n [ngStyle]=\"mentionMenuStyle()\"\r\n [class.origin-bottom-left]=\"\r\n mentionMenuPosition()?.placement === 'above'\r\n \"\r\n >\r\n @if (mentionLoading()) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n Searching...\r\n </div>\r\n } @else if (mentionCandidates().length === 0) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n No matches\r\n </div>\r\n } @else {\r\n @for (\r\n candidate of mentionCandidates();\r\n track candidate.userId;\r\n let i = $index\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full cursor-pointer items-start gap-2 bg-transparent px-2.5 py-2 text-left text-[0.78rem] transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]\"\r\n [class.bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]]=\"\r\n mentionActiveIndex() === i\r\n \"\r\n (click)=\"selectMention(candidate)\"\r\n >\r\n <span\r\n class=\"mt-px inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_18%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.7rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)]\"\r\n >\r\n {{ getMentionAvatarText(candidate) }}\r\n </span>\r\n <span\r\n class=\"flex min-w-0 flex-1 flex-col gap-0.5\"\r\n >\r\n <span\r\n class=\"text-[0.79rem] leading-[1.25] font-semibold text-surface-900\"\r\n >{{\r\n candidate.displayName ||\r\n candidate.userName ||\r\n candidate.userId\r\n }}</span\r\n >\r\n <span\r\n class=\"inline-flex items-center text-[0.73rem] leading-[1.2] text-surface-500\"\r\n >\r\n @{{ candidate.userId }}\r\n </span>\r\n </span>\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"mt-2 flex flex-wrap items-center justify-between gap-2\"\r\n >\r\n <span class=\"text-xs text-surface-500\"\r\n >{{ editText().length }}/10000</span\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <button\r\n type=\"button\"\r\n class=\"rounded-[0.65rem] border border-surface-300 bg-transparent px-3 py-2 text-xs font-semibold leading-none text-surface-700 transition-colors hover:border-[color-mix(in_srgb,var(--p-primary-color)_24%,transparent)] hover:bg-[color-mix(in_srgb,var(--p-primary-color)_8%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"cancelEdit()\"\r\n >\r\n Cancel\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"rounded-[0.65rem] border border-[color-mix(in_srgb,var(--p-primary-color)_26%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_12%,white)] px-3 py-2 text-xs font-bold leading-none text-[color-mix(in_srgb,var(--p-primary-color)_76%,black)] transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_17%,white)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n [disabled]=\"!canSaveEdit()\"\r\n (click)=\"saveEdit()\"\r\n >\r\n {{ savingEdit() ? \"Saving...\" : \"Save\" }}\r\n </button>\r\n </div>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"whitespace-pre-wrap pt-1 break-words text-sm leading-6\"\r\n >\r\n @for (\r\n segment of getCommentSegments(comment);\r\n track $index\r\n ) {\r\n <span\r\n [ngClass]=\"\r\n segment.isMention\r\n ? 'rounded-sm bg-primary-50 px-0.5 font-semibold text-primary-700'\r\n : ''\r\n \"\r\n [attr.data-user-id]=\"segment.userId || null\"\r\n >\r\n {{ segment.text }}\r\n </span>\r\n }\r\n </div>\r\n\r\n @if (comment.attachments.length > 0) {\r\n <div class=\"mt-2 flex flex-wrap gap-2\">\r\n @for (\r\n attachment of comment.attachments;\r\n track attachment.id\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"inline-flex max-w-full items-center gap-1.5 rounded-lg border border-surface-300 px-2 py-1 text-[0.72rem] hover:bg-surface-50\"\r\n (click)=\"downloadAttachment(comment, attachment)\"\r\n >\r\n <span class=\"truncate\">{{\r\n attachment.fileName\r\n }}</span>\r\n <span class=\"text-[11px] text-surface-500\"\r\n >({{ attachment.size | number }} bytes)</span\r\n >\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"mt-2 flex flex-wrap items-center gap-1\">\r\n @if (!comment.isSystem) {\r\n <button\r\n type=\"button\"\r\n class=\"cursor-pointer rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"openReply(comment)\"\r\n >\r\n Reply\r\n </button>\r\n }\r\n @if (canEditComment(comment)) {\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"startEdit(comment)\"\r\n >\r\n Edit\r\n </button>\r\n }\r\n @if (canDeleteComment(comment)) {\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-red-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n [disabled]=\"isDeleting(comment.id)\"\r\n (click)=\"deleteComment(comment)\"\r\n >\r\n {{ isDeleting(comment.id) ? \"Deleting...\" : \"Delete\" }}\r\n </button>\r\n }\r\n @if (comment.updatedAt) {\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"openRevisions(comment)\"\r\n >\r\n History\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (isOwnComment(comment)) {\r\n <div\r\n class=\"mt-0.5 inline-flex h-[1.9rem] w-[1.9rem] shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_20%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.74rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_75%,black)]\"\r\n >\r\n {{ getAvatarText(comment) }}\r\n </div>\r\n }\r\n </article>\r\n }\r\n }\r\n </div>\r\n\r\n <footer\r\n class=\"z-10 shrink-0 border-t border-surface-200 bg-content px-3 py-3\"\r\n >\r\n @if (replyToComment(); as replyComment) {\r\n <div\r\n class=\"mb-2 flex items-center justify-between rounded-xl border border-surface-200 bg-surface-50 px-2 py-1\"\r\n >\r\n <div class=\"min-w-0 text-xs text-surface-600\">\r\n <span class=\"font-semibold\"\r\n >Replying to {{ replyComment.createdBy }}</span\r\n >\r\n <p class=\"truncate\">{{ replyComment.comment }}</p>\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"clearReply()\"\r\n >\r\n Cancel\r\n </button>\r\n </div>\r\n }\r\n\r\n <div\r\n class=\"rounded-[1.5rem] border border-surface-300 bg-white p-2.5 shadow-sm\"\r\n >\r\n <div class=\"relative\">\r\n <textarea\r\n #composerInput\r\n rows=\"2\"\r\n class=\"w-full min-h-[3.75rem] resize-none border-0 bg-transparent px-2 pb-10 pr-24 pt-1 text-[0.9rem] leading-[1.45] text-surface-900 outline-none\"\r\n [disabled]=\"disabled() || posting()\"\r\n [ngModel]=\"composerText()\"\r\n (ngModelChange)=\"composerText.set($event)\"\r\n (input)=\"onComposerInput($event)\"\r\n (keyup)=\"onComposerCaretEvent($event)\"\r\n (click)=\"onComposerCaretEvent($event)\"\r\n (scroll)=\"onComposerCaretEvent($event)\"\r\n (keydown)=\"onComposerKeydown($event)\"\r\n [placeholder]=\"placeholder()\"\r\n ></textarea>\r\n\r\n <div class=\"absolute right-1 bottom-1 flex items-center gap-2\">\r\n @if (allowAttachments()) {\r\n <mt-button\r\n icon=\"file.paperclip\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n variant=\"text\"\r\n [rounded]=\"true\"\r\n styleClass=\"mt-discussion-icon-btn\"\r\n [disabled]=\"disabled() || posting()\"\r\n (onClick)=\"browseAttachments()\"\r\n />\r\n }\r\n\r\n <mt-button\r\n icon=\"communication.send-01\"\r\n size=\"small\"\r\n [rounded]=\"true\"\r\n styleClass=\"mt-discussion-send-btn\"\r\n [loading]=\"posting()\"\r\n [disabled]=\"!canSend()\"\r\n (onClick)=\"sendComment()\"\r\n />\r\n </div>\r\n\r\n @if (mentionSession()?.mode === \"composer\") {\r\n <div\r\n class=\"absolute top-0 left-0 z-30 min-w-56 overflow-auto rounded-xl border border-surface-300 bg-white shadow-[0_10px_40px_color-mix(in_srgb,black_14%,transparent)]\"\r\n [ngStyle]=\"mentionMenuStyle()\"\r\n [class.origin-bottom-left]=\"\r\n mentionMenuPosition()?.placement === 'above'\r\n \"\r\n >\r\n @if (mentionLoading()) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n Searching...\r\n </div>\r\n } @else if (mentionCandidates().length === 0) {\r\n <div class=\"px-3 py-2 text-xs text-surface-500\">\r\n No matches\r\n </div>\r\n } @else {\r\n @for (\r\n candidate of mentionCandidates();\r\n track candidate.userId;\r\n let i = $index\r\n ) {\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full cursor-pointer items-start gap-2 bg-transparent px-2.5 py-2 text-left text-[0.78rem] transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]\"\r\n [class.bg-[color-mix(in_srgb,var(--p-primary-color)_11%,white)]]=\"\r\n mentionActiveIndex() === i\r\n \"\r\n (click)=\"selectMention(candidate)\"\r\n >\r\n <span\r\n class=\"mt-px inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full border border-[color-mix(in_srgb,var(--p-primary-color)_18%,transparent)] bg-[color-mix(in_srgb,var(--p-primary-color)_16%,white)] text-[0.7rem] font-bold text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)]\"\r\n >\r\n {{ getMentionAvatarText(candidate) }}\r\n </span>\r\n <span class=\"flex min-w-0 flex-1 flex-col gap-0.5\">\r\n <span\r\n class=\"text-[0.79rem] leading-[1.25] font-semibold text-surface-900\"\r\n >{{\r\n candidate.displayName ||\r\n candidate.userName ||\r\n candidate.userId\r\n }}</span\r\n >\r\n <span\r\n class=\"inline-flex items-center text-[0.73rem] leading-[1.2] text-surface-500\"\r\n >\r\n @{{ candidate.userId }}\r\n </span>\r\n </span>\r\n </button>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (composerAttachments().length > 0) {\r\n <div class=\"mt-2 flex flex-wrap gap-2 px-1\">\r\n @for (attachment of composerAttachments(); track attachment.id) {\r\n <div\r\n class=\"rounded-xl border border-surface-200 bg-surface-50 px-2.5 py-1.5 text-xs\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"max-w-[12rem] truncate\">{{\r\n attachment.fileName\r\n }}</span>\r\n @if (attachment.status === \"uploading\") {\r\n <span class=\"text-surface-500\"\r\n >{{ attachment.progress }}%</span\r\n >\r\n } @else if (attachment.status === \"failed\") {\r\n <span class=\"text-red-600\">Failed</span>\r\n } @else {\r\n <span class=\"text-emerald-600\">Ready</span>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"rounded-lg bg-transparent px-2 py-1 text-[0.72rem] font-semibold leading-none text-surface-600 transition-colors hover:bg-[color-mix(in_srgb,var(--p-primary-color)_10%,white)] hover:text-[color-mix(in_srgb,var(--p-primary-color)_74%,black)] disabled:cursor-not-allowed disabled:opacity-55\"\r\n (click)=\"removeAttachment(attachment.id)\"\r\n >\r\n Remove\r\n </button>\r\n </div>\r\n @if (attachment.error) {\r\n <p class=\"text-[11px] text-red-600\">\r\n {{ attachment.error }}\r\n </p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n @if (composerText().length > 10000) {\r\n <div class=\"mt-2 px-1 text-xs font-medium text-red-600\">\r\n Comment cannot exceed 10000 characters.\r\n </div>\r\n }\r\n </div>\r\n </footer>\r\n </div>\r\n </div>\r\n</mt-card>\r\n\r\n<p-dialog\r\n [visible]=\"revisionsDialogVisible()\"\r\n (visibleChange)=\"revisionsDialogVisible.set($event)\"\r\n [modal]=\"true\"\r\n [dismissableMask]=\"true\"\r\n [draggable]=\"false\"\r\n [resizable]=\"false\"\r\n [style]=\"{ width: 'min(42rem, 92vw)' }\"\r\n header=\"Comment history\"\r\n>\r\n @if (revisionLoading()) {\r\n <div class=\"space-y-2\">\r\n @for (row of [1, 2, 3]; track row) {\r\n <div class=\"h-12 animate-pulse rounded-xl bg-surface-100\"></div>\r\n }\r\n </div>\r\n } @else if (visibleRevisions().length === 0) {\r\n <p class=\"text-sm text-surface-500\">No revision snapshots.</p>\r\n } @else {\r\n <div class=\"max-h-[55vh] space-y-2 overflow-y-auto pr-1\">\r\n @for (revision of visibleRevisions(); track revision.id) {\r\n <article class=\"rounded-xl border border-surface-200 p-3\">\r\n <div class=\"mb-1 text-xs text-surface-500\">\r\n Revision #{{ revision.revisionNumber }} &bull;\r\n {{ revision.createdAt | date: \"MMM d, y h:mm a\" }} &bull;\r\n {{ revision.createdBy }}\r\n </div>\r\n <div class=\"whitespace-pre-wrap break-words text-sm leading-6\">\r\n @for (\r\n segment of getCommentSegments({\r\n id: revision.id,\r\n moduleType: selectedRevisionComment()?.moduleType || \"\",\r\n recordId: selectedRevisionComment()?.recordId || 0,\r\n parentCommentId: null,\r\n comment: revision.comment,\r\n isSystem: false,\r\n createdAt: revision.createdAt,\r\n updatedAt: null,\r\n createdBy: revision.createdBy,\r\n updatedBy: null,\r\n attachments: [],\r\n mentions: revision.mentions,\r\n });\r\n track $index\r\n ) {\r\n <span\r\n [ngClass]=\"\r\n segment.isMention\r\n ? 'rounded-sm bg-primary-50 px-0.5 font-semibold text-primary-700'\r\n : ''\r\n \"\r\n >{{ segment.text }}</span\r\n >\r\n }\r\n </div>\r\n </article>\r\n }\r\n </div>\r\n }\r\n</p-dialog>\r\n", styles: [":host{display:block;height:100%;min-height:0}:host ::ng-deep .mt-discussion-card>div{display:flex;flex-direction:column;height:100%;min-height:0}:host ::ng-deep .mt-discussion-card>div>div.flex-1{display:flex;flex-direction:column;min-height:0;overflow:hidden}:host ::ng-deep .mt-discussion-actions-popover .p-popover-content{padding:.25rem}:host ::ng-deep .mt-discussion-icon-btn,:host ::ng-deep .mt-discussion-send-btn{height:2.25rem;width:2.25rem;min-width:2.25rem}:host ::ng-deep .mt-discussion-send-btn{box-shadow:0 10px 24px color-mix(in srgb,var(--p-primary-color) 22%,transparent)}\n"] }]
1651
1638
  }], ctorParameters: () => [], propDecorators: { moduleType: [{ type: i0.Input, args: [{ isSignal: true, alias: "moduleType", required: true }] }], recordId: [{ type: i0.Input, args: [{ isSignal: true, alias: "recordId", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], currentUserId: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentUserId", required: false }] }], requestContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "requestContext", required: false }] }], mentionableUsers: [{ type: i0.Input, args: [{ isSignal: true, alias: "mentionableUsers", required: false }] }], mentionSearchEndpoint: [{ type: i0.Input, args: [{ isSignal: true, alias: "mentionSearchEndpoint", required: false }] }], mentionSearchParam: [{ type: i0.Input, args: [{ isSignal: true, alias: "mentionSearchParam", required: false }] }], mentionSearchDataPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "mentionSearchDataPath", required: false }] }], allowAttachments: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowAttachments", required: false }] }], uploadEndpoint: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadEndpoint", required: false }] }], attachmentDownloadEndpoint: [{ type: i0.Input, args: [{ isSignal: true, alias: "attachmentDownloadEndpoint", required: false }] }], showParticipants: [{ type: i0.Input, args: [{ isSignal: true, alias: "showParticipants", required: false }] }], autoMarkRead: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoMarkRead", required: false }] }], refreshIntervalMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "refreshIntervalMs", required: false }] }], styleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleClass", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loaded: [{ type: i0.Output, args: ["loaded"] }], errored: [{ type: i0.Output, args: ["errored"] }], commentCreated: [{ type: i0.Output, args: ["commentCreated"] }], commentUpdated: [{ type: i0.Output, args: ["commentUpdated"] }], commentDeleted: [{ type: i0.Output, args: ["commentDeleted"] }], readStateChanged: [{ type: i0.Output, args: ["readStateChanged"] }], viewportRef: [{ type: i0.ViewChild, args: ['viewport', { isSignal: true }] }], composerInputRef: [{ type: i0.ViewChild, args: ['composerInput', { isSignal: true }] }], attachmentInputRef: [{ type: i0.ViewChild, args: ['attachmentInput', { isSignal: true }] }] } });
1652
1639
 
1653
1640
  /**