@xhub-short/ui 0.1.0-beta.1 → 0.1.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CommentSheet.css-BeCrEaUG.d.ts +221 -0
- package/dist/{chunk-2PTMP65P.js → chunk-2FSDVYER.js} +8 -9
- package/dist/{chunk-WKX2WBVO.js → chunk-3XPJHUYL.js} +1 -39
- package/dist/{chunk-ANGBSV7L.js → chunk-AC2IFAJR.js} +10 -5
- package/dist/{chunk-4YDIRPIN.js → chunk-ANCP53F3.js} +3 -3
- package/dist/chunk-AQHD6LPS.js +430 -0
- package/dist/{chunk-HW4LXTFT.js → chunk-CL6BS7GB.js} +7 -5
- package/dist/{chunk-YW23IBKF.js → chunk-ECR42RKK.js} +46 -5
- package/dist/chunk-EDWS2IPH.js +1 -0
- package/dist/chunk-FNXTPQ6L.js +2573 -0
- package/dist/{chunk-DHQJBXQW.js → chunk-KWHMZ6H5.js} +1 -1
- package/dist/{chunk-UXMA4KJZ.js → chunk-RMLTPW5S.js} +3 -2
- package/dist/{chunk-SSJDO24Q.js → chunk-SZXFH334.js} +1 -1
- package/dist/{chunk-4MN72OZH.js → chunk-UNV3NWN6.js} +4 -4
- package/dist/{chunk-ZZDQKP4R.js → chunk-WCRDTBCZ.js} +94 -155
- package/dist/{chunk-XAOEHLOX.js → chunk-XDIH66C4.js} +245 -52
- package/dist/components/ActionBar/index.js +1 -1
- package/dist/components/AuthorInfo/index.d.ts +5 -1
- package/dist/components/AuthorInfo/index.js +1 -1
- package/dist/components/BlurhashPlaceholder/index.d.ts +67 -0
- package/dist/components/BlurhashPlaceholder/index.js +150 -0
- package/dist/components/CommentSheet/index.d.ts +164 -0
- package/dist/components/CommentSheet/index.js +1 -0
- package/dist/components/ErrorBoundary/index.js +1 -1
- package/dist/components/OfflineIndicator/index.d.ts +56 -0
- package/dist/components/OfflineIndicator/index.js +151 -0
- package/dist/components/ProgressBar/index.d.ts +30 -2
- package/dist/components/ProgressBar/index.js +1 -1
- package/dist/components/Skeleton/index.js +1 -1
- package/dist/components/SubtitleDisplay/index.d.ts +94 -0
- package/dist/components/SubtitleDisplay/index.js +165 -0
- package/dist/components/VideoFeed/index.d.ts +11 -0
- package/dist/components/VideoFeed/index.js +1 -1
- package/dist/components/VideoInfo/index.js +1 -1
- package/dist/components/VideoPlayer/index.d.ts +14 -41
- package/dist/components/VideoPlayer/index.js +1 -1
- package/dist/components/VideoSlot/index.d.ts +124 -64
- package/dist/components/VideoSlot/index.js +1 -1
- package/dist/components/VirtualSlider/index.d.ts +339 -0
- package/dist/components/VirtualSlider/index.js +1 -0
- package/dist/components/icons/index.js +1 -1
- package/dist/index.d.ts +76 -93
- package/dist/index.js +75 -27
- package/package.json +53 -8
- package/dist/use-gesture-react.esm-3SV4QLEJ.js +0 -1893
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import react__default, { ReactElement, ReactNode } from 'react';
|
|
3
|
+
import { CommentItem, UICommentState, UICommentActions, CommentConfig } from '@xhub-short/contracts';
|
|
4
|
+
|
|
5
|
+
interface CommentInputProps {
|
|
6
|
+
/** Placeholder text */
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
/** Quick emojis */
|
|
9
|
+
emojis?: string[];
|
|
10
|
+
/** Max input length */
|
|
11
|
+
maxLength?: number;
|
|
12
|
+
/** Custom class */
|
|
13
|
+
className?: string;
|
|
14
|
+
/** On submit callback */
|
|
15
|
+
onSubmitSuccess?: () => void;
|
|
16
|
+
/** On media button click */
|
|
17
|
+
onMediaClick?: () => void;
|
|
18
|
+
/** Reply to text (default: "Replying to") */
|
|
19
|
+
replyingToText?: string;
|
|
20
|
+
/** Reply placeholder template (default: "Reply to @{name}...") - {name} will be replaced */
|
|
21
|
+
replyPlaceholderTemplate?: string;
|
|
22
|
+
/** Cancel reply aria-label (default: "Cancel reply") */
|
|
23
|
+
cancelReplyAriaLabel?: string;
|
|
24
|
+
/** Add media aria-label (default: "Add media") */
|
|
25
|
+
addMediaAriaLabel?: string;
|
|
26
|
+
/** Submit comment aria-label (default: "Submit comment") */
|
|
27
|
+
submitAriaLabel?: string;
|
|
28
|
+
/** Open emoji aria-label (default: "Open emoji") */
|
|
29
|
+
emojiAriaLabel?: string;
|
|
30
|
+
/** Emoji button aria-label template (default: "Add {emoji}") */
|
|
31
|
+
addEmojiAriaLabel?: string;
|
|
32
|
+
}
|
|
33
|
+
declare const CommentInput: react.NamedExoticComponent<CommentInputProps>;
|
|
34
|
+
|
|
35
|
+
interface CommentItemProps {
|
|
36
|
+
comment: CommentItem;
|
|
37
|
+
className?: string;
|
|
38
|
+
}
|
|
39
|
+
declare const CommentItemComponent: react.NamedExoticComponent<CommentItemProps>;
|
|
40
|
+
|
|
41
|
+
interface CommentListProps {
|
|
42
|
+
/** Custom empty state */
|
|
43
|
+
emptyState?: ReactElement;
|
|
44
|
+
/** Custom loading state */
|
|
45
|
+
loadingState?: ReactElement;
|
|
46
|
+
/** Custom error state */
|
|
47
|
+
errorState?: (error: Error, retry: () => void) => ReactElement;
|
|
48
|
+
/** Custom class */
|
|
49
|
+
className?: string;
|
|
50
|
+
/** Error text (default: "Failed to load comments") */
|
|
51
|
+
errorText?: string;
|
|
52
|
+
/** Retry button text (default: "Try again") */
|
|
53
|
+
retryText?: string;
|
|
54
|
+
/** Empty state text (default: "No comments yet. Be the first!") */
|
|
55
|
+
emptyText?: string;
|
|
56
|
+
/** Load more button text (default: "Load more comments") */
|
|
57
|
+
loadMoreText?: string;
|
|
58
|
+
}
|
|
59
|
+
declare const CommentList: react.NamedExoticComponent<CommentListProps>;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* i18n strings for CommentSheet internal components
|
|
63
|
+
*/
|
|
64
|
+
interface CommentSheetI18n {
|
|
65
|
+
/** Text for "See more" button (default: "See more") */
|
|
66
|
+
expandText?: string;
|
|
67
|
+
/** Text for "See less" button (default: "See less") */
|
|
68
|
+
collapseText?: string;
|
|
69
|
+
/** Text for view replies - use {count} placeholder (default: "View {count} more replies") */
|
|
70
|
+
viewRepliesText?: string;
|
|
71
|
+
/** Text for hide replies (default: "Hide replies") */
|
|
72
|
+
hideRepliesText?: string;
|
|
73
|
+
/** Text for load replies (default: "Load replies") */
|
|
74
|
+
loadRepliesText?: string;
|
|
75
|
+
/** Text for view more replies (default: "View more replies") */
|
|
76
|
+
viewMoreRepliesText?: string;
|
|
77
|
+
/** Function to format relative time */
|
|
78
|
+
formatRelativeTime?: (dateStr: string) => string;
|
|
79
|
+
/** Text for delete menu option (default: "Delete") */
|
|
80
|
+
deleteText?: string;
|
|
81
|
+
/** Text for edit menu option (default: "Edit") */
|
|
82
|
+
editText?: string;
|
|
83
|
+
/** Text for report menu option (default: "Report") */
|
|
84
|
+
reportText?: string;
|
|
85
|
+
/** Delete confirmation title (default: "Delete comment?") */
|
|
86
|
+
deleteConfirmTitle?: string;
|
|
87
|
+
/** Delete confirmation message (default: "This action cannot be undone.") */
|
|
88
|
+
deleteConfirmMessage?: string;
|
|
89
|
+
/** Delete confirm button (default: "Delete") */
|
|
90
|
+
deleteConfirmButton?: string;
|
|
91
|
+
/** Cancel button (default: "Cancel") */
|
|
92
|
+
cancelButton?: string;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* CommentSheet context value
|
|
96
|
+
*/
|
|
97
|
+
interface CommentSheetContextValue {
|
|
98
|
+
/** Comment state */
|
|
99
|
+
state: UICommentState;
|
|
100
|
+
/** Comment actions */
|
|
101
|
+
actions: UICommentActions;
|
|
102
|
+
/** Video ID */
|
|
103
|
+
videoId: string;
|
|
104
|
+
/** Config */
|
|
105
|
+
config: CommentConfig;
|
|
106
|
+
/** Whether sheet is open */
|
|
107
|
+
isOpen: boolean;
|
|
108
|
+
/** Close sheet */
|
|
109
|
+
onClose: () => void;
|
|
110
|
+
/** Reply target (when replying to a comment) */
|
|
111
|
+
replyTarget: ReplyTarget | null;
|
|
112
|
+
/** Set reply target */
|
|
113
|
+
setReplyTarget: (target: ReplyTarget | null) => void;
|
|
114
|
+
/** Initial count from video data (used before API loads) */
|
|
115
|
+
initialCount?: number;
|
|
116
|
+
/** i18n strings for internal components */
|
|
117
|
+
i18n: CommentSheetI18n;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Reply target info
|
|
121
|
+
*/
|
|
122
|
+
interface ReplyTarget {
|
|
123
|
+
/** Parent comment ID */
|
|
124
|
+
commentId: string;
|
|
125
|
+
/** Author name for @mention */
|
|
126
|
+
authorName: string;
|
|
127
|
+
/** Author ID */
|
|
128
|
+
authorId: string;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* CommentSheet context
|
|
132
|
+
*/
|
|
133
|
+
declare const CommentSheetContext: react.Context<CommentSheetContextValue | undefined>;
|
|
134
|
+
/**
|
|
135
|
+
* Hook to use CommentSheet context
|
|
136
|
+
* @throws if used outside of CommentSheetHeadless
|
|
137
|
+
*/
|
|
138
|
+
declare function useCommentSheetContext(): CommentSheetContextValue;
|
|
139
|
+
/**
|
|
140
|
+
* Hook to optionally use CommentSheet context
|
|
141
|
+
* @returns context or undefined if not within CommentSheetHeadless
|
|
142
|
+
*/
|
|
143
|
+
declare function useOptionalCommentSheetContext(): CommentSheetContextValue | undefined;
|
|
144
|
+
|
|
145
|
+
interface SheetHeaderProps {
|
|
146
|
+
/** Custom title label (default: "Comments") */
|
|
147
|
+
titleLabel?: string;
|
|
148
|
+
/** Show drag handle */
|
|
149
|
+
showHandle?: boolean;
|
|
150
|
+
/** Show sort button */
|
|
151
|
+
showSort?: boolean;
|
|
152
|
+
/** Sort click handler */
|
|
153
|
+
onSortClick?: () => void;
|
|
154
|
+
/** Custom close icon */
|
|
155
|
+
closeIcon?: ReactElement;
|
|
156
|
+
/** Custom class */
|
|
157
|
+
className?: string;
|
|
158
|
+
/** Sort button aria-label (default: "Sort comments") */
|
|
159
|
+
sortAriaLabel?: string;
|
|
160
|
+
/** Close button aria-label (default: "Close comments") */
|
|
161
|
+
closeAriaLabel?: string;
|
|
162
|
+
}
|
|
163
|
+
declare const SheetHeader: react__default.NamedExoticComponent<SheetHeaderProps>;
|
|
164
|
+
|
|
165
|
+
interface CommentSheetHeadlessProps {
|
|
166
|
+
/** Whether sheet is open */
|
|
167
|
+
isOpen: boolean;
|
|
168
|
+
/** Close callback */
|
|
169
|
+
onClose: () => void;
|
|
170
|
+
/** Video ID for comments */
|
|
171
|
+
videoId: string;
|
|
172
|
+
/** Comment state from SDK */
|
|
173
|
+
state: UICommentState;
|
|
174
|
+
/** Comment actions from SDK */
|
|
175
|
+
actions: UICommentActions;
|
|
176
|
+
/** Config */
|
|
177
|
+
config?: Partial<CommentConfig>;
|
|
178
|
+
/** Initial count from video data (displayed before API loads) */
|
|
179
|
+
initialCount?: number;
|
|
180
|
+
/** Custom children (compound pattern) */
|
|
181
|
+
children?: ReactNode;
|
|
182
|
+
/** Root class name */
|
|
183
|
+
className?: string;
|
|
184
|
+
/** Backdrop class name */
|
|
185
|
+
backdropClassName?: string;
|
|
186
|
+
/** Close on backdrop click */
|
|
187
|
+
closeOnBackdropClick?: boolean;
|
|
188
|
+
/** Close on escape key */
|
|
189
|
+
closeOnEscape?: boolean;
|
|
190
|
+
/** Enable drag-to-dismiss */
|
|
191
|
+
enableDragToDismiss?: boolean;
|
|
192
|
+
/** Drag threshold to close (px) */
|
|
193
|
+
dragCloseThreshold?: number;
|
|
194
|
+
/** i18n strings for internal components (CommentItem, etc.) */
|
|
195
|
+
i18n?: CommentSheetI18n;
|
|
196
|
+
}
|
|
197
|
+
declare const CommentSheetHeadless: react.NamedExoticComponent<CommentSheetHeadlessProps>;
|
|
198
|
+
declare const CommentSheet: react.NamedExoticComponent<CommentSheetHeadlessProps> & {
|
|
199
|
+
Header: react.NamedExoticComponent<SheetHeaderProps>;
|
|
200
|
+
List: react.NamedExoticComponent<CommentListProps>;
|
|
201
|
+
Input: react.NamedExoticComponent<CommentInputProps>;
|
|
202
|
+
Item: react.NamedExoticComponent<CommentItemProps>;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* CommentSheet CSS
|
|
207
|
+
*
|
|
208
|
+
* Modern bottom sheet for comments (Light Theme)
|
|
209
|
+
* Based on Figma design: https://figma.com/design/Kd1lJUJ4B3Kuw3dV9UcUok
|
|
210
|
+
* Features:
|
|
211
|
+
* - Light theme with clean aesthetics
|
|
212
|
+
* - Slide-up animation
|
|
213
|
+
* - Backdrop with click-to-close
|
|
214
|
+
* - Keyboard-aware input positioning
|
|
215
|
+
* - Scrollable comment list
|
|
216
|
+
* - Pinned comment support
|
|
217
|
+
* - Vertical reply thread lines
|
|
218
|
+
*/
|
|
219
|
+
declare const COMMENT_SHEET_CSS = "\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n CSS VARIABLES (Light Theme)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n:root {\n /* Primary colors */\n --sv-comment-primary: #164d8e;\n --sv-comment-primary-light: #1354ae;\n --sv-comment-primary-dark: #003477;\n \n /* Contrast colors */\n --sv-comment-bg: #ffffff;\n --sv-comment-text: #121212;\n --sv-comment-text-secondary: #6b7271;\n --sv-comment-border: rgba(18, 18, 18, 0.08);\n \n /* Accent colors */\n --sv-comment-like-color: #ff434e;\n --sv-comment-verified-color: #1ea031;\n --sv-comment-mention-color: #164d8e;\n \n /* Component specific */\n --sv-comment-avatar-bg: #e5e6e6;\n --sv-comment-input-border: #a3a3a3;\n --sv-comment-reply-line: #e5e6e6;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n BACKDROP & CONTAINER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-comment-sheet-backdrop {\n position: fixed;\n inset: 0;\n background: var(--sv-comment-backdrop-bg, rgba(0, 0, 0, 0.5));\n z-index: var(--sv-comment-sheet-z-index, 1000);\n opacity: 0;\n visibility: hidden;\n pointer-events: none;\n transition: opacity var(--sv-comment-animation-duration, 400ms) ease,\n visibility 0s linear var(--sv-comment-animation-duration, 400ms);\n}\n\n.sv-comment-sheet-backdrop--open {\n opacity: 1;\n visibility: visible;\n pointer-events: auto;\n transition: opacity var(--sv-comment-animation-duration, 400ms) ease,\n visibility 0s linear 0s;\n}\n\n/* Keyframes for slide animations */\n@keyframes sv-sheet-slide-up {\n from { transform: translateY(100%); }\n to { transform: translateY(0); }\n}\n\n@keyframes sv-sheet-slide-down {\n from { transform: translateY(0); }\n to { transform: translateY(100%); }\n}\n\n.sv-comment-sheet {\n position: fixed;\n margin: 16px;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--sv-comment-bg, #ffffff);\n border-radius: var(--sv-comment-sheet-radius, 24px);\n z-index: var(--sv-comment-sheet-z-index, 1001);\n display: flex;\n flex-direction: column;\n max-height: var(--sv-comment-sheet-height, 55vh);\n transform: translateY(100%);\n overflow: hidden;\n touch-action: pan-y;\n isolation: isolate;\n pointer-events: none;\n will-change: transform;\n}\n\n.sv-comment-sheet--open {\n transform: translateY(0);\n pointer-events: auto;\n animation: sv-sheet-slide-up var(--sv-comment-animation-duration, 400ms) \n var(--sv-comment-animation-easing, cubic-bezier(0.32, 0.72, 0, 1)) forwards;\n}\n\n.sv-comment-sheet--open.sv-comment-sheet--closing {\n pointer-events: none;\n animation: sv-sheet-slide-down var(--sv-comment-animation-duration, 400ms) \n var(--sv-comment-animation-easing, cubic-bezier(0.32, 0.72, 0, 1)) forwards !important;\n}\n\n/* CRITICAL: Disable VirtualSlider/VideoFeed swipe when CommentSheet is open */\nbody.sv-comment-sheet-open .sv-slider,\nbody.sv-comment-sheet-open .sv-video-feed {\n pointer-events: none !important;\n touch-action: none !important;\n}\n\nbody.sv-comment-sheet-open .sv-comment-sheet,\nbody.sv-comment-sheet-open .sv-comment-sheet-backdrop {\n touch-action: auto !important;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n HEADER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-comment-sheet__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--sv-comment-border);\n flex-shrink: 0;\n position: relative;\n cursor: grab;\n touch-action: none;\n}\n\n.sv-comment-sheet__header:active {\n cursor: grabbing;\n}\n\n.sv-comment-sheet__header-handle {\n position: absolute;\n top: 8px;\n left: 50%;\n transform: translateX(-50%);\n width: 36px;\n height: 4px;\n background: var(--sv-comment-text-secondary);\n border-radius: 2px;\n opacity: 0.3;\n}\n\n.sv-comment-sheet__header-left {\n display: flex;\n align-items: center;\n gap: 2px;\n}\n\n.sv-comment-sheet__title {\n font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 18px;\n font-weight: 600;\n line-height: 1.4;\n color: var(--sv-comment-text);\n opacity: 0.9;\n margin: 0;\n}\n\n.sv-comment-sheet__sort-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n color: var(--sv-comment-text);\n}\n\n.sv-comment-sheet__sort-btn svg {\n width: 20px;\n height: 20px;\n}\n\n.sv-comment-sheet__close-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n border: none;\n border-radius: 100px;\n background: linear-gradient(180deg, var(--sv-comment-primary-light) 0%, var(--sv-comment-primary-dark) 100%);\n cursor: pointer;\n transition: opacity 0.15s ease;\n}\n\n.sv-comment-sheet__close-btn:hover {\n opacity: 0.9;\n}\n\n.sv-comment-sheet__close-btn svg {\n width: 20px;\n height: 20px;\n color: #ffffff;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n COMMENT LIST\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-comment-sheet__list {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 8px 16px 28px 16px;\n -webkit-overflow-scrolling: touch;\n overscroll-behavior: contain;\n touch-action: pan-y;\n}\n\n.sv-comment-sheet__list::-webkit-scrollbar {\n width: 0px;\n}\n\n.sv-comment-sheet__list::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.0);\n border-radius: 0px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n COMMENT ITEM\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-comment-item {\n display: flex;\n gap: 6px;\n padding: 16px 0;\n position: relative;\n}\n\n.sv-comment-item--pending {\n opacity: 0.6;\n}\n\n.sv-comment-item--pinned {\n background: var(--sv-comment-bg);\n}\n\n.sv-comment-item__avatar {\n width: 40px;\n height: 40px;\n border-radius: 120px;\n flex-shrink: 0;\n object-fit: cover;\n background: var(--sv-comment-avatar-bg);\n}\n\n.sv-comment-item__content {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.sv-comment-item__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 4px;\n}\n\n.sv-comment-item__header-left {\n display: flex;\n align-items: center;\n gap: 4px;\n min-width: 0;\n}\n\n.sv-comment-item__pin-icon {\n width: 16px;\n height: 16px;\n flex-shrink: 0;\n color: var(--sv-comment-primary);\n}\n\n.sv-comment-item__author {\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 14px;\n font-weight: 600;\n line-height: 1.4;\n color: var(--sv-comment-text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.sv-comment-item__verified {\n width: 12px;\n height: 12px;\n flex-shrink: 0;\n color: var(--sv-comment-verified-color);\n}\n\n.sv-comment-item__badge {\n font-size: 10px;\n padding: 2px 6px;\n background: var(--sv-comment-primary);\n color: #ffffff;\n border-radius: 4px;\n flex-shrink: 0;\n}\n\n.sv-comment-item__menu-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n color: var(--sv-comment-text-secondary);\n}\n\n.sv-comment-item__menu-btn svg {\n width: 20px;\n height: 20px;\n}\n\n.sv-comment-item__text {\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 12px;\n font-weight: 400;\n line-height: 1.4;\n color: var(--sv-comment-text);\n word-break: break-word;\n margin: 0;\n padding-right: 16px;\n}\n\n/* Text collapse */\n.sv-comment-item__text--collapsed {\n display: -webkit-box;\n -webkit-line-clamp: var(--sv-comment-max-lines, 3);\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.sv-comment-item__expand-btn {\n background: none;\n border: none;\n padding: 0;\n font-size: 12px;\n color: var(--sv-comment-text-secondary);\n cursor: pointer;\n margin-top: 4px;\n}\n\n.sv-comment-item__expand-btn:hover {\n color: var(--sv-comment-text);\n}\n\n/* Actions row */\n.sv-comment-item__actions {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.sv-comment-item__time {\n font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 12px;\n font-weight: 500;\n line-height: 1.2;\n color: var(--sv-comment-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.sv-comment-item__action-btn {\n display: flex;\n align-items: center;\n gap: 4px;\n background: none;\n border: none;\n padding: 0;\n font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 12px;\n font-weight: 500;\n line-height: 1.2;\n color: var(--sv-comment-text-secondary);\n cursor: pointer;\n transition: color 0.15s ease;\n}\n\n.sv-comment-item__action-btn:hover {\n color: var(--sv-comment-text);\n}\n\n.sv-comment-item__action-btn--active {\n color: var(--sv-comment-like-color);\n}\n\n.sv-comment-item__action-btn--active:hover {\n color: var(--sv-comment-like-color);\n}\n\n.sv-comment-item__action-icon {\n width: 20px;\n height: 20px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n REPLIES\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-comment-replies {\n margin-top: 12px;\n position: relative;\n}\n\n/* Vertical connecting line */\n.sv-comment-item--has-replies::before {\n content: '';\n position: absolute;\n left: 20px;\n top: 56px;\n bottom: 0;\n width: 1px;\n background: var(--sv-comment-reply-line);\n}\n\n.sv-comment-replies__toggle {\n display: flex;\n align-items: center;\n gap: 0;\n background: none;\n border: none;\n padding: 4px 0;\n cursor: pointer;\n}\n\n.sv-comment-replies__toggle-line {\n width: 24px;\n height: 1px;\n background: #a3a3a3;\n margin-right: 0;\n}\n\n.sv-comment-replies__toggle-text {\n font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 13px;\n font-weight: 600;\n line-height: 1.4;\n color: var(--sv-comment-text-secondary);\n white-space: nowrap;\n}\n\n.sv-comment-replies__toggle-icon {\n width: 20px;\n height: 20px;\n color: var(--sv-comment-text-secondary);\n}\n\n.sv-comment-replies__list {\n margin-top: 12px;\n}\n\n.sv-comment-reply {\n display: flex;\n gap: 6px;\n padding: 0 0 12px 0;\n position: relative;\n}\n\n.sv-comment-reply__avatar {\n width: 24px;\n height: 24px;\n border-radius: 100px;\n flex-shrink: 0;\n object-fit: cover;\n background: var(--sv-comment-avatar-bg);\n}\n\n.sv-comment-reply__mention {\n color: var(--sv-comment-mention-color);\n font-weight: 500;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n INPUT AREA\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-comment-sheet__input-area {\n padding: 0 16px 36px 16px;\n flex-shrink: 0;\n}\n\n/* Guest mode - login prompt instead of input */\n.sv-comment-input-guest {\n padding: 16px;\n border-top: 1px solid var(--sv-comment-border);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n background: var(--sv-comment-bg);\n color: var(--sv-comment-primary);\n font-weight: 600;\n font-size: 14px;\n width: 100%;\n transition: background 0.15s ease;\n}\n\n.sv-comment-input-guest:hover {\n background: rgba(22, 77, 142, 0.05);\n}\n\n.sv-comment-input-guest:active {\n background: rgba(22, 77, 142, 0.1);\n}\n\n.sv-comment-sheet__reply-to {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 4px 0;\n margin-bottom: 8px;\n font-size: 12px;\n color: var(--sv-comment-text-secondary);\n}\n\n.sv-comment-sheet__reply-to-author-name {\n font-size: 12px;\n color: var(--sv-comment-text);\n font-weight: 500;\n}\n\n.sv-comment-sheet__reply-to-clear {\n background: none;\n border: none;\n padding: 4px;\n color: var(--sv-comment-text-secondary);\n cursor: pointer;\n font-size: 12px;\n}\n\n.sv-comment-sheet__input-wrapper {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 44px;\n padding: 16px;\n background: var(--sv-comment-bg);\n border: 1px solid var(--sv-comment-input-border);\n border-radius: 12px;\n backdrop-filter: blur(50px);\n}\n\n.sv-comment-sheet__input-left {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n}\n\n.sv-comment-sheet__media-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n flex-shrink: 0;\n}\n\n.sv-comment-sheet__media-btn svg {\n width: 20px;\n height: 20px;\n}\n\n.sv-comment-sheet__input {\n flex: 1;\n background: none;\n border: none;\n outline: none;\n resize: none;\n font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 12px;\n font-style: italic;\n font-weight: 400;\n line-height: 1.4;\n color: var(--sv-comment-text);\n padding: 0;\n min-width: 0;\n}\n\n.sv-comment-sheet__input::placeholder {\n color: var(--sv-comment-text-secondary);\n}\n\n.sv-comment-sheet__input:not(:placeholder-shown) {\n font-style: normal;\n}\n\n.sv-comment-sheet__emoji-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n flex-shrink: 0;\n}\n\n.sv-comment-sheet__emoji-btn svg {\n width: 20px;\n height: 20px;\n color: var(--sv-comment-primary);\n}\n\n/* Hidden emoji bar (can be toggled) */\n.sv-comment-sheet__emoji-bar {\n display: none;\n gap: 8px;\n padding: 8px 0;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n.sv-comment-sheet__emoji-bar--visible {\n display: flex;\n}\n\n.sv-comment-sheet__emoji-bar::-webkit-scrollbar {\n display: none;\n}\n\n.sv-comment-sheet__emoji-bar-btn {\n background: none;\n border: none;\n padding: 4px;\n font-size: 20px;\n cursor: pointer;\n border-radius: 4px;\n transition: background 0.15s ease;\n}\n\n.sv-comment-sheet__emoji-bar-btn:hover {\n background: rgba(0, 0, 0, 0.05);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n STATES\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-comment-sheet__loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 32px;\n color: var(--sv-comment-text-secondary);\n}\n\n.sv-comment-sheet__loading-spinner {\n width: 24px;\n height: 24px;\n border: 2px solid rgba(0, 0, 0, 0.1);\n border-top-color: var(--sv-comment-primary);\n border-radius: 50%;\n animation: sv-comment-spin 0.8s linear infinite;\n}\n\n@keyframes sv-comment-spin {\n to { transform: rotate(360deg); }\n}\n\n.sv-comment-sheet__empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 32px;\n text-align: center;\n}\n\n.sv-comment-sheet__empty-icon {\n font-size: 48px;\n margin-bottom: 12px;\n}\n\n.sv-comment-sheet__empty-text {\n color: var(--sv-comment-text-secondary);\n font-size: 14px;\n}\n\n.sv-comment-sheet__error {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 32px;\n text-align: center;\n color: var(--sv-comment-like-color);\n}\n\n.sv-comment-sheet__error-btn {\n margin-top: 12px;\n padding: 8px 16px;\n background: rgba(0, 0, 0, 0.05);\n border: none;\n border-radius: 8px;\n color: var(--sv-comment-text);\n cursor: pointer;\n}\n\n/* Load more */\n.sv-comment-sheet__load-more {\n display: flex;\n justify-content: center;\n padding: 12px;\n}\n\n.sv-comment-sheet__load-more-btn {\n background: none;\n border: none;\n padding: 8px 16px;\n color: var(--sv-comment-text-secondary);\n cursor: pointer;\n font-size: 13px;\n}\n\n.sv-comment-sheet__load-more-btn:hover {\n color: var(--sv-comment-text);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n COMMENT MENU (Dropdown)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-comment-menu {\n position: relative;\n}\n\n.sv-comment-menu__trigger {\n display: flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n padding: 4px;\n cursor: pointer;\n color: var(--sv-comment-text-secondary);\n border-radius: 4px;\n transition: background 0.15s ease;\n}\n\n.sv-comment-menu__trigger:hover {\n background: rgba(0, 0, 0, 0.05);\n}\n\n.sv-comment-menu__icon {\n width: 20px;\n height: 20px;\n}\n\n.sv-comment-menu__dropdown {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n min-width: 140px;\n background: var(--sv-comment-bg);\n border: 1px solid var(--sv-comment-border);\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n z-index: 10;\n overflow: hidden;\n animation: sv-menu-fade-in 0.15s ease;\n}\n\n@keyframes sv-menu-fade-in {\n from { opacity: 0; transform: translateY(-4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.sv-comment-menu__item {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 10px 12px;\n background: none;\n border: none;\n cursor: pointer;\n font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 14px;\n font-weight: 500;\n color: var(--sv-comment-text);\n text-align: left;\n transition: background 0.15s ease;\n}\n\n.sv-comment-menu__item:hover {\n background: rgba(0, 0, 0, 0.05);\n}\n\n.sv-comment-menu__item--danger {\n color: var(--sv-comment-like-color);\n}\n\n.sv-comment-menu__item--danger:hover {\n background: rgba(255, 67, 78, 0.08);\n}\n\n.sv-comment-menu__item-icon {\n width: 18px;\n height: 18px;\n flex-shrink: 0;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n DELETE CONFIRMATION DIALOG\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-comment-dialog-overlay {\n position: fixed;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.5);\n z-index: var(--sv-comment-modal-z-index, 1100);\n animation: sv-dialog-overlay-fade-in 0.2s ease;\n}\n\n@keyframes sv-dialog-overlay-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.sv-comment-dialog {\n background: var(--sv-comment-bg);\n border-radius: 16px;\n padding: 24px;\n max-width: 300px;\n width: calc(100% - 48px);\n text-align: center;\n animation: sv-dialog-scale-in 0.2s ease;\n}\n\n@keyframes sv-dialog-scale-in {\n from { opacity: 0; transform: scale(0.95); }\n to { opacity: 1; transform: scale(1); }\n}\n\n.sv-comment-dialog__title {\n font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 17px;\n font-weight: 600;\n color: var(--sv-comment-text);\n margin: 0 0 8px 0;\n}\n\n.sv-comment-dialog__message {\n font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 14px;\n color: var(--sv-comment-text-secondary);\n margin: 0 0 20px 0;\n line-height: 1.4;\n}\n\n.sv-comment-dialog__actions {\n display: flex;\n gap: 12px;\n}\n\n.sv-comment-dialog__btn {\n flex: 1;\n padding: 12px 16px;\n border: none;\n border-radius: 10px;\n font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 15px;\n font-weight: 600;\n cursor: pointer;\n transition: opacity 0.15s ease;\n}\n\n.sv-comment-dialog__btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.sv-comment-dialog__btn--cancel {\n background: rgba(0, 0, 0, 0.06);\n color: var(--sv-comment-text);\n}\n\n.sv-comment-dialog__btn--cancel:hover:not(:disabled) {\n background: rgba(0, 0, 0, 0.1);\n}\n\n.sv-comment-dialog__btn--danger {\n background: var(--sv-comment-like-color);\n color: #ffffff;\n}\n\n.sv-comment-dialog__btn--danger:hover:not(:disabled) {\n opacity: 0.9;\n}\n\n/* Legacy classes (keep for backwards compatibility) */\n.sv-comment-delete-confirm {\n position: fixed;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.5);\n z-index: var(--sv-comment-modal-z-index, 1100);\n}\n\n.sv-comment-delete-confirm__dialog {\n background: var(--sv-comment-bg);\n border-radius: 12px;\n padding: 16px;\n max-width: 280px;\n text-align: center;\n}\n\n.sv-comment-delete-confirm__title {\n font-size: 16px;\n font-weight: 600;\n color: var(--sv-comment-text);\n margin-bottom: 8px;\n}\n\n.sv-comment-delete-confirm__text {\n font-size: 14px;\n color: var(--sv-comment-text-secondary);\n margin-bottom: 16px;\n}\n\n.sv-comment-delete-confirm__actions {\n display: flex;\n gap: 8px;\n}\n\n.sv-comment-delete-confirm__btn {\n flex: 1;\n padding: 8px 12px;\n border: none;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.sv-comment-delete-confirm__btn--cancel {\n background: rgba(0, 0, 0, 0.05);\n color: var(--sv-comment-text);\n}\n\n.sv-comment-delete-confirm__btn--delete {\n background: var(--sv-comment-like-color);\n color: #ffffff;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n SKELETON LOADING\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n@keyframes sv-skeleton-shimmer {\n 0% { background-position: -200% 0; }\n 100% { background-position: 200% 0; }\n}\n\n.sv-comment-skeleton-list {\n display: flex;\n flex-direction: column;\n}\n\n.sv-comment-skeleton {\n animation: sv-skeleton-fade-in 0.3s ease;\n}\n\n@keyframes sv-skeleton-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.sv-comment-skeleton__avatar {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n background: linear-gradient(\n 90deg,\n rgba(0, 0, 0, 0.04) 25%,\n rgba(0, 0, 0, 0.08) 50%,\n rgba(0, 0, 0, 0.04) 75%\n );\n background-size: 200% 100%;\n animation: sv-skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.sv-comment-skeleton__content {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.sv-comment-skeleton__header {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.sv-comment-skeleton__author {\n width: 80px;\n height: 14px;\n border-radius: 4px;\n background: linear-gradient(\n 90deg,\n rgba(0, 0, 0, 0.04) 25%,\n rgba(0, 0, 0, 0.08) 50%,\n rgba(0, 0, 0, 0.04) 75%\n );\n background-size: 200% 100%;\n animation: sv-skeleton-shimmer 1.5s ease-in-out infinite;\n animation-delay: 0.1s;\n}\n\n.sv-comment-skeleton__time {\n width: 40px;\n height: 12px;\n border-radius: 4px;\n background: linear-gradient(\n 90deg,\n rgba(0, 0, 0, 0.04) 25%,\n rgba(0, 0, 0, 0.08) 50%,\n rgba(0, 0, 0, 0.04) 75%\n );\n background-size: 200% 100%;\n animation: sv-skeleton-shimmer 1.5s ease-in-out infinite;\n animation-delay: 0.15s;\n}\n\n.sv-comment-skeleton__text {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.sv-comment-skeleton__line {\n height: 14px;\n border-radius: 4px;\n background: linear-gradient(\n 90deg,\n rgba(0, 0, 0, 0.04) 25%,\n rgba(0, 0, 0, 0.08) 50%,\n rgba(0, 0, 0, 0.04) 75%\n );\n background-size: 200% 100%;\n animation: sv-skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.sv-comment-skeleton__line--full {\n width: 100%;\n animation-delay: 0.2s;\n}\n\n.sv-comment-skeleton__line--medium {\n width: 65%;\n animation-delay: 0.25s;\n}\n\n.sv-comment-skeleton__actions {\n display: flex;\n align-items: center;\n gap: 16px;\n margin-top: 4px;\n}\n\n.sv-comment-skeleton__action {\n width: 50px;\n height: 12px;\n border-radius: 4px;\n background: linear-gradient(\n 90deg,\n rgba(0, 0, 0, 0.04) 25%,\n rgba(0, 0, 0, 0.08) 50%,\n rgba(0, 0, 0, 0.04) 75%\n );\n background-size: 200% 100%;\n animation: sv-skeleton-shimmer 1.5s ease-in-out infinite;\n animation-delay: 0.3s;\n}\n";
|
|
220
|
+
|
|
221
|
+
export { CommentSheet as C, type ReplyTarget as R, SheetHeader as S, CommentSheetHeadless as a, type CommentSheetHeadlessProps as b, type SheetHeaderProps as c, CommentList as d, type CommentListProps as e, CommentInput as f, type CommentInputProps as g, CommentItemComponent as h, type CommentItemProps as i, CommentSheetContext as j, useOptionalCommentSheetContext as k, type CommentSheetContextValue as l, type CommentSheetI18n as m, COMMENT_SHEET_CSS as n, useCommentSheetContext as u };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PlusIcon } from './chunk-
|
|
2
|
-
import { injectComponentCSS
|
|
1
|
+
import { PlusIcon } from './chunk-ANCP53F3.js';
|
|
2
|
+
import { injectComponentCSS } from './chunk-RMLTPW5S.js';
|
|
3
3
|
import { clsx } from 'clsx';
|
|
4
4
|
import { createContext, useInsertionEffect, useMemo, useState, useEffect, useContext } from 'react';
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -71,7 +71,7 @@ function AuthorAvatar({
|
|
|
71
71
|
tabIndex: handleClick ? 0 : void 0,
|
|
72
72
|
"aria-label": handleClick ? `View ${avatarAlt}'s profile` : void 0,
|
|
73
73
|
children: [
|
|
74
|
-
children ?? (showImage ? /* @__PURE__ */ jsx(
|
|
74
|
+
children ?? (showImage && avatarSrc ? /* @__PURE__ */ jsx(
|
|
75
75
|
"img",
|
|
76
76
|
{
|
|
77
77
|
src: avatarSrc,
|
|
@@ -590,7 +590,9 @@ function FollowButton({
|
|
|
590
590
|
followingText = "Following",
|
|
591
591
|
disabled = false,
|
|
592
592
|
className,
|
|
593
|
-
children
|
|
593
|
+
children,
|
|
594
|
+
followAriaLabel = "Follow",
|
|
595
|
+
unfollowAriaLabel = "Unfollow"
|
|
594
596
|
}) {
|
|
595
597
|
const context = useOptionalAuthorInfoContext();
|
|
596
598
|
const isFollowing = isFollowingProp ?? context?.isFollowing ?? false;
|
|
@@ -634,7 +636,7 @@ function FollowButton({
|
|
|
634
636
|
onTouchEnd: stopPropagation,
|
|
635
637
|
disabled: isDisabled,
|
|
636
638
|
"aria-pressed": isFollowing,
|
|
637
|
-
"aria-label": isFollowing ?
|
|
639
|
+
"aria-label": isFollowing ? unfollowAriaLabel : followAriaLabel,
|
|
638
640
|
"aria-busy": isPending,
|
|
639
641
|
children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
640
642
|
/* @__PURE__ */ jsx(
|
|
@@ -668,10 +670,7 @@ function AuthorInfoHeadlessRoot({
|
|
|
668
670
|
children
|
|
669
671
|
}) {
|
|
670
672
|
useInsertionEffect(() => {
|
|
671
|
-
injectComponentCSS(CSS_COMPONENT_ID, AUTHOR_INFO_CSS);
|
|
672
|
-
return () => {
|
|
673
|
-
removeComponentCSS(CSS_COMPONENT_ID);
|
|
674
|
-
};
|
|
673
|
+
return injectComponentCSS(CSS_COMPONENT_ID, AUTHOR_INFO_CSS);
|
|
675
674
|
}, []);
|
|
676
675
|
const contextValue = useMemo(
|
|
677
676
|
() => ({
|
|
@@ -1,30 +1,3 @@
|
|
|
1
|
-
// src/utils/lazyGesture.ts
|
|
2
|
-
var gestureModule = null;
|
|
3
|
-
var loadPromise = null;
|
|
4
|
-
async function loadGesture() {
|
|
5
|
-
if (gestureModule) {
|
|
6
|
-
return gestureModule;
|
|
7
|
-
}
|
|
8
|
-
if (loadPromise) {
|
|
9
|
-
return loadPromise;
|
|
10
|
-
}
|
|
11
|
-
loadPromise = import('./use-gesture-react.esm-3SV4QLEJ.js').then((mod) => {
|
|
12
|
-
gestureModule = mod;
|
|
13
|
-
return mod;
|
|
14
|
-
}).catch((error) => {
|
|
15
|
-
loadPromise = null;
|
|
16
|
-
throw error;
|
|
17
|
-
});
|
|
18
|
-
return loadPromise;
|
|
19
|
-
}
|
|
20
|
-
function isGestureLoaded() {
|
|
21
|
-
return gestureModule !== null;
|
|
22
|
-
}
|
|
23
|
-
function preloadGesture() {
|
|
24
|
-
loadGesture().catch(() => {
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
1
|
// src/utils/formatCount.ts
|
|
29
2
|
var DEFAULT_SUFFIXES = {
|
|
30
3
|
thousand: "K",
|
|
@@ -83,16 +56,5 @@ function parseFormattedCount(formatted) {
|
|
|
83
56
|
return num;
|
|
84
57
|
}
|
|
85
58
|
}
|
|
86
|
-
function cn(...inputs) {
|
|
87
|
-
return inputs.filter(Boolean).map((input) => {
|
|
88
|
-
if (typeof input === "string") {
|
|
89
|
-
return input;
|
|
90
|
-
}
|
|
91
|
-
if (typeof input === "object" && input !== null) {
|
|
92
|
-
return Object.entries(input).filter(([, value]) => value).map(([key]) => key).join(" ");
|
|
93
|
-
}
|
|
94
|
-
return "";
|
|
95
|
-
}).join(" ").trim();
|
|
96
|
-
}
|
|
97
59
|
|
|
98
|
-
export {
|
|
60
|
+
export { formatCount, formatCountWithSeparators, parseFormattedCount };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { injectComponentCSS } from './chunk-
|
|
1
|
+
import { formatCount } from './chunk-3XPJHUYL.js';
|
|
2
|
+
import { injectComponentCSS } from './chunk-RMLTPW5S.js';
|
|
3
|
+
import { clsx } from 'clsx';
|
|
3
4
|
import { createContext, useInsertionEffect, useState, useRef, useEffect, useCallback, useContext } from 'react';
|
|
4
5
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
6
|
|
|
@@ -339,6 +340,7 @@ function ActionButton({
|
|
|
339
340
|
const handleTouchEnd = useCallback(
|
|
340
341
|
(e) => {
|
|
341
342
|
e.stopPropagation();
|
|
343
|
+
e.preventDefault();
|
|
342
344
|
if (!disabled && onClick) {
|
|
343
345
|
onClick();
|
|
344
346
|
}
|
|
@@ -360,7 +362,7 @@ function ActionButton({
|
|
|
360
362
|
const formattedCount = count !== void 0 ? formatter(count) : null;
|
|
361
363
|
const shouldShowCount = count !== void 0 && (!hideZeroCount || count > 0);
|
|
362
364
|
const displayIcon = isActive && activeIcon ? activeIcon : icon;
|
|
363
|
-
const buttonClasses =
|
|
365
|
+
const buttonClasses = clsx(
|
|
364
366
|
CSS_PREFIX,
|
|
365
367
|
variant !== "default" && `${CSS_PREFIX}--${variant}`,
|
|
366
368
|
type !== "default" && `${CSS_PREFIX}--${type}`,
|
|
@@ -389,7 +391,10 @@ function ActionButton({
|
|
|
389
391
|
shouldShowCount && /* @__PURE__ */ jsx(
|
|
390
392
|
"span",
|
|
391
393
|
{
|
|
392
|
-
className:
|
|
394
|
+
className: clsx(
|
|
395
|
+
`${CSS_PREFIX}__count`,
|
|
396
|
+
!shouldShowCount && `${CSS_PREFIX}__count--hidden`
|
|
397
|
+
),
|
|
393
398
|
children: formattedCount
|
|
394
399
|
}
|
|
395
400
|
)
|
|
@@ -443,7 +448,7 @@ function ActionBarHeadlessRoot({
|
|
|
443
448
|
interactionState,
|
|
444
449
|
interactionActions
|
|
445
450
|
};
|
|
446
|
-
const containerClasses =
|
|
451
|
+
const containerClasses = clsx(
|
|
447
452
|
CSS_PREFIX2,
|
|
448
453
|
direction === "horizontal" && `${CSS_PREFIX2}--horizontal`,
|
|
449
454
|
className
|
|
@@ -110,10 +110,10 @@ function BookmarkFilledIcon(props) {
|
|
|
110
110
|
) });
|
|
111
111
|
}
|
|
112
112
|
function PlayIcon(props) {
|
|
113
|
-
return /* @__PURE__ */ jsx("svg", {
|
|
113
|
+
return /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", xmlns: "http://www.w3.org/2000/svg", fill: "none", ...getIconProps(props), children: /* @__PURE__ */ jsx(
|
|
114
114
|
"path",
|
|
115
115
|
{
|
|
116
|
-
d: "
|
|
116
|
+
d: "M9.92196 2.01322C7.19974 0.436195 3.79175 2.40044 3.79175 5.54647V22.4486C3.79175 25.5946 7.19974 27.5588 9.92195 25.9818L24.5099 17.5308C27.2252 15.9578 27.2252 12.0373 24.5099 10.4643L9.92196 2.01322Z",
|
|
117
117
|
fill: "currentColor"
|
|
118
118
|
}
|
|
119
119
|
) });
|
|
@@ -122,7 +122,7 @@ function PauseIcon(props) {
|
|
|
122
122
|
return /* @__PURE__ */ jsx("svg", { ...getIconProps(props), "aria-hidden": "true", children: /* @__PURE__ */ jsx(
|
|
123
123
|
"path",
|
|
124
124
|
{
|
|
125
|
-
d: "
|
|
125
|
+
d: "M24.2096 4.20016V23.8002C24.2096 24.5422 24.2096 24.9902 23.9879 25.4265C23.7907 25.8138 23.4816 26.123 23.0954 26.319C22.6591 26.5407 22.2111 26.5407 21.4679 26.5407H19.3679C18.6259 26.5407 18.1767 26.5407 17.7404 26.319C17.3542 26.123 17.0451 25.8138 16.8479 25.4265C16.6251 24.989 16.6251 24.541 16.6251 23.799V4.20016C16.6251 3.45816 16.6251 3.01016 16.8467 2.57383C17.0439 2.1865 17.3531 1.87733 17.7393 1.68133C18.1756 1.4585 18.6236 1.4585 19.3667 1.4585H21.4667C22.2099 1.4585 22.6579 1.4585 23.0954 1.68133C23.4804 1.87733 23.7896 2.1865 23.9867 2.57266C24.2096 3.01016 24.2096 3.45816 24.2096 4.20016ZM10.2621 1.68133C9.82458 1.4585 9.37658 1.4585 8.63342 1.4585H6.53341C5.79025 1.4585 5.34225 1.4585 4.90591 1.68133C4.51858 1.8785 4.20941 2.18766 4.01341 2.57383C3.79175 3.01016 3.79175 3.45816 3.79175 4.20016V23.8002C3.79175 24.5422 3.79175 24.9902 4.01341 25.4253C4.21058 25.8127 4.51975 26.1218 4.90708 26.319C5.34341 26.5407 5.79141 26.5407 6.53458 26.5407H8.63458C9.37658 26.5407 9.82575 26.5407 10.2621 26.319C10.6482 26.123 10.9574 25.8138 11.1546 25.4265C11.3762 24.9902 11.3762 24.5422 11.3762 23.8002V4.20016C11.3762 3.45816 11.3762 3.01016 11.1534 2.57266C10.9562 2.18533 10.6471 1.87733 10.2621 1.68133Z",
|
|
126
126
|
fill: "currentColor"
|
|
127
127
|
}
|
|
128
128
|
) });
|