<template>
  <div :class="[ns.b(), ns.is('loading', loading)]" :style="themeStyle">
    <div :class="ns.e('header')">
      <!-- Create New Button -->
      <button :class="ns.e('add-btn')" @click="handleCreate">
        <slot name="add-icon">
          <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
            <path
              d="M12 5V19M5 12H19"
              stroke="currentColor"
              stroke-width="2"
              stroke-linecap="round"
              stroke-linejoin="round"
            />
          </svg>
        </slot>
        <span :class="ns.e('add-text')">
          <slot name="add-text">{{ t('ai.conversations.newConversation') }}</slot>
        </span>
      </button>
    </div>

    <!-- Loading Skeleton -->
    <div v-if="loading && data.length === 0" :class="ns.e('loading-placer')">
      <div v-for="i in 5" :key="i" :class="ns.e('skeleton-item')">
        <div :class="ns.e('skeleton-line')"></div>
        <div :class="ns.e('skeleton-line')" style="width: 60%"></div>
      </div>
    </div>

    <!-- Conversation List with groups -->
    <div
      v-else
      ref="containerRef"
      :class="[ns.e('list'), ns.is('virtual', virtualScroll)]"
      :style="listStyle"
      @scroll.passive="virtualScroll ? handleVirtualScroll($event) : void 0"
    >
      <!-- 时间分组渲染 -->
      <template v-if="groupedData.length > 0">
        <template v-for="group in groupedData" :key="group.label">
          <!-- 分组标题 -->
          <div :class="ns.e('group-label')">
            <slot name="group-label" :label="group.label">
              {{ t(`ai.conversations.${group.label}`) }}
            </slot>
          </div>

          <!-- 分组内的对话项 -->
          <TransitionGroup name="yh-conversation-item" tag="div">
            <div
              v-for="item in group.items"
              :key="item.id"
              :class="[ns.e('item'), ns.is('active', activeId === item.id), ns.is('pinned', !!item.pinned)]"
              @click="handleClick(item)"
            >
              <!-- 置顶图标 -->
              <span v-if="item.pinned" :class="ns.e('pin-icon')">
                <svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor">
                  <path
                    d="M16 12V4h1a1 1 0 0 0 0-2H7a1 1 0 0 0 0 2h1v8l-2 2v2h5v5l1 1 1-1v-5h5v-2l-2-2z"
                  />
                </svg>
              </span>

              <!-- Item Info -->
              <div :class="ns.e('item-content')">
                <span
                  v-if="!editingId || editingId !== item.id"
                  :class="ns.e('title')"
                  :title="item.title"
                >
                  {{ item.title }}
                </span>
                <input
                  v-else
                  v-model="editTitle"
                  :class="ns.e('input')"
                  @blur="confirmEdit(item)"
                  @keydown.enter="confirmEdit(item)"
                  @keydown.esc="cancelEdit"
                  @click.stop
                  ref="inputRef"
                />

                <span v-if="item.updatedAt" :class="ns.e('time')">
                  {{ formatTime(item.updatedAt) }}
                </span>
                <span v-if="item.excerpt" :class="ns.e('excerpt')">
                  {{ item.excerpt }}
                </span>
              </div>

              <!-- Actions -->
              <div :class="ns.e('actions')" @click.stop v-if="!editingId || editingId !== item.id">
                <!-- 置顶/取消置顶 -->
                <span
                  :class="[ns.e('action-btn'), ns.is('active', !!item.pinned)]"
                  :title="item.pinned ? t('ai.conversations.unpin') : t('ai.conversations.pin')"
                  @click.stop="handlePin(item)"
                >
                  <svg
                    viewBox="0 0 24 24"
                    width="13"
                    height="13"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2"
                  >
                    <path
                      d="M16 12V4h1a1 1 0 0 0 0-2H7a1 1 0 0 0 0 2h1v8l-2 2v2h5v5l1 1 1-1v-5h5v-2l-2-2z"
                    />
                  </svg>
                </span>
                <!-- Edit Icon -->
                <span :class="ns.e('action-btn')" @click.stop="startEdit(item)">
                  <slot name="edit-icon">
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      stroke-linecap="round"
                      stroke-linejoin="round"
                    >
                      <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
                      <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
                    </svg>
                  </slot>
                </span>
                <!-- Delete Icon -->
                <span :class="ns.e('action-btn')" @click.stop="handleDelete(item)">
                  <slot name="delete-icon">
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      stroke-linecap="round"
                      stroke-linejoin="round"
                    >
                      <polyline points="3 6 5 6 21 6"></polyline>
                      <path
                        d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
                      ></path>
                      <line x1="10" y1="11" x2="10" y2="17"></line>
                      <line x1="14" y1="11" x2="14" y2="17"></line>
                    </svg>
                  </slot>
                </span>
              </div>
            </div>
          </TransitionGroup>
        </template>
      </template>

      <!-- Flat 模式（未分组）-->
      <template v-else-if="data.length > 0 && !showGroups">
        <!-- 虚拟滚动模式 -->
        <template v-if="virtualScroll">
          <!-- 外层：position:relative + 总高度，产生真实滚动条 -->
          <div :style="{
  position: 'relative',
  height: totalHeight + 'px'
}">
            <!-- 内层：position:absolute + top:offsetY，定位到当前可见区域 -->
            <div :style="{
  position: 'absolute',
  top: offsetY + 'px',
  left: 0,
  right: 0
}">
              <div
                v-for="item in visibleItems"
                :key="item.id"
                :class="[ns.e('item'), ns.is('active', activeId === item.id), ns.is('pinned', !!item.pinned)]"
                :style="{
  height: virtualScrollItemHeight + 'px'
}"
                @click="handleClick(item)"
              >
                <!-- 置顶图标 -->
                <span v-if="item.pinned" :class="ns.e('pin-icon')">
                  <svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor">
                    <path
                      d="M16 12V4h1a1 1 0 0 0 0-2H7a1 1 0 0 0 0 2h1v8l-2 2v2h5v5l1 1 1-1v-5h5v-2l-2-2z"
                    />
                  </svg>
                </span>

                <!-- Item Info -->
                <div :class="ns.e('item-content')">
                  <span
                    v-if="!editingId || editingId !== item.id"
                    :class="ns.e('title')"
                    :title="item.title"
                  >
                    {{ item.title }}
                  </span>
                  <input
                    v-else
                    v-model="editTitle"
                    :class="ns.e('input')"
                    @blur="confirmEdit(item)"
                    @keydown.enter="confirmEdit(item)"
                    @keydown.esc="cancelEdit"
                    @click.stop
                    ref="inputRef"
                  />

                  <span v-if="item.updatedAt" :class="ns.e('time')">
                    {{ formatTime(item.updatedAt) }}
                  </span>
                  <span v-if="item.excerpt" :class="ns.e('excerpt')">
                    {{ item.excerpt }}
                  </span>
                </div>

                <!-- Actions -->
                <div
                  :class="ns.e('actions')"
                  @click.stop
                  v-if="!editingId || editingId !== item.id"
                >
                  <!-- 置顶/取消置顶 -->
                  <span
                    :class="[ns.e('action-btn'), ns.is('active', !!item.pinned)]"
                    :title="item.pinned ? t('ai.conversations.unpin') : t('ai.conversations.pin')"
                    @click.stop="handlePin(item)"
                  >
                    <svg
                      viewBox="0 0 24 24"
                      width="13"
                      height="13"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                    >
                      <path
                        d="M16 12V4h1a1 1 0 0 0 0-2H7a1 1 0 0 0 0 2h1v8l-2 2v2h5v5l1 1 1-1v-5h5v-2l-2-2z"
                      />
                    </svg>
                  </span>
                  <!-- Edit Icon -->
                  <span :class="ns.e('action-btn')" @click.stop="startEdit(item)">
                    <slot name="edit-icon">
                      <svg
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2"
                        stroke-linecap="round"
                        stroke-linejoin="round"
                      >
                        <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
                        <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
                      </svg>
                    </slot>
                  </span>
                  <!-- Delete Icon -->
                  <span :class="ns.e('action-btn')" @click.stop="handleDelete(item)">
                    <slot name="delete-icon">
                      <svg
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2"
                        stroke-linecap="round"
                        stroke-linejoin="round"
                      >
                        <polyline points="3 6 5 6 21 6"></polyline>
                        <path
                          d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
                        ></path>
                        <line x1="10" y1="11" x2="10" y2="17"></line>
                        <line x1="14" y1="11" x2="14" y2="17"></line>
                      </svg>
                    </slot>
                  </span>
                </div>
              </div>
            </div>
          </div>
        </template>
        <!-- 普通模式 -->
        <template v-else>
          <div
            v-for="item in data"
            :key="item.id"
            :class="[ns.e('item'), ns.is('active', activeId === item.id), ns.is('pinned', !!item.pinned)]"
            @click="handleClick(item)"
          >
            <!-- 置顶图标 -->
            <span v-if="item.pinned" :class="ns.e('pin-icon')">
              <svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor">
                <path
                  d="M16 12V4h1a1 1 0 0 0 0-2H7a1 1 0 0 0 0 2h1v8l-2 2v2h5v5l1 1 1-1v-5h5v-2l-2-2z"
                />
              </svg>
            </span>

            <!-- Item Info -->
            <div :class="ns.e('item-content')">
              <span
                v-if="!editingId || editingId !== item.id"
                :class="ns.e('title')"
                :title="item.title"
              >
                {{ item.title }}
              </span>
              <input
                v-else
                v-model="editTitle"
                :class="ns.e('input')"
                @blur="confirmEdit(item)"
                @keydown.enter="confirmEdit(item)"
                @keydown.esc="cancelEdit"
                @click.stop
                ref="inputRef"
              />

              <span v-if="item.updatedAt" :class="ns.e('time')">
                {{ formatTime(item.updatedAt) }}
              </span>
              <span v-if="item.excerpt" :class="ns.e('excerpt')">
                {{ item.excerpt }}
              </span>
            </div>

            <!-- Actions -->
            <div :class="ns.e('actions')" @click.stop v-if="!editingId || editingId !== item.id">
              <!-- 置顶/取消置顶 -->
              <span
                :class="[ns.e('action-btn'), ns.is('active', !!item.pinned)]"
                :title="item.pinned ? t('ai.conversations.unpin') : t('ai.conversations.pin')"
                @click.stop="handlePin(item)"
              >
                <svg
                  viewBox="0 0 24 24"
                  width="13"
                  height="13"
                  fill="none"
                  stroke="currentColor"
                  stroke-width="2"
                >
                  <path
                    d="M16 12V4h1a1 1 0 0 0 0-2H7a1 1 0 0 0 0 2h1v8l-2 2v2h5v5l1 1 1-1v-5h5v-2l-2-2z"
                  />
                </svg>
              </span>
              <!-- Edit Icon -->
              <span :class="ns.e('action-btn')" @click.stop="startEdit(item)">
                <slot name="edit-icon">
                  <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2"
                    stroke-linecap="round"
                    stroke-linejoin="round"
                  >
                    <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
                    <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
                  </svg>
                </slot>
              </span>
              <!-- Delete Icon -->
              <span :class="ns.e('action-btn')" @click.stop="handleDelete(item)">
                <slot name="delete-icon">
                  <svg
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    stroke-width="2"
                    stroke-linecap="round"
                    stroke-linejoin="round"
                  >
                    <polyline points="3 6 5 6 21 6"></polyline>
                    <path
                      d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
                    ></path>
                    <line x1="10" y1="11" x2="10" y2="17"></line>
                    <line x1="14" y1="11" x2="14" y2="17"></line>
                  </svg>
                </slot>
              </span>
            </div>
          </div>
        </template>
      </template>

      <!-- Empty State -->
      <div v-if="!loading && data.length === 0" :class="ns.e('empty')">
        <slot name="empty">{{ t("ai.conversations.noData") }}</slot>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, nextTick } from "vue";
