| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703 |
- // ─────────────────────────────────────────────────────────────
- // /chat — 메인 실시간 채팅 (d2-community §⑤, roomKey=main)
- // 색/치수는 app/styles/tokens 변수만 사용 (하드코딩 금지)
- // Twitch 스타일: border-radius 0, 선 기반 깔끔한 UI
- // 채팅 도크(우측 고정) + 팝업(/chat-popup) 공용 스타일
- // ─────────────────────────────────────────────────────────────
- #chat-room {
- display: flex;
- flex-direction: column;
- height: 100%;
- min-height: 0;
- padding: var(--sp-4) var(--sp-5);
- gap: var(--sp-3);
- @media (max-width: 767.98px) {
- padding: var(--sp-3);
- }
- // ── 헤더: 참여자 수(클릭→목록) + 상태 + 컨트롤 ──
- .chat-room__head {
- display: flex;
- align-items: center;
- justify-content: space-between;
- flex-wrap: wrap;
- gap: var(--sp-2);
- }
- // 참여자 수 버튼 (실시간 채팅 label 위치)
- .chat-room__count {
- display: inline-flex;
- align-items: center;
- gap: var(--sp-2);
- padding: var(--sp-1) var(--sp-2);
- background: transparent;
- border: none;
- cursor: pointer;
- font-size: var(--fs-sm);
- color: var(--text-secondary);
- font-variant-numeric: tabular-nums;
- // --bg-icon(다크)은 양 테마 공통 → 라이트에서 어두운 텍스트가 안 보이므로 흰색 고정
- // (옆 .chat-room__icon-btn 알림/설정 버튼과 동일). 숫자/caret/아이콘까지 함께 밝게.
- &:hover, &:focus-visible {
- background: var(--bg-icon);
- color: #fff;
- .chat-room__count-num,
- .chat-room__count-caret,
- > svg:first-child {
- color: #fff;
- }
- }
- > svg:first-child {
- color: var(--text-muted);
- }
- }
- .chat-room__count-num {
- font-weight: 700;
- color: var(--text-primary);
- }
- .chat-room__count-caret {
- font-size: var(--fs-2xs);
- color: var(--text-muted);
- transition: transform 0.15s ease;
- &.is-open {
- transform: rotate(180deg);
- }
- }
- .chat-room__meta {
- display: flex;
- align-items: center;
- gap: var(--sp-2);
- font-size: var(--fs-sm);
- color: var(--text-secondary);
- }
- .chat-room__state {
- color: var(--text-muted);
- white-space: nowrap;
- &--warn {
- color: var(--az-accent);
- }
- &--error {
- color: var(--color-danger);
- }
- }
- .chat-room__notice {
- display: flex;
- align-items: center;
- gap: var(--sp-3);
- padding: var(--sp-3) var(--sp-4);
- background: var(--bg-subtle);
- border: 1px solid var(--border-default);
- border-radius: 0;
- font-size: var(--fs-sm);
- color: var(--text-secondary);
- svg {
- flex-shrink: 0;
- color: var(--az-accent);
- }
- }
- .chat-room__body {
- position: relative;
- display: flex;
- flex: 1;
- min-height: 0;
- }
- .chat-room__messages {
- flex: 1;
- min-height: 0;
- overflow-y: auto;
- padding: var(--sp-3);
- background: var(--bg-elevated);
- border: 1px solid var(--border-default);
- border-radius: 0;
- }
- .chat-room__empty {
- padding: var(--sp-6) var(--sp-4);
- text-align: center;
- font-size: var(--fs-sm);
- color: var(--text-muted);
- }
- .chat-room__message {
- display: flex;
- align-items: baseline;
- gap: var(--sp-3);
- padding: var(--sp-2) var(--sp-3);
- // 글씨 크게/작게 — --chat-fs 배율 (이름·내용 상속)
- font-size: calc(var(--fs-base) * var(--chat-fs, 1));
- line-height: 1.5;
- border-radius: 0;
- &:hover {
- background: var(--bg-subtle-hover);
- }
- }
- .chat-room__time {
- flex-shrink: 0;
- font-size: var(--fs-2xs);
- color: var(--text-muted);
- font-variant-numeric: tabular-nums;
- }
- .chat-room__badge {
- flex-shrink: 0;
- align-self: center;
- width: var(--sp-5);
- height: var(--sp-5);
- object-fit: contain;
- }
- .chat-room__name {
- flex-shrink: 0;
- font-weight: 600;
- color: var(--title-color, var(--text-secondary));
- }
- .chat-room__content {
- color: var(--text-primary);
- word-break: break-word;
- overflow-wrap: anywhere;
- }
- // 시스템 메시지 — 일반 메시지와 스타일 구분
- .chat-room__system {
- padding: var(--sp-2) var(--sp-3);
- text-align: center;
- font-size: var(--fs-xs);
- font-style: italic;
- color: var(--text-muted);
- }
- // 참여자 목록 오버레이 — 본체(.chat-room__body) 를 덮음
- .chat-room__participants {
- position: absolute;
- inset: 0;
- z-index: 20;
- display: flex;
- }
- // "새 메시지 ↓" 점프 버튼 — 위로 스크롤 중 새 메시지 도착 시 노출
- .chat-room__jump {
- position: absolute;
- bottom: var(--sp-4);
- left: 50%;
- transform: translateX(-50%);
- display: inline-flex;
- align-items: center;
- gap: var(--sp-2);
- padding: var(--sp-2) var(--sp-4);
- background: var(--az-accent);
- color: var(--btn-primary-text);
- font-size: var(--fs-sm);
- font-weight: 600;
- border: none;
- border-radius: 0;
- cursor: pointer;
- box-shadow: 0 var(--sp-1) var(--sp-3) var(--shadow-color);
- &:hover {
- background: var(--az-accent-hover);
- }
- }
- .chat-room__footer {
- position: relative;
- display: flex;
- flex-direction: column;
- gap: var(--sp-2);
- }
- .chat-room__input-row {
- display: flex;
- align-items: stretch;
- gap: var(--sp-2);
- }
- .chat-room__input {
- flex: 1;
- min-width: 0;
- padding: var(--sp-3) var(--sp-4);
- background: var(--bg-input);
- color: var(--text-primary);
- font-size: var(--fs-base);
- border: 1px solid var(--border-strong);
- border-radius: 0;
- &::placeholder {
- color: var(--text-muted);
- }
- &:disabled {
- opacity: 0.6;
- cursor: not-allowed;
- }
- }
- .chat-room__send {
- flex-shrink: 0;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- min-width: var(--sp-7);
- padding: 0 var(--sp-4);
- background: var(--az-accent);
- color: var(--btn-primary-text);
- font-size: var(--fs-base);
- font-weight: 600;
- border: none;
- border-radius: 0;
- cursor: pointer;
- &:hover:not(:disabled) {
- background: var(--az-accent-hover);
- }
- &:disabled {
- background: var(--bg-subtle);
- color: var(--text-muted);
- cursor: not-allowed;
- }
- }
- .chat-room__cooldown {
- font-variant-numeric: tabular-nums;
- }
- // 푸터 이모지 버튼 — 입력창·전송과 높이 정렬(선 기반 아이콘 버튼)
- #emojiPicker {
- flex-shrink: 0;
- position: static; // 팝업(aside)의 위치 기준을 .chat-room__footer 로 이동
- > button {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--sp-7);
- height: 100%;
- min-height: var(--sp-7);
- background: var(--bg-subtle);
- border: 1px solid var(--border-strong);
- color: var(--text-secondary);
- cursor: pointer;
- &:hover, &:focus, &:active {
- background: var(--bg-subtle-hover);
- color: var(--text-link);
- }
- }
- // 좁은 도크 폭 안에서 위로 열림 — footer 폭에 맞춰 span, 화면 밖 클리핑 방지
- > aside {
- position: absolute;
- top: auto;
- bottom: calc(100% + var(--sp-2));
- left: var(--sp-3);
- right: var(--sp-3);
- width: auto !important;
- height: min(340px, 50vh) !important;
- max-width: none;
- // Twitch 플랫: 이모지 팝업도 라운드 제거 (라이브러리 기본 8px 상쇄)
- border-radius: 0;
- --epr-width: auto;
- --epr-height: 340px;
- --epr-picker-border-radius: 0;
- }
- }
- .chat-room__blocked {
- padding: var(--sp-4);
- text-align: center;
- background: var(--color-danger-bg);
- border: 1px solid var(--color-danger-border);
- border-radius: 0;
- font-size: var(--fs-sm);
- color: var(--color-danger);
- }
- // 팝업(/chat-popup) — 전체 창 채움
- &.chat-room--popup {
- flex: 1;
- min-height: 0;
- }
- }
- // ── 공용 아이콘 버튼 (헤더 수신설정 · 설정 트리거 · 닫기) ──
- .chat-room__icon-btn,
- .chat-menu__trigger,
- .chat-participants__close,
- .chat-modal__close {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--sp-6);
- height: var(--sp-6);
- background: transparent;
- border: none;
- cursor: pointer;
- color: var(--text-secondary);
- font-size: var(--fs-base);
- border-radius: 0;
- &:hover {
- background: var(--bg-icon);
- color: #fff; // --bg-icon(다크)은 양 테마 공통 → 라이트에서 --text-primary(어두움)가 안 보이므로 흰색 고정
- }
- }
- // ── 접속 참여자 목록 ──
- .chat-participants {
- display: flex;
- flex: 1;
- min-width: 0;
- flex-direction: column;
- background: var(--bg-elevated);
- border: 1px solid var(--border-default);
- &__head {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: var(--sp-3);
- border-bottom: 1px solid var(--border-default);
- }
- &__title {
- font-size: var(--fs-sm);
- font-weight: 600;
- color: var(--text-primary);
- }
- &__body {
- flex: 1;
- min-height: 0;
- overflow-y: auto;
- }
- &__empty {
- padding: var(--sp-6) var(--sp-4);
- text-align: center;
- font-size: var(--fs-sm);
- color: var(--text-muted);
- }
- &__list {
- display: flex;
- flex-direction: column;
- }
- &__item {
- display: flex;
- align-items: center;
- gap: var(--sp-3);
- padding: var(--sp-2) var(--sp-3);
- &:hover {
- background: var(--bg-subtle-hover);
- }
- }
- &__avatar {
- flex-shrink: 0;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--sp-6);
- height: var(--sp-6);
- background: var(--bg-subtle);
- color: var(--text-muted);
- overflow: hidden;
- img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- }
- }
- &__info {
- display: flex;
- flex-direction: column;
- flex: 1;
- min-width: 0;
- }
- &__name {
- font-size: var(--fs-sm);
- font-weight: 600;
- color: var(--text-primary);
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- &__sid {
- font-size: var(--fs-2xs);
- color: var(--text-muted);
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- &__level {
- flex-shrink: 0;
- padding: 0 var(--sp-2);
- font-size: var(--fs-2xs);
- font-weight: 600;
- color: var(--az-accent);
- border: 1px solid var(--border-default);
- }
- }
- // ── 설정 dropdown (톱니바퀴) ──
- .chat-menu {
- position: relative;
- display: inline-flex;
- &__dropdown {
- position: absolute;
- top: calc(100% + var(--sp-2));
- right: 0;
- z-index: 30;
- min-width: 160px;
- padding: var(--sp-2) 0;
- background: var(--bg-elevated);
- border: 1px solid var(--border-default);
- box-shadow: 0 var(--sp-1) var(--sp-3) var(--shadow-color);
- }
- &__item {
- display: flex;
- align-items: center;
- gap: var(--sp-3);
- width: 100%;
- padding: var(--sp-2) var(--sp-4);
- background: transparent;
- border: none;
- cursor: pointer;
- font-size: var(--fs-sm);
- color: var(--text-secondary);
- text-align: left;
- svg {
- width: var(--sp-4);
- color: var(--text-muted);
- }
- &:hover {
- background: var(--bg-subtle-hover);
- color: var(--text-primary);
- svg {
- color: var(--az-accent);
- }
- }
- }
- &__divider {
- height: 1px;
- margin: var(--sp-2) 0;
- background: var(--border-default);
- }
- }
- // ── 수신설정 modal (portal → body) ──
- .chat-modal {
- position: fixed;
- inset: 0;
- z-index: 1200;
- display: flex;
- align-items: center;
- justify-content: center;
- padding: var(--sp-4);
- background: var(--overlay-color);
- &__panel {
- display: flex;
- flex-direction: column;
- width: min(420px, 100%);
- max-height: min(560px, calc(100dvh - 2rem));
- background: var(--bg-page);
- border: 1px solid var(--border-default);
- box-shadow: 0 var(--sp-2) var(--sp-5) var(--shadow-color);
- }
- &__head {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: var(--sp-4);
- border-bottom: 1px solid var(--border-default);
- }
- &__title {
- font-size: var(--fs-lg);
- font-weight: 700;
- color: var(--text-primary);
- }
- &__body {
- display: flex;
- flex-direction: column;
- gap: var(--sp-4);
- padding: var(--sp-4);
- overflow-y: auto;
- }
- &__loading {
- padding: var(--sp-5);
- text-align: center;
- font-size: var(--fs-sm);
- color: var(--text-muted);
- }
- &__error {
- font-size: var(--fs-sm);
- color: var(--color-danger);
- }
- &__foot {
- display: flex;
- justify-content: flex-end;
- gap: var(--sp-3);
- padding: var(--sp-4);
- border-top: 1px solid var(--border-default);
- }
- &__btn {
- padding: var(--sp-2) var(--sp-5);
- font-size: var(--fs-sm);
- font-weight: 600;
- border: 1px solid transparent;
- border-radius: 0;
- cursor: pointer;
- &--ghost {
- background: transparent;
- border-color: var(--border-strong);
- color: var(--text-secondary);
- &:hover:not(:disabled) {
- background: var(--bg-subtle-hover);
- color: var(--text-primary);
- }
- }
- &--primary {
- background: var(--az-accent);
- color: var(--btn-primary-text);
- &:hover:not(:disabled) {
- background: var(--az-accent-hover);
- }
- }
- &:disabled {
- opacity: 0.6;
- cursor: not-allowed;
- }
- }
- }
- // ── 토글 스위치 (초대/귓속말/팔로잉 접속 표시) — 선 기반 사각 스위치 ──
- .chat-toggle {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: var(--sp-4);
- cursor: pointer;
- &__text {
- display: flex;
- flex-direction: column;
- gap: var(--sp-1);
- min-width: 0;
- }
- &__label {
- font-size: var(--fs-base);
- font-weight: 600;
- color: var(--text-primary);
- }
- &__desc {
- font-size: var(--fs-2xs);
- color: var(--text-muted);
- }
- &__switch {
- position: relative;
- flex-shrink: 0;
- width: 44px;
- height: 24px;
- input {
- position: absolute;
- inset: 0;
- z-index: 1;
- margin: 0;
- opacity: 0;
- cursor: pointer;
- &:disabled {
- cursor: not-allowed;
- }
- }
- }
- &__slider {
- position: absolute;
- inset: 0;
- background: var(--bg-subtle);
- border: 1px solid var(--border-strong);
- transition: background 0.15s ease, border-color 0.15s ease;
- &::before {
- content: '';
- position: absolute;
- top: 2px;
- left: 2px;
- width: 18px;
- height: 18px;
- background: var(--text-muted);
- transition: transform 0.15s ease, background 0.15s ease;
- }
- }
- input:checked + &__slider {
- background: var(--az-accent);
- border-color: var(--az-accent);
- &::before {
- transform: translateX(20px);
- background: var(--btn-primary-text);
- }
- }
- input:focus-visible + &__slider {
- outline: 2px solid var(--az-accent);
- outline-offset: 2px;
- }
- }
- // ── 채팅 팝업 창(/chat-popup) 래퍼 — 전체 뷰포트 ──
- .chat-popup {
- display: flex;
- height: 100vh;
- height: 100dvh;
- }
|