import { useNamespace, useLocale, useVirtualScroll } from "@yh-ui/hooks";
import { useComponentTheme } from "@yh-ui/theme";
import { aiConversationsProps, aiConversationsEmits } from "./ai-conversations";
defineOptions({
  name: "YhAiConversations"
});
const props = defineProps(aiConversationsProps);
const emit = defineEmits(aiConversationsEmits);
const ns = useNamespace("ai-conversations");
const { t } = useLocale();
const { themeStyle } = useComponentTheme("ai-conversations", props.themeOverrides);
const editingId = ref(null);
const editTitle = ref("");
const inputRef = ref();
const showGroups = computed(() => props.grouped !== false && !props.virtualScroll);
const {
  visibleItems,
  totalHeight,
  offsetY,
  onScroll: handleVirtualScroll,
  scrollToIndex,
  containerRef
} = useVirtualScroll({
  itemHeight: computed(() => props.virtualScrollItemHeight),
  containerHeight: computed(() => props.virtualScrollHeight),
  overscan: computed(() => props.virtualScrollOverscan),
  items: computed(() => props.data)
});
const listStyle = computed(() => {
  if (!props.virtualScroll) return {};
  return {
    height: `${props.virtualScrollHeight}px`,
    maxHeight: `${props.virtualScrollHeight}px`,
    overflowY: "auto",
    position: "relative"
  };
});
const getGroupKey = (item) => {
  if (item.pinned) return "pinned";
  const diff = Date.now() - item.updatedAt;
  const oneDay = 864e5;
  if (diff < oneDay) return "today";
  if (diff < 7 * oneDay) return "last7Days";
  if (diff < 30 * oneDay) return "last30Days";
  return "earlier";
};
const groupedData = computed(() => {
  if (!showGroups.value) return [];
  const groups = {
    pinned: [],
    today: [],
    last7Days: [],
    last30Days: [],
    earlier: []
  };
  for (const item of props.data) {
    groups[getGroupKey(item)].push(item);
  }
  const order = ["pinned", "today", "last7Days", "last30Days", "earlier"];
  return order.filter((k) => groups[k].length > 0).map((k) => ({ label: k, items: groups[k] }));
});
const handleCreate = () => emit("create");
const handleClick = (item) => {
  if (editingId.value === item.id) return;
  emit("update:activeId", item.id);
  emit("click", item);
};
const handleDelete = (item) => emit("delete", item);
const handlePin = (item) => emit("pin", item, !item.pinned);
const startEdit = (item) => {
  editingId.value = item.id;
  editTitle.value = item.title;
  nextTick(() => {
    if (inputRef.value?.[0]) inputRef.value[0].focus();
  });
};
const confirmEdit = (item) => {
  if (!editingId.value) return;
  const title = editTitle.value.trim();
  if (title && title !== item.title) emit("edit", item, title);
  editingId.value = null;
};
const cancelEdit = () => {
  editingId.value = null;
};
const formatTime = (ts) => {
  const d = new Date(ts);
  const now = /* @__PURE__ */ new Date();
  const isToday = d.toDateString() === now.toDateString();
  const pad = (n) => n.toString().padStart(2, "0");
  if (isToday) {
    return `${pad(d.getHours())}:${pad(d.getMinutes())}`;
  }
  return `${d.getMonth() + 1}/${d.getDate()}`;
};
const scrollToItem = (id) => {
  const index = props.data.findIndex((item) => item.id === id);
  if (index !== -1) {
    scrollToIndex(index);
  }
};
defineExpose({
  scrollToItem,
  scrollToIndex
});
</script>

<style>
@charset "UTF-8";
/**
 * YH-UI Sass Variables
 * 原具体的 CSS 变量输出规则 (:root, html.dark 等) 已移至 root.scss，以防止各组件样式编译时产生重复的全局变量 CSS 冗余。
 */
.yh-ai-conversations {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  border-right: 1px solid var(--yh-ai-conversations-border-color, var(--yh-border-color));
  background-color: var(--yh-ai-conversations-bg-color, var(--yh-bg-color));
}
.yh-ai-conversations__header {
  padding: var(--yh-ai-conversations-header-padding, 16px);
  border-bottom: 1px solid var(--yh-ai-conversations-border-color, var(--yh-border-color));
}

.yh-ai-conversations__add-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 8px 16px;
  background-color: var(--yh-bg-color);
  border: 1px solid var(--yh-border-color);
  border-radius: var(--yh-border-radius-base);
  color: var(--yh-text-color-primary);
  cursor: pointer;
  transition: all var(--yh-transition-duration);
  gap: 4px;
}
.yh-ai-conversations__add-btn:hover {
  border-color: var(--yh-color-primary);
  color: var(--yh-color-primary);
  background-color: var(--yh-color-primary-light-9);
}
.yh-ai-conversations__add-btn svg {
  width: 16px;
  height: 16px;
}

.yh-ai-conversations__list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  position: relative;
}
.yh-ai-conversations__list.is-virtual {
  flex: none;
  display: block;
  padding: 0;
  position: relative;
}

.yh-ai-conversations__list::-webkit-scrollbar {
  width: 4px;
}
.yh-ai-conversations__list::-webkit-scrollbar-thumb {
  border-radius: 4px;
  background: var(--yh-border-color-light);
}

.yh-ai-conversations__loading-placer {
  display: flex;
  justify-content: center;
  padding: 24px 0;
}

.yh-ai-conversations__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 50px;
  height: auto;
  padding: var(--yh-ai-conversations-item-padding, 12px 16px);
  margin: 0 4px 8px;
  border-radius: var(--yh-border-radius-base);
  cursor: pointer;
  transition: all var(--yh-transition-duration);
  background-color: transparent;
  position: relative;
  box-sizing: border-box;
  flex-shrink: 0;
}
.yh-ai-conversations__item:hover {
  background-color: var(--yh-ai-conversations-hover-bg-color, var(--yh-bg-color-page));
}
.yh-ai-conversations__item:hover .yh-ai-conversations__actions {
  opacity: 1;
  visibility: visible;
}
.yh-ai-conversations__item.is-active {
  background-color: var(--yh-ai-conversations-active-bg-color, var(--yh-color-primary-light-9));
}
.yh-ai-conversations__item.is-active::before {
  content: "";
  position: absolute;
  left: 0;
  top: 20%;
  bottom: 20%;
  width: 3px;
  background-color: var(--yh-color-primary);
  border-radius: 0 2px 2px 0;
}
.yh-ai-conversations__item.is-active .yh-ai-conversations__title {
  color: var(--yh-ai-conversations-active-text-color, var(--yh-color-primary));
  font-weight: 600;
}
.yh-ai-conversations__item.is-active .yh-ai-conversations__time,
.yh-ai-conversations__item.is-active .yh-ai-conversations__excerpt {
  color: var(--yh-color-primary-light-3);
}

.yh-ai-conversations__item-content {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
  gap: 8px;
}

.yh-ai-conversations__title {
  font-size: var(--yh-ai-conversations-title-font-size, 14px);
  color: var(--yh-text-color-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color var(--yh-transition-duration);
}

.yh-ai-conversations__input {
  width: 100%;
  font-size: 14px;
  border: 1px solid var(--yh-color-primary);
  border-radius: 4px;
  padding: 2px 6px;
  outline: none;
  background: var(--yh-bg-color);
  color: var(--yh-text-color-primary);
}

.yh-ai-conversations__time {
  font-size: var(--yh-ai-conversations-time-font-size, 12px);
  color: var(--yh-text-color-secondary);
}

.yh-ai-conversations__excerpt {
  font-size: 12px;
  color: var(--yh-text-color-regular);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.yh-ai-conversations__actions {
  display: flex;
  align-items: center;
  gap: 4px;
  opacity: 0;
  visibility: hidden;
  transition: all var(--yh-transition-duration);
}

.yh-ai-conversations__action-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  color: var(--yh-text-color-secondary);
  border-radius: 4px;
  cursor: pointer;
}
.yh-ai-conversations__action-btn:hover {
  background-color: var(--yh-fill-color-light);
  color: var(--yh-text-color-primary);
}
.yh-ai-conversations__action-btn svg {
  width: 14px;
  height: 14px;
}

.yh-ai-conversations__empty {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  color: var(--yh-text-color-secondary);
  font-size: 14px;
}

.yh-ai-conversations__group-label {
  padding: 8px 16px 4px;
  font-size: 11px;
  font-weight: 600;
  color: var(--yh-text-color-disabled);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  user-select: none;
}

.yh-ai-conversations__pin-icon {
  display: flex;
  align-items: center;
  margin-right: 4px;
  color: var(--yh-color-primary-light-3);
  flex-shrink: 0;
}

.yh-ai-conversations__item.is-pinned {
  background-color: var(--yh-ai-conversations-hover-bg-color, var(--yh-bg-color-page));
}
.yh-ai-conversations__item.is-pinned::before {
  content: "";
  position: absolute;
  left: 0;
  top: 25%;
  bottom: 25%;
  width: 3px;
  background-color: var(--yh-color-primary-light-3);
  border-radius: 0 2px 2px 0;
}

.yh-ai-conversations__action-btn.is-active {
  color: var(--yh-color-primary) !important;
}

.yh-ai-conversations__skeleton-item {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 16px;
  border-radius: var(--yh-border-radius-base);
}

.yh-ai-conversations__skeleton-line {
  height: 13px;
  border-radius: 7px;
  width: 100%;
  background: linear-gradient(90deg, var(--yh-fill-color) 25%, var(--yh-fill-color-light) 50%, var(--yh-fill-color) 75%);
  background-size: 200% 100%;
  animation: yh-conv-shimmer 1.5s infinite;
}

.yh-conversation-item-enter-active,
.yh-conversation-item-leave-active {
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

.yh-conversation-item-enter-from {
  opacity: 0;
  transform: translateX(-12px);
}

.yh-conversation-item-leave-to {
  opacity: 0;
  transform: translateX(12px);
}

@keyframes yh-conv-shimmer {
  0% {
    background-position: 200% 0;
  }
  100% {
    background-position: -200% 0;
  }
}
</style>
