@impakers/debug 1.3.1 → 1.3.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.
- package/dist/react.js +556 -222
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +556 -222
- package/dist/react.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -1576,39 +1576,6 @@ ${a.stack?.split("\n").slice(0, 3).join("\n")}`;
|
|
|
1576
1576
|
});
|
|
1577
1577
|
}
|
|
1578
1578
|
installConsoleCapture();
|
|
1579
|
-
var MAX_NETWORK_ERRORS = 5;
|
|
1580
|
-
var recentNetworkErrors = [];
|
|
1581
|
-
var fetchPatched = false;
|
|
1582
|
-
function installFetchCapture() {
|
|
1583
|
-
if (fetchPatched || typeof window === "undefined") return;
|
|
1584
|
-
fetchPatched = true;
|
|
1585
|
-
const originalFetch = window.fetch;
|
|
1586
|
-
window.fetch = async (input, init) => {
|
|
1587
|
-
const method = init?.method || "GET";
|
|
1588
|
-
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
1589
|
-
try {
|
|
1590
|
-
const response = await originalFetch(input, init);
|
|
1591
|
-
if (!response.ok && response.status >= 400) {
|
|
1592
|
-
recentNetworkErrors.push({
|
|
1593
|
-
url: url.slice(0, 200),
|
|
1594
|
-
status: response.status,
|
|
1595
|
-
method
|
|
1596
|
-
});
|
|
1597
|
-
if (recentNetworkErrors.length > MAX_NETWORK_ERRORS) recentNetworkErrors.shift();
|
|
1598
|
-
}
|
|
1599
|
-
return response;
|
|
1600
|
-
} catch (err) {
|
|
1601
|
-
recentNetworkErrors.push({
|
|
1602
|
-
url: url.slice(0, 200),
|
|
1603
|
-
status: 0,
|
|
1604
|
-
method
|
|
1605
|
-
});
|
|
1606
|
-
if (recentNetworkErrors.length > MAX_NETWORK_ERRORS) recentNetworkErrors.shift();
|
|
1607
|
-
throw err;
|
|
1608
|
-
}
|
|
1609
|
-
};
|
|
1610
|
-
}
|
|
1611
|
-
installFetchCapture();
|
|
1612
1579
|
function parseBrowser(ua) {
|
|
1613
1580
|
const edge = ua.match(/Edg\/(\d+[\d.]*)/);
|
|
1614
1581
|
if (edge) return `Edge ${edge[1]}`;
|
|
@@ -1743,7 +1710,6 @@ function collectMetadata(getUser) {
|
|
|
1743
1710
|
cookies: parseCookies(),
|
|
1744
1711
|
jwtClaims: findAndDecodeJwt() ?? void 0,
|
|
1745
1712
|
consoleErrors: recentConsoleErrors.length > 0 ? [...recentConsoleErrors] : void 0,
|
|
1746
|
-
networkErrors: recentNetworkErrors.length > 0 ? [...recentNetworkErrors] : void 0,
|
|
1747
1713
|
performance: getPagePerformance()
|
|
1748
1714
|
};
|
|
1749
1715
|
if (getUser) {
|
|
@@ -1786,94 +1752,313 @@ async function apiFetch(url, options = {}) {
|
|
|
1786
1752
|
return res;
|
|
1787
1753
|
}
|
|
1788
1754
|
var cache = /* @__PURE__ */ new Map();
|
|
1755
|
+
var inflightRequests = /* @__PURE__ */ new Map();
|
|
1756
|
+
var listeners = /* @__PURE__ */ new Map();
|
|
1789
1757
|
var CACHE_TTL = 3e4;
|
|
1790
|
-
function
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
return
|
|
1758
|
+
function getFeedbacksCacheKey(url) {
|
|
1759
|
+
return `feedbacks:${url}`;
|
|
1760
|
+
}
|
|
1761
|
+
function getAllFeedbacksCacheKey() {
|
|
1762
|
+
return "feedbacks:__all__";
|
|
1763
|
+
}
|
|
1764
|
+
function getCommentsCacheKey(taskId) {
|
|
1765
|
+
return `comments:${taskId}`;
|
|
1798
1766
|
}
|
|
1799
1767
|
function setCache(key, data) {
|
|
1800
1768
|
cache.set(key, { data, timestamp: Date.now() });
|
|
1769
|
+
const subs = listeners.get(key);
|
|
1770
|
+
if (!subs) return;
|
|
1771
|
+
subs.forEach((listener) => listener(data));
|
|
1772
|
+
}
|
|
1773
|
+
function peekCache(key) {
|
|
1774
|
+
const entry = cache.get(key);
|
|
1775
|
+
return entry?.data ?? null;
|
|
1776
|
+
}
|
|
1777
|
+
function isCacheFresh(key) {
|
|
1778
|
+
const entry = cache.get(key);
|
|
1779
|
+
if (!entry) return false;
|
|
1780
|
+
return Date.now() - entry.timestamp <= CACHE_TTL;
|
|
1781
|
+
}
|
|
1782
|
+
function getMatchingKeys(pattern) {
|
|
1783
|
+
return Array.from(cache.keys()).filter((key) => key.includes(pattern));
|
|
1801
1784
|
}
|
|
1802
|
-
function
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1785
|
+
function snapshotCaches(pattern) {
|
|
1786
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
1787
|
+
for (const key of getMatchingKeys(pattern)) {
|
|
1788
|
+
const value = peekCache(key);
|
|
1789
|
+
if (value !== null) snapshots.set(key, value);
|
|
1806
1790
|
}
|
|
1807
|
-
|
|
1808
|
-
|
|
1791
|
+
return snapshots;
|
|
1792
|
+
}
|
|
1793
|
+
function restoreSnapshots(snapshots) {
|
|
1794
|
+
snapshots.forEach((value, key) => setCache(key, value));
|
|
1795
|
+
}
|
|
1796
|
+
function mutateCache(key, updater) {
|
|
1797
|
+
const next = updater(peekCache(key));
|
|
1798
|
+
setCache(key, next);
|
|
1799
|
+
return next;
|
|
1800
|
+
}
|
|
1801
|
+
function mutateMatchingCaches(pattern, updater) {
|
|
1802
|
+
for (const key of getMatchingKeys(pattern)) {
|
|
1803
|
+
const current = peekCache(key);
|
|
1804
|
+
if (current === null) continue;
|
|
1805
|
+
setCache(key, updater(current));
|
|
1809
1806
|
}
|
|
1810
1807
|
}
|
|
1808
|
+
async function revalidateCache(key, fetcher) {
|
|
1809
|
+
const existing = inflightRequests.get(key);
|
|
1810
|
+
if (existing) return existing;
|
|
1811
|
+
const request = (async () => {
|
|
1812
|
+
try {
|
|
1813
|
+
const data = await fetcher();
|
|
1814
|
+
setCache(key, data);
|
|
1815
|
+
return data;
|
|
1816
|
+
} finally {
|
|
1817
|
+
inflightRequests.delete(key);
|
|
1818
|
+
}
|
|
1819
|
+
})();
|
|
1820
|
+
inflightRequests.set(key, request);
|
|
1821
|
+
return request;
|
|
1822
|
+
}
|
|
1823
|
+
async function readWithCache(key, fetcher, options = {}) {
|
|
1824
|
+
const cached = peekCache(key);
|
|
1825
|
+
if (cached !== null && !options.force) {
|
|
1826
|
+
if (options.staleWhileRevalidate || !isCacheFresh(key)) {
|
|
1827
|
+
void revalidateCache(key, fetcher);
|
|
1828
|
+
}
|
|
1829
|
+
return cached;
|
|
1830
|
+
}
|
|
1831
|
+
return revalidateCache(key, fetcher);
|
|
1832
|
+
}
|
|
1833
|
+
function subscribeCache(key, listener) {
|
|
1834
|
+
const subs = listeners.get(key) || /* @__PURE__ */ new Set();
|
|
1835
|
+
subs.add(listener);
|
|
1836
|
+
listeners.set(key, subs);
|
|
1837
|
+
return () => {
|
|
1838
|
+
const current = listeners.get(key);
|
|
1839
|
+
if (!current) return;
|
|
1840
|
+
current.delete(listener);
|
|
1841
|
+
if (current.size === 0) listeners.delete(key);
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
function getCachedSnapshot(key) {
|
|
1845
|
+
return peekCache(key);
|
|
1846
|
+
}
|
|
1811
1847
|
async function submitFeedback(endpoint, payload) {
|
|
1812
|
-
const
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1848
|
+
const tempTaskId = `temp-task-${Date.now()}`;
|
|
1849
|
+
const feedbackUrl = payload.feedbackUrl;
|
|
1850
|
+
const marker = payload.feedbackMarker;
|
|
1851
|
+
const previousFeedbacks = feedbackUrl ? peekCache(getFeedbacksCacheKey(feedbackUrl)) || [] : null;
|
|
1852
|
+
const previousAll = peekCache(getAllFeedbacksCacheKey());
|
|
1853
|
+
const optimisticTask = feedbackUrl ? {
|
|
1854
|
+
id: tempTaskId,
|
|
1855
|
+
taskNumber: 0,
|
|
1856
|
+
title: payload.title,
|
|
1857
|
+
status: "todo",
|
|
1858
|
+
priority: payload.priority,
|
|
1859
|
+
feedbackUrl,
|
|
1860
|
+
feedbackMarker: marker || null,
|
|
1861
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1862
|
+
commentCount: 0,
|
|
1863
|
+
_optimistic: true
|
|
1864
|
+
} : null;
|
|
1865
|
+
if (feedbackUrl && optimisticTask) {
|
|
1866
|
+
setCache(getFeedbacksCacheKey(feedbackUrl), [optimisticTask, ...previousFeedbacks]);
|
|
1867
|
+
if (previousAll) {
|
|
1868
|
+
setCache(getAllFeedbacksCacheKey(), [optimisticTask, ...previousAll]);
|
|
1869
|
+
}
|
|
1818
1870
|
}
|
|
1819
|
-
invalidateCache("feedbacks:");
|
|
1820
1871
|
try {
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1872
|
+
const res = await apiFetch(endpoint, {
|
|
1873
|
+
method: "POST",
|
|
1874
|
+
body: JSON.stringify(payload)
|
|
1875
|
+
});
|
|
1876
|
+
const result = await res.json().catch(() => ({}));
|
|
1877
|
+
if (feedbackUrl && optimisticTask) {
|
|
1878
|
+
const finalTask = {
|
|
1879
|
+
...optimisticTask,
|
|
1880
|
+
id: result.taskId || tempTaskId,
|
|
1881
|
+
taskNumber: result.taskNumber || 0,
|
|
1882
|
+
_optimistic: false
|
|
1883
|
+
};
|
|
1884
|
+
mutateCache(
|
|
1885
|
+
getFeedbacksCacheKey(feedbackUrl),
|
|
1886
|
+
(current) => (current || []).map((item) => item.id === tempTaskId ? finalTask : item)
|
|
1887
|
+
);
|
|
1888
|
+
if (previousAll) {
|
|
1889
|
+
mutateCache(
|
|
1890
|
+
getAllFeedbacksCacheKey(),
|
|
1891
|
+
(current) => (current || []).map((item) => item.id === tempTaskId ? finalTask : item)
|
|
1892
|
+
);
|
|
1893
|
+
}
|
|
1894
|
+
void revalidateFeedbacks(endpoint, feedbackUrl).catch(() => {
|
|
1895
|
+
});
|
|
1896
|
+
if (previousAll) void revalidateAllFeedbacks(endpoint).catch(() => {
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
return result;
|
|
1900
|
+
} catch (error) {
|
|
1901
|
+
if (feedbackUrl && previousFeedbacks) {
|
|
1902
|
+
setCache(getFeedbacksCacheKey(feedbackUrl), previousFeedbacks);
|
|
1903
|
+
}
|
|
1904
|
+
if (previousAll) {
|
|
1905
|
+
setCache(getAllFeedbacksCacheKey(), previousAll);
|
|
1906
|
+
}
|
|
1907
|
+
throw error;
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
async function fetchFeedbacks(endpoint, url, options = {}) {
|
|
1911
|
+
const cacheKey = getFeedbacksCacheKey(url);
|
|
1912
|
+
return readWithCache(cacheKey, async () => {
|
|
1913
|
+
const res = await apiFetch(`${endpoint}?url=${encodeURIComponent(url)}`);
|
|
1914
|
+
const data = await res.json();
|
|
1915
|
+
return data.tasks || [];
|
|
1916
|
+
}, options);
|
|
1917
|
+
}
|
|
1918
|
+
async function revalidateFeedbacks(endpoint, url) {
|
|
1919
|
+
const cacheKey = getFeedbacksCacheKey(url);
|
|
1920
|
+
return revalidateCache(cacheKey, async () => {
|
|
1921
|
+
const res = await apiFetch(`${endpoint}?url=${encodeURIComponent(url)}`);
|
|
1922
|
+
const data = await res.json();
|
|
1923
|
+
return data.tasks || [];
|
|
1924
|
+
});
|
|
1925
|
+
}
|
|
1926
|
+
async function revalidateAllFeedbacks(endpoint) {
|
|
1927
|
+
const cacheKey = getAllFeedbacksCacheKey();
|
|
1928
|
+
return revalidateCache(cacheKey, async () => {
|
|
1929
|
+
const res = await apiFetch(`${endpoint}?url=__all__`);
|
|
1930
|
+
const data = await res.json();
|
|
1931
|
+
return data.tasks || [];
|
|
1932
|
+
});
|
|
1933
|
+
}
|
|
1934
|
+
async function fetchComments(endpoint, taskId, options = {}) {
|
|
1935
|
+
const cacheKey = getCommentsCacheKey(taskId);
|
|
1936
|
+
return readWithCache(cacheKey, async () => {
|
|
1937
|
+
const res = await apiFetch(`${endpoint}/${taskId}/comments`);
|
|
1938
|
+
const data = await res.json();
|
|
1939
|
+
return data.comments || [];
|
|
1940
|
+
}, options);
|
|
1941
|
+
}
|
|
1942
|
+
async function revalidateComments(endpoint, taskId) {
|
|
1943
|
+
const cacheKey = getCommentsCacheKey(taskId);
|
|
1944
|
+
return revalidateCache(cacheKey, async () => {
|
|
1945
|
+
const res = await apiFetch(`${endpoint}/${taskId}/comments`);
|
|
1946
|
+
const data = await res.json();
|
|
1947
|
+
return data.comments || [];
|
|
1948
|
+
});
|
|
1949
|
+
}
|
|
1950
|
+
function incrementCommentCount(taskId, delta) {
|
|
1951
|
+
mutateMatchingCaches(
|
|
1952
|
+
"feedbacks:",
|
|
1953
|
+
(items) => items.map((item) => item.id === taskId ? { ...item, commentCount: Math.max(0, (item.commentCount || 0) + delta) } : item)
|
|
1954
|
+
);
|
|
1955
|
+
}
|
|
1956
|
+
function revalidateCachedFeedbackLists(endpoint) {
|
|
1957
|
+
const feedbackKeys = getMatchingKeys("feedbacks:");
|
|
1958
|
+
feedbackKeys.forEach((key) => {
|
|
1959
|
+
const url = key.replace("feedbacks:", "");
|
|
1960
|
+
if (url === "__all__") {
|
|
1961
|
+
void revalidateAllFeedbacks(endpoint).catch(() => {
|
|
1962
|
+
});
|
|
1963
|
+
} else {
|
|
1964
|
+
void revalidateFeedbacks(endpoint, url).catch(() => {
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
});
|
|
1968
|
+
}
|
|
1969
|
+
async function postComment(endpoint, taskId, content, authorName, authorId, screenshot, file) {
|
|
1847
1970
|
const tempComment = {
|
|
1848
1971
|
id: `temp-${Date.now()}`,
|
|
1849
1972
|
content,
|
|
1850
1973
|
authorName,
|
|
1851
1974
|
authorId,
|
|
1852
|
-
imageUrl: screenshot
|
|
1975
|
+
imageUrl: screenshot || void 0,
|
|
1976
|
+
fileUrl: file?.url,
|
|
1977
|
+
fileName: file?.fileName,
|
|
1978
|
+
fileType: file?.fileType,
|
|
1979
|
+
fileSize: file?.fileSize,
|
|
1980
|
+
fileSource: file?.fileSource,
|
|
1853
1981
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1854
1982
|
};
|
|
1855
|
-
const cacheKey =
|
|
1856
|
-
const
|
|
1857
|
-
|
|
1858
|
-
|
|
1983
|
+
const cacheKey = getCommentsCacheKey(taskId);
|
|
1984
|
+
const previousComments = peekCache(cacheKey) || [];
|
|
1985
|
+
const feedbackSnapshots = snapshotCaches("feedbacks:");
|
|
1986
|
+
setCache(cacheKey, [...previousComments, tempComment]);
|
|
1987
|
+
incrementCommentCount(taskId, 1);
|
|
1988
|
+
try {
|
|
1989
|
+
const res = await apiFetch(`${endpoint}/${taskId}/comments`, {
|
|
1990
|
+
method: "POST",
|
|
1991
|
+
body: JSON.stringify({
|
|
1992
|
+
content,
|
|
1993
|
+
authorName,
|
|
1994
|
+
authorId,
|
|
1995
|
+
screenshot,
|
|
1996
|
+
...file && {
|
|
1997
|
+
fileUrl: file.url,
|
|
1998
|
+
fileName: file.fileName,
|
|
1999
|
+
fileType: file.fileType,
|
|
2000
|
+
fileSize: file.fileSize,
|
|
2001
|
+
fileSource: file.fileSource
|
|
2002
|
+
}
|
|
2003
|
+
})
|
|
2004
|
+
});
|
|
2005
|
+
const data = await res.json();
|
|
2006
|
+
const serverComment = data.comment;
|
|
2007
|
+
mutateCache(
|
|
2008
|
+
cacheKey,
|
|
2009
|
+
(current) => (current || []).map((comment) => comment.id === tempComment.id ? serverComment : comment)
|
|
2010
|
+
);
|
|
2011
|
+
void revalidateComments(endpoint, taskId);
|
|
2012
|
+
revalidateCachedFeedbackLists(endpoint);
|
|
2013
|
+
return serverComment;
|
|
2014
|
+
} catch (error) {
|
|
2015
|
+
setCache(cacheKey, previousComments);
|
|
2016
|
+
restoreSnapshots(feedbackSnapshots);
|
|
2017
|
+
throw error;
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
var MAX_FILE_SIZE = 4.5 * 1024 * 1024;
|
|
2021
|
+
async function uploadFile(endpoint, file, context, taskId) {
|
|
2022
|
+
if (file.size > MAX_FILE_SIZE) {
|
|
2023
|
+
throw new Error(`\uD30C\uC77C \uD06C\uAE30\uAC00 4.5MB\uB97C \uCD08\uACFC\uD569\uB2C8\uB2E4. (${(file.size / 1024 / 1024).toFixed(1)}MB)`);
|
|
2024
|
+
}
|
|
2025
|
+
const token = getToken();
|
|
2026
|
+
const formData = new FormData();
|
|
2027
|
+
formData.append("file", file);
|
|
2028
|
+
formData.append("context", context);
|
|
2029
|
+
if (taskId) formData.append("taskId", taskId);
|
|
2030
|
+
const res = await fetch(`${endpoint}/upload`, {
|
|
1859
2031
|
method: "POST",
|
|
1860
|
-
|
|
2032
|
+
headers: {
|
|
2033
|
+
Authorization: `Bearer ${token}`
|
|
2034
|
+
// Content-Type은 FormData가 자동 설정 (boundary 포함)
|
|
2035
|
+
},
|
|
2036
|
+
body: formData
|
|
1861
2037
|
});
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
(
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
return serverComment;
|
|
2038
|
+
if (!res.ok) {
|
|
2039
|
+
if (res.status === 401) throw new Error("\uC778\uC99D\uC774 \uB9CC\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
2040
|
+
if (res.status === 413) throw new Error("\uD30C\uC77C \uD06C\uAE30\uAC00 4.5MB\uB97C \uCD08\uACFC\uD569\uB2C8\uB2E4.");
|
|
2041
|
+
const err = await res.json().catch(() => ({ error: "\uD30C\uC77C \uC5C5\uB85C\uB4DC \uC2E4\uD328" }));
|
|
2042
|
+
throw new Error(err.error || "\uD30C\uC77C \uC5C5\uB85C\uB4DC \uC2E4\uD328");
|
|
2043
|
+
}
|
|
2044
|
+
return res.json();
|
|
1870
2045
|
}
|
|
1871
2046
|
async function updateTaskStatus(endpoint, taskId, status) {
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
2047
|
+
const snapshots = snapshotCaches("feedbacks:");
|
|
2048
|
+
mutateMatchingCaches(
|
|
2049
|
+
"feedbacks:",
|
|
2050
|
+
(items) => items.map((item) => item.id === taskId ? { ...item, status } : item)
|
|
2051
|
+
);
|
|
2052
|
+
try {
|
|
2053
|
+
await apiFetch(`${endpoint}/${taskId}/status`, {
|
|
2054
|
+
method: "PATCH",
|
|
2055
|
+
body: JSON.stringify({ status })
|
|
2056
|
+
});
|
|
2057
|
+
revalidateCachedFeedbackLists(endpoint);
|
|
2058
|
+
} catch (error) {
|
|
2059
|
+
restoreSnapshots(snapshots);
|
|
2060
|
+
throw error;
|
|
2061
|
+
}
|
|
1877
2062
|
}
|
|
1878
2063
|
|
|
1879
2064
|
// src/core/sourcemap-resolver.ts
|
|
@@ -2025,8 +2210,8 @@ function PendingMarker({ x, y, accentColor }) {
|
|
|
2025
2210
|
var import_react3 = require("react");
|
|
2026
2211
|
|
|
2027
2212
|
// src/components/comment-thread/styles.module.scss
|
|
2028
|
-
var css3 = '@keyframes styles-module__threadIn___pBTFZ {\n from {\n opacity: 0;\n transform: scale(0.96) translateY(4px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n@keyframes styles-module__threadOut___-ccKh {\n from {\n opacity: 1;\n transform: scale(1);\n }\n to {\n opacity: 0;\n transform: scale(0.96);\n }\n}\n.styles-module__thread___ua2EO {\n position: fixed;\n width: 340px;\n max-height: 480px;\n background: #fff;\n border-radius: 12px;\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);\n z-index: 100002;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n font-size: 13px;\n color: #1a1a1a;\n animation: styles-module__threadIn___pBTFZ 0.15s ease-out;\n -webkit-font-smoothing: antialiased;\n}\n.styles-module__thread___ua2EO.styles-module__exiting___RIPeX {\n animation: styles-module__threadOut___-ccKh 0.12s ease-in forwards;\n pointer-events: none;\n}\n\n.styles-module__header___GiEBq {\n padding: 14px 16px 10px;\n display: flex;\n align-items: flex-start;\n gap: 10px;\n}\n\n.styles-module__avatar___JElAd {\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: #16a34a;\n color: #fff;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.styles-module__headerInfo___E8809 {\n flex: 1;\n min-width: 0;\n}\n\n.styles-module__headerTop___eDiCd {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 4px;\n}\n\n.styles-module__authorName___T1BfB {\n font-size: 13px;\n font-weight: 600;\n color: #1a1a1a;\n}\n\n.styles-module__timestamp___WusBf {\n font-size: 12px;\n color: #9ca3af;\n}\n\n.styles-module__headerActions___8FsMY {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-shrink: 0;\n}\n\n.styles-module__headerAction___Tinmq {\n width: 28px;\n height: 28px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: #9ca3af;\n transition: background 0.12s, color 0.12s;\n padding: 0;\n}\n.styles-module__headerAction___Tinmq:hover {\n background: #f3f4f6;\n color: #374151;\n}\n.styles-module__headerAction___Tinmq svg {\n width: 16px;\n height: 16px;\n}\n\n.styles-module__title___qkfqY {\n font-size: 13px;\n color: #1a1a1a;\n line-height: 1.5;\n word-break: break-word;\n}\n\n.styles-module__commentsList___kYqAR {\n flex: 1;\n overflow-y: auto;\n padding: 0;\n}\n.styles-module__commentsList___kYqAR::-webkit-scrollbar {\n width: 4px;\n}\n.styles-module__commentsList___kYqAR::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 2px;\n}\n\n.styles-module__comment___pW3IO {\n padding: 10px 16px;\n display: flex;\n align-items: flex-start;\n gap: 10px;\n}\n.styles-module__comment___pW3IO:hover {\n background: #f9fafb;\n}\n.styles-module__comment___pW3IO:hover .styles-module__commentActions___wO0fs {\n opacity: 1;\n}\n\n.styles-module__commentHighlight___EiTmx {\n background: #eff6ff;\n border-left: 2px solid #3b82f6;\n padding-left: 14px;\n}\n\n.styles-module__commentContent___RObGr {\n flex: 1;\n min-width: 0;\n}\n\n.styles-module__commentTop___BbTF3 {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 2px;\n}\n\n.styles-module__commentAuthor___tBjpl {\n font-size: 13px;\n font-weight: 600;\n color: #1a1a1a;\n}\n\n.styles-module__commentTime___0OLrz {\n font-size: 12px;\n color: #9ca3af;\n}\n\n.styles-module__commentActions___wO0fs {\n display: flex;\n gap: 2px;\n opacity: 0;\n transition: opacity 0.12s;\n}\n\n.styles-module__commentText___ldy2V {\n font-size: 13px;\n color: #374151;\n line-height: 1.5;\n word-break: break-word;\n white-space: pre-wrap;\n}\n\n.styles-module__screenshot___jUqau {\n margin-top: 8px;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n overflow: hidden;\n position: relative;\n max-width: 200px;\n}\n.styles-module__screenshot___jUqau img {\n width: 100%;\n height: auto;\n display: block;\n}\n.styles-module__screenshot___jUqau .styles-module__screenshotBadge___roEqY {\n position: absolute;\n top: 6px;\n right: 6px;\n background: rgba(0, 0, 0, 0.6);\n color: #fff;\n font-size: 10px;\n padding: 2px 6px;\n border-radius: 4px;\n font-weight: 500;\n}\n\n.styles-module__divider___kDjxN {\n height: 1px;\n background: #f3f4f6;\n margin: 0;\n}\n\n.styles-module__pendingImage___gHaF3 {\n position: relative;\n margin: 0 16px 8px;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n overflow: hidden;\n max-height: 120px;\n}\n.styles-module__pendingImage___gHaF3 img {\n width: 100%;\n height: auto;\n display: block;\n object-fit: cover;\n max-height: 120px;\n}\n\n.styles-module__pendingRemove___FRL4h {\n position: absolute;\n top: 4px;\n right: 4px;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.6);\n color: #fff;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n line-height: 1;\n padding: 0;\n}\n.styles-module__pendingRemove___FRL4h:hover {\n background: rgba(0, 0, 0, 0.8);\n}\n\n.styles-module__replyArea___VQn9b {\n padding: 10px 16px 8px;\n border-top: 1px solid #f3f4f6;\n}\n\n.styles-module__replyInput___uZNBW {\n width: 100%;\n border: none;\n outline: none;\n font-size: 13px;\n font-family: inherit;\n color: #1a1a1a;\n resize: none;\n padding: 0;\n min-height: 20px;\n max-height: 80px;\n line-height: 1.5;\n}\n.styles-module__replyInput___uZNBW::placeholder {\n color: #9ca3af;\n}\n\n.styles-module__replyToolbar___fTFJU {\n display: flex;\n align-items: center;\n padding: 4px 16px 10px;\n gap: 4px;\n}\n\n.styles-module__replyTool___Ho-Rx {\n width: 28px;\n height: 28px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: #9ca3af;\n transition: background 0.12s, color 0.12s;\n padding: 0;\n}\n.styles-module__replyTool___Ho-Rx:hover {\n background: #f3f4f6;\n color: #374151;\n}\n.styles-module__replyTool___Ho-Rx svg {\n width: 16px;\n height: 16px;\n}\n\n.styles-module__replySend___e0VSb {\n margin-left: auto;\n width: 28px;\n height: 28px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: #9ca3af;\n transition: background 0.12s, color 0.12s;\n padding: 0;\n}\n.styles-module__replySend___e0VSb:hover {\n color: #3b82f6;\n}\n.styles-module__replySend___e0VSb.styles-module__active___R--Jj {\n color: #3b82f6;\n}\n.styles-module__replySend___e0VSb svg {\n width: 16px;\n height: 16px;\n}\n\n.styles-module__empty___XXGiw {\n padding: 24px 16px;\n text-align: center;\n color: #9ca3af;\n font-size: 13px;\n}\n\n.styles-module__statusBadge___el8ml {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n font-weight: 500;\n padding: 2px 8px;\n border-radius: 10px;\n margin-left: auto;\n}\n.styles-module__statusBadge___el8ml.styles-module__todo___rUWBr {\n background: #fef3c7;\n color: #92400e;\n}\n.styles-module__statusBadge___el8ml.styles-module__inProgress___HEWgU {\n background: #dbeafe;\n color: #1e40af;\n}\n.styles-module__statusBadge___el8ml.styles-module__done___zC12n {\n background: #dcfce7;\n color: #166534;\n}\n\n.styles-module__lightbox___KoWEF {\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n background: rgba(0, 0, 0, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: zoom-out;\n}\n.styles-module__lightbox___KoWEF img {\n max-width: 90vw;\n max-height: 90vh;\n border-radius: 8px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n cursor: default;\n}\n\n.styles-module__lightboxClose___tGZlm {\n position: absolute;\n top: 16px;\n right: 16px;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.15);\n color: #fff;\n border: none;\n cursor: pointer;\n font-size: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.styles-module__lightboxClose___tGZlm:hover {\n background: rgba(255, 255, 255, 0.25);\n}';
|
|
2029
|
-
var classNames3 = { "thread": "styles-module__thread___ua2EO", "threadIn": "styles-module__threadIn___pBTFZ", "exiting": "styles-module__exiting___RIPeX", "threadOut": "styles-module__threadOut___-ccKh", "header": "styles-module__header___GiEBq", "avatar": "styles-module__avatar___JElAd", "headerInfo": "styles-module__headerInfo___E8809", "headerTop": "styles-module__headerTop___eDiCd", "authorName": "styles-module__authorName___T1BfB", "timestamp": "styles-module__timestamp___WusBf", "headerActions": "styles-module__headerActions___8FsMY", "headerAction": "styles-module__headerAction___Tinmq", "title": "styles-module__title___qkfqY", "commentsList": "styles-module__commentsList___kYqAR", "comment": "styles-module__comment___pW3IO", "commentActions": "styles-module__commentActions___wO0fs", "commentHighlight": "styles-module__commentHighlight___EiTmx", "commentContent": "styles-module__commentContent___RObGr", "commentTop": "styles-module__commentTop___BbTF3", "commentAuthor": "styles-module__commentAuthor___tBjpl", "commentTime": "styles-module__commentTime___0OLrz", "commentText": "styles-module__commentText___ldy2V", "screenshot": "styles-module__screenshot___jUqau", "screenshotBadge": "styles-module__screenshotBadge___roEqY", "divider": "styles-module__divider___kDjxN", "pendingImage": "styles-module__pendingImage___gHaF3", "pendingRemove": "styles-module__pendingRemove___FRL4h", "replyArea": "styles-module__replyArea___VQn9b", "replyInput": "styles-module__replyInput___uZNBW", "replyToolbar": "styles-module__replyToolbar___fTFJU", "replyTool": "styles-module__replyTool___Ho-Rx", "replySend": "styles-module__replySend___e0VSb", "active": "styles-module__active___R--Jj", "empty": "styles-module__empty___XXGiw", "statusBadge": "styles-module__statusBadge___el8ml", "todo": "styles-module__todo___rUWBr", "inProgress": "styles-module__inProgress___HEWgU", "done": "styles-module__done___zC12n", "lightbox": "styles-module__lightbox___KoWEF", "lightboxClose": "styles-module__lightboxClose___tGZlm" };
|
|
2213
|
+
var css3 = '@keyframes styles-module__threadIn___pBTFZ {\n from {\n opacity: 0;\n transform: scale(0.96) translateY(4px);\n }\n to {\n opacity: 1;\n transform: scale(1) translateY(0);\n }\n}\n@keyframes styles-module__threadOut___-ccKh {\n from {\n opacity: 1;\n transform: scale(1);\n }\n to {\n opacity: 0;\n transform: scale(0.96);\n }\n}\n.styles-module__thread___ua2EO {\n position: fixed;\n width: 340px;\n max-height: 480px;\n background: #fff;\n border-radius: 12px;\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);\n z-index: 100002;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n font-size: 13px;\n color: #1a1a1a;\n animation: styles-module__threadIn___pBTFZ 0.15s ease-out;\n -webkit-font-smoothing: antialiased;\n}\n.styles-module__thread___ua2EO.styles-module__exiting___RIPeX {\n animation: styles-module__threadOut___-ccKh 0.12s ease-in forwards;\n pointer-events: none;\n}\n\n.styles-module__header___GiEBq {\n padding: 14px 16px 10px;\n display: flex;\n align-items: flex-start;\n gap: 10px;\n}\n\n.styles-module__avatar___JElAd {\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: #16a34a;\n color: #fff;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.styles-module__headerInfo___E8809 {\n flex: 1;\n min-width: 0;\n}\n\n.styles-module__headerTop___eDiCd {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 4px;\n}\n\n.styles-module__authorName___T1BfB {\n font-size: 13px;\n font-weight: 600;\n color: #1a1a1a;\n}\n\n.styles-module__timestamp___WusBf {\n font-size: 12px;\n color: #9ca3af;\n}\n\n.styles-module__headerActions___8FsMY {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-shrink: 0;\n}\n\n.styles-module__headerAction___Tinmq {\n width: 28px;\n height: 28px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: #9ca3af;\n transition: background 0.12s, color 0.12s;\n padding: 0;\n}\n.styles-module__headerAction___Tinmq:hover {\n background: #f3f4f6;\n color: #374151;\n}\n.styles-module__headerAction___Tinmq svg {\n width: 16px;\n height: 16px;\n}\n\n.styles-module__title___qkfqY {\n font-size: 13px;\n color: #1a1a1a;\n line-height: 1.5;\n word-break: break-word;\n}\n\n.styles-module__commentsList___kYqAR {\n flex: 1;\n overflow-y: auto;\n padding: 0;\n}\n.styles-module__commentsList___kYqAR::-webkit-scrollbar {\n width: 4px;\n}\n.styles-module__commentsList___kYqAR::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 2px;\n}\n\n.styles-module__comment___pW3IO {\n padding: 10px 16px;\n display: flex;\n align-items: flex-start;\n gap: 10px;\n}\n.styles-module__comment___pW3IO:hover {\n background: #f9fafb;\n}\n.styles-module__comment___pW3IO:hover .styles-module__commentActions___wO0fs {\n opacity: 1;\n}\n\n.styles-module__commentHighlight___EiTmx {\n background: #eff6ff;\n border-left: 2px solid #3b82f6;\n padding-left: 14px;\n}\n\n.styles-module__commentContent___RObGr {\n flex: 1;\n min-width: 0;\n}\n\n.styles-module__commentTop___BbTF3 {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 2px;\n}\n\n.styles-module__commentAuthor___tBjpl {\n font-size: 13px;\n font-weight: 600;\n color: #1a1a1a;\n}\n\n.styles-module__commentTime___0OLrz {\n font-size: 12px;\n color: #9ca3af;\n}\n\n.styles-module__commentActions___wO0fs {\n display: flex;\n gap: 2px;\n opacity: 0;\n transition: opacity 0.12s;\n}\n\n.styles-module__commentText___ldy2V {\n font-size: 13px;\n color: #374151;\n line-height: 1.5;\n word-break: break-word;\n white-space: pre-wrap;\n}\n\n.styles-module__screenshot___jUqau {\n margin-top: 8px;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n overflow: hidden;\n position: relative;\n max-width: 200px;\n}\n.styles-module__screenshot___jUqau img {\n width: 100%;\n height: auto;\n display: block;\n}\n.styles-module__screenshot___jUqau .styles-module__screenshotBadge___roEqY {\n position: absolute;\n top: 6px;\n right: 6px;\n background: rgba(0, 0, 0, 0.6);\n color: #fff;\n font-size: 10px;\n padding: 2px 6px;\n border-radius: 4px;\n font-weight: 500;\n}\n\n.styles-module__fileCard___-iOro {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n padding: 8px 10px;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n background: #f9fafb;\n text-decoration: none;\n color: inherit;\n cursor: pointer;\n transition: background 0.12s;\n max-width: 200px;\n}\n.styles-module__fileCard___-iOro:hover {\n background: #f3f4f6;\n}\n\n.styles-module__fileIcon___dNJMT {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n background: #e5e7eb;\n color: #374151;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 10px;\n font-weight: 700;\n flex-shrink: 0;\n letter-spacing: 0.5px;\n}\n\n.styles-module__fileInfo___dVrLV {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 1px;\n}\n\n.styles-module__fileCardName___SHOj- {\n font-size: 12px;\n font-weight: 500;\n color: #1a1a1a;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.styles-module__fileCardSize___W53JL {\n font-size: 11px;\n color: #9ca3af;\n}\n\n.styles-module__pendingFile___-OSRs {\n position: relative;\n margin: 0 16px 8px;\n padding: 8px 10px;\n padding-right: 30px;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n background: #f9fafb;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.styles-module__divider___kDjxN {\n height: 1px;\n background: #f3f4f6;\n margin: 0;\n}\n\n.styles-module__pendingImage___gHaF3 {\n position: relative;\n margin: 0 16px 8px;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n overflow: hidden;\n max-height: 120px;\n}\n.styles-module__pendingImage___gHaF3 img {\n width: 100%;\n height: auto;\n display: block;\n object-fit: cover;\n max-height: 120px;\n}\n\n.styles-module__pendingRemove___FRL4h {\n position: absolute;\n top: 4px;\n right: 4px;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: rgba(0, 0, 0, 0.6);\n color: #fff;\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n line-height: 1;\n padding: 0;\n}\n.styles-module__pendingRemove___FRL4h:hover {\n background: rgba(0, 0, 0, 0.8);\n}\n\n.styles-module__replyArea___VQn9b {\n padding: 10px 16px 8px;\n border-top: 1px solid #f3f4f6;\n}\n\n.styles-module__replyInput___uZNBW {\n width: 100%;\n border: none;\n outline: none;\n font-size: 13px;\n font-family: inherit;\n color: #1a1a1a;\n resize: none;\n padding: 0;\n min-height: 20px;\n max-height: 80px;\n line-height: 1.5;\n}\n.styles-module__replyInput___uZNBW::placeholder {\n color: #9ca3af;\n}\n\n.styles-module__replyToolbar___fTFJU {\n display: flex;\n align-items: center;\n padding: 4px 16px 10px;\n gap: 4px;\n}\n\n.styles-module__replyTool___Ho-Rx {\n width: 28px;\n height: 28px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: #9ca3af;\n transition: background 0.12s, color 0.12s;\n padding: 0;\n}\n.styles-module__replyTool___Ho-Rx:hover {\n background: #f3f4f6;\n color: #374151;\n}\n.styles-module__replyTool___Ho-Rx svg {\n width: 16px;\n height: 16px;\n}\n\n.styles-module__replySend___e0VSb {\n margin-left: auto;\n width: 28px;\n height: 28px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: #9ca3af;\n transition: background 0.12s, color 0.12s;\n padding: 0;\n}\n.styles-module__replySend___e0VSb:hover {\n color: #3b82f6;\n}\n.styles-module__replySend___e0VSb.styles-module__active___R--Jj {\n color: #3b82f6;\n}\n.styles-module__replySend___e0VSb svg {\n width: 16px;\n height: 16px;\n}\n\n.styles-module__empty___XXGiw {\n padding: 24px 16px;\n text-align: center;\n color: #9ca3af;\n font-size: 13px;\n}\n\n.styles-module__statusBadge___el8ml {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n font-weight: 500;\n padding: 2px 8px;\n border-radius: 10px;\n margin-left: auto;\n}\n.styles-module__statusBadge___el8ml.styles-module__todo___rUWBr {\n background: #fef3c7;\n color: #92400e;\n}\n.styles-module__statusBadge___el8ml.styles-module__inProgress___HEWgU {\n background: #dbeafe;\n color: #1e40af;\n}\n.styles-module__statusBadge___el8ml.styles-module__done___zC12n {\n background: #dcfce7;\n color: #166534;\n}\n\n.styles-module__lightbox___KoWEF {\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n background: rgba(0, 0, 0, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: zoom-out;\n}\n.styles-module__lightbox___KoWEF img {\n max-width: 90vw;\n max-height: 90vh;\n border-radius: 8px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n cursor: default;\n}\n\n.styles-module__lightboxClose___tGZlm {\n position: absolute;\n top: 16px;\n right: 16px;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.15);\n color: #fff;\n border: none;\n cursor: pointer;\n font-size: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.styles-module__lightboxClose___tGZlm:hover {\n background: rgba(255, 255, 255, 0.25);\n}';
|
|
2214
|
+
var classNames3 = { "thread": "styles-module__thread___ua2EO", "threadIn": "styles-module__threadIn___pBTFZ", "exiting": "styles-module__exiting___RIPeX", "threadOut": "styles-module__threadOut___-ccKh", "header": "styles-module__header___GiEBq", "avatar": "styles-module__avatar___JElAd", "headerInfo": "styles-module__headerInfo___E8809", "headerTop": "styles-module__headerTop___eDiCd", "authorName": "styles-module__authorName___T1BfB", "timestamp": "styles-module__timestamp___WusBf", "headerActions": "styles-module__headerActions___8FsMY", "headerAction": "styles-module__headerAction___Tinmq", "title": "styles-module__title___qkfqY", "commentsList": "styles-module__commentsList___kYqAR", "comment": "styles-module__comment___pW3IO", "commentActions": "styles-module__commentActions___wO0fs", "commentHighlight": "styles-module__commentHighlight___EiTmx", "commentContent": "styles-module__commentContent___RObGr", "commentTop": "styles-module__commentTop___BbTF3", "commentAuthor": "styles-module__commentAuthor___tBjpl", "commentTime": "styles-module__commentTime___0OLrz", "commentText": "styles-module__commentText___ldy2V", "screenshot": "styles-module__screenshot___jUqau", "screenshotBadge": "styles-module__screenshotBadge___roEqY", "fileCard": "styles-module__fileCard___-iOro", "fileIcon": "styles-module__fileIcon___dNJMT", "fileInfo": "styles-module__fileInfo___dVrLV", "fileCardName": "styles-module__fileCardName___SHOj-", "fileCardSize": "styles-module__fileCardSize___W53JL", "pendingFile": "styles-module__pendingFile___-OSRs", "divider": "styles-module__divider___kDjxN", "pendingImage": "styles-module__pendingImage___gHaF3", "pendingRemove": "styles-module__pendingRemove___FRL4h", "replyArea": "styles-module__replyArea___VQn9b", "replyInput": "styles-module__replyInput___uZNBW", "replyToolbar": "styles-module__replyToolbar___fTFJU", "replyTool": "styles-module__replyTool___Ho-Rx", "replySend": "styles-module__replySend___e0VSb", "active": "styles-module__active___R--Jj", "empty": "styles-module__empty___XXGiw", "statusBadge": "styles-module__statusBadge___el8ml", "todo": "styles-module__todo___rUWBr", "inProgress": "styles-module__inProgress___HEWgU", "done": "styles-module__done___zC12n", "lightbox": "styles-module__lightbox___KoWEF", "lightboxClose": "styles-module__lightboxClose___tGZlm" };
|
|
2030
2215
|
if (typeof document !== "undefined") {
|
|
2031
2216
|
let style = document.getElementById("impakers-debug-styles-comment-thread-styles");
|
|
2032
2217
|
if (!style) {
|
|
@@ -2054,6 +2239,21 @@ function timeAgo(dateStr) {
|
|
|
2054
2239
|
function getInitials(name) {
|
|
2055
2240
|
return name.slice(0, 1).toUpperCase();
|
|
2056
2241
|
}
|
|
2242
|
+
function formatFileSize(bytes) {
|
|
2243
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
2244
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)}KB`;
|
|
2245
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
2246
|
+
}
|
|
2247
|
+
function getFileIcon(mimeType) {
|
|
2248
|
+
if (mimeType.includes("pdf")) return "PDF";
|
|
2249
|
+
if (mimeType.includes("spreadsheet") || mimeType.includes("excel") || mimeType.includes("csv")) return "XLS";
|
|
2250
|
+
if (mimeType.includes("presentation") || mimeType.includes("powerpoint")) return "PPT";
|
|
2251
|
+
if (mimeType.includes("document") || mimeType.includes("word")) return "DOC";
|
|
2252
|
+
if (mimeType.includes("zip") || mimeType.includes("compressed") || mimeType.includes("archive")) return "ZIP";
|
|
2253
|
+
if (mimeType.includes("video")) return "VID";
|
|
2254
|
+
if (mimeType.includes("audio")) return "AUD";
|
|
2255
|
+
return "FILE";
|
|
2256
|
+
}
|
|
2057
2257
|
function CommentThread({
|
|
2058
2258
|
task,
|
|
2059
2259
|
currentUserName,
|
|
@@ -2068,6 +2268,7 @@ function CommentThread({
|
|
|
2068
2268
|
const [replyText, setReplyText] = (0, import_react3.useState)("");
|
|
2069
2269
|
const [exiting, setExiting] = (0, import_react3.useState)(false);
|
|
2070
2270
|
const [pendingImage, setPendingImage] = (0, import_react3.useState)(null);
|
|
2271
|
+
const [pendingFile, setPendingFile] = (0, import_react3.useState)(null);
|
|
2071
2272
|
const [capturingDom, setCapturingDom] = (0, import_react3.useState)(false);
|
|
2072
2273
|
const textareaRef = (0, import_react3.useRef)(null);
|
|
2073
2274
|
const listRef = (0, import_react3.useRef)(null);
|
|
@@ -2094,11 +2295,12 @@ function CommentThread({
|
|
|
2094
2295
|
setTimeout(() => onClose(), 120);
|
|
2095
2296
|
}, [onClose]);
|
|
2096
2297
|
const handleSend = (0, import_react3.useCallback)(() => {
|
|
2097
|
-
if (!replyText.trim() && !pendingImage) return;
|
|
2098
|
-
onReply(task.id, replyText.trim(), pendingImage || void 0);
|
|
2298
|
+
if (!replyText.trim() && !pendingImage && !pendingFile) return;
|
|
2299
|
+
onReply(task.id, replyText.trim(), pendingImage || void 0, pendingFile || void 0);
|
|
2099
2300
|
setReplyText("");
|
|
2100
2301
|
setPendingImage(null);
|
|
2101
|
-
|
|
2302
|
+
setPendingFile(null);
|
|
2303
|
+
}, [replyText, pendingImage, pendingFile, task.id, onReply]);
|
|
2102
2304
|
const handleKeyDown = (0, import_react3.useCallback)(
|
|
2103
2305
|
(e) => {
|
|
2104
2306
|
e.stopPropagation();
|
|
@@ -2174,12 +2376,23 @@ function CommentThread({
|
|
|
2174
2376
|
}, []);
|
|
2175
2377
|
const handleFileChange = (0, import_react3.useCallback)((e) => {
|
|
2176
2378
|
const file = e.target.files?.[0];
|
|
2177
|
-
if (!file
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2379
|
+
if (!file) return;
|
|
2380
|
+
if (file.size > 4.5 * 1024 * 1024) {
|
|
2381
|
+
console.warn("[@impakers/debug] \uD30C\uC77C \uD06C\uAE30\uAC00 4.5MB\uB97C \uCD08\uACFC\uD569\uB2C8\uB2E4.");
|
|
2382
|
+
e.target.value = "";
|
|
2383
|
+
return;
|
|
2384
|
+
}
|
|
2385
|
+
if (file.type.startsWith("image/")) {
|
|
2386
|
+
setPendingFile(null);
|
|
2387
|
+
const reader = new FileReader();
|
|
2388
|
+
reader.onload = () => {
|
|
2389
|
+
setPendingImage(reader.result);
|
|
2390
|
+
};
|
|
2391
|
+
reader.readAsDataURL(file);
|
|
2392
|
+
} else {
|
|
2393
|
+
setPendingImage(null);
|
|
2394
|
+
setPendingFile(file);
|
|
2395
|
+
}
|
|
2183
2396
|
e.target.value = "";
|
|
2184
2397
|
}, []);
|
|
2185
2398
|
const feedbackTitle = task.title.replace(/^\[피드백\]\s*/, "");
|
|
@@ -2228,6 +2441,23 @@ function CommentThread({
|
|
|
2228
2441
|
style: { cursor: "pointer" },
|
|
2229
2442
|
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("img", { src: comment.imageUrl, alt: "screenshot" })
|
|
2230
2443
|
}
|
|
2444
|
+
),
|
|
2445
|
+
comment.fileUrl && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2446
|
+
"a",
|
|
2447
|
+
{
|
|
2448
|
+
className: styles_module_default3.fileCard,
|
|
2449
|
+
href: comment.fileUrl,
|
|
2450
|
+
target: "_blank",
|
|
2451
|
+
rel: "noopener noreferrer",
|
|
2452
|
+
onClick: (e) => e.stopPropagation(),
|
|
2453
|
+
children: [
|
|
2454
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: styles_module_default3.fileIcon, children: getFileIcon(comment.fileType || "") }),
|
|
2455
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: styles_module_default3.fileInfo, children: [
|
|
2456
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: styles_module_default3.fileCardName, children: comment.fileName || "\uD30C\uC77C" }),
|
|
2457
|
+
comment.fileSize != null && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: styles_module_default3.fileCardSize, children: formatFileSize(comment.fileSize) })
|
|
2458
|
+
] })
|
|
2459
|
+
]
|
|
2460
|
+
}
|
|
2231
2461
|
)
|
|
2232
2462
|
] })
|
|
2233
2463
|
] }, comment.id)) })
|
|
@@ -2236,6 +2466,14 @@ function CommentThread({
|
|
|
2236
2466
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("img", { src: pendingImage, alt: "pending" }),
|
|
2237
2467
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: styles_module_default3.pendingRemove, onClick: () => setPendingImage(null), type: "button", children: "\xD7" })
|
|
2238
2468
|
] }),
|
|
2469
|
+
pendingFile && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: styles_module_default3.pendingFile, children: [
|
|
2470
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: styles_module_default3.fileIcon, children: getFileIcon(pendingFile.type) }),
|
|
2471
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: styles_module_default3.fileInfo, children: [
|
|
2472
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: styles_module_default3.fileCardName, children: pendingFile.name }),
|
|
2473
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: styles_module_default3.fileCardSize, children: formatFileSize(pendingFile.size) })
|
|
2474
|
+
] }),
|
|
2475
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: styles_module_default3.pendingRemove, onClick: () => setPendingFile(null), type: "button", children: "\xD7" })
|
|
2476
|
+
] }),
|
|
2239
2477
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: styles_module_default3.replyArea, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2240
2478
|
"textarea",
|
|
2241
2479
|
{
|
|
@@ -2249,7 +2487,7 @@ function CommentThread({
|
|
|
2249
2487
|
}
|
|
2250
2488
|
) }),
|
|
2251
2489
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: styles_module_default3.replyToolbar, children: [
|
|
2252
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: styles_module_default3.replyTool, onClick: handleAttachClick, type: "button", title: "\
|
|
2490
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: styles_module_default3.replyTool, onClick: handleAttachClick, type: "button", title: "\uD30C\uC77C \uCCA8\uBD80", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
2253
2491
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
|
|
2254
2492
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
|
|
2255
2493
|
] }) }),
|
|
@@ -2260,9 +2498,9 @@ function CommentThread({
|
|
|
2260
2498
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2261
2499
|
"button",
|
|
2262
2500
|
{
|
|
2263
|
-
className: `${styles_module_default3.replySend} ${replyText.trim() || pendingImage ? styles_module_default3.active : ""}`,
|
|
2501
|
+
className: `${styles_module_default3.replySend} ${replyText.trim() || pendingImage || pendingFile ? styles_module_default3.active : ""}`,
|
|
2264
2502
|
onClick: handleSend,
|
|
2265
|
-
disabled: !replyText.trim() && !pendingImage,
|
|
2503
|
+
disabled: !replyText.trim() && !pendingImage && !pendingFile,
|
|
2266
2504
|
type: "button",
|
|
2267
2505
|
title: "\uC804\uC1A1",
|
|
2268
2506
|
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
@@ -2277,7 +2515,7 @@ function CommentThread({
|
|
|
2277
2515
|
{
|
|
2278
2516
|
ref: fileInputRef,
|
|
2279
2517
|
type: "file",
|
|
2280
|
-
accept: "
|
|
2518
|
+
accept: "*/*",
|
|
2281
2519
|
style: { display: "none" },
|
|
2282
2520
|
onChange: handleFileChange
|
|
2283
2521
|
}
|
|
@@ -2475,8 +2713,8 @@ var import_react5 = require("react");
|
|
|
2475
2713
|
var import_react_dom = require("react-dom");
|
|
2476
2714
|
|
|
2477
2715
|
// src/components/inbox-panel/styles.module.scss
|
|
2478
|
-
var css5 = '@keyframes styles-module__slideIn___0o0s- {\n from {\n transform: translateX(100%);\n }\n to {\n transform: translateX(0);\n }\n}\n@keyframes styles-module__slideOut___nKrBX {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(100%);\n }\n}\n@keyframes styles-module__fadeIn___j09Ts {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.styles-module__backdrop___zYhcU {\n position: fixed;\n inset: 0;\n z-index: 100003;\n animation: styles-module__fadeIn___j09Ts 0.15s ease-out;\n}\n\n.styles-module__panel___6YS8k {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 420px;\n max-width: 100vw;\n background: #fafafa;\n z-index: 100004;\n display: flex;\n flex-direction: column;\n box-shadow: -4px 0 24px rgba(0, 0, 0, 0.08);\n animation: styles-module__slideIn___0o0s- 0.2s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n}\n.styles-module__panel___6YS8k.styles-module__exiting___6A-Ag {\n animation: styles-module__slideOut___nKrBX 0.15s ease-in forwards;\n}\n\n.styles-module__header___fBbGz {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid #e5e7eb;\n background: #fff;\n flex-shrink: 0;\n}\n\n.styles-module__headerLeft___e0YLf {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.styles-module__headerTitle___oEPJa {\n font-size: 14px;\n font-weight: 600;\n color: #18181b;\n}\n\n.styles-module__closeBtn___-H8ra {\n width: 32px;\n height: 32px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: #6b7280;\n transition: background 0.12s, color 0.12s;\n}\n.styles-module__closeBtn___-H8ra:hover {\n background: #f3f4f6;\n color: #18181b;\n}\n.styles-module__closeBtn___-H8ra svg {\n width: 18px;\n height: 18px;\n}\n\n.styles-module__tabs___nfuX7 {\n display: flex;\n padding: 0 20px;\n gap: 0;\n border-bottom: 1px solid #e5e7eb;\n background: #fff;\n flex-shrink: 0;\n}\n\n.styles-module__tab___Hc-jn {\n padding: 10px 16px;\n font-size: 13px;\n font-weight: 500;\n color: #6b7280;\n border: none;\n background: none;\n cursor: pointer;\n border-bottom: 2px solid transparent;\n transition: color 0.12s, border-color 0.12s;\n font-family: inherit;\n}\n.styles-module__tab___Hc-jn:hover {\n color: #374151;\n}\n.styles-module__tab___Hc-jn.styles-module__active___ZQzA5 {\n color: #18181b;\n border-bottom-color: #18181b;\n}\n\n.styles-module__tabBadge___IdFDQ {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n border-radius: 9px;\n background: #e5e7eb;\n color: #374151;\n font-size: 11px;\n font-weight: 600;\n padding: 0 5px;\n margin-left: 6px;\n}\n\n.styles-module__content___L2lRw {\n flex: 1;\n overflow-y: auto;\n padding: 12px;\n}\n.styles-module__content___L2lRw::-webkit-scrollbar {\n width: 4px;\n}\n.styles-module__content___L2lRw::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 2px;\n}\n\n.styles-module__card___F8qwd {\n background: #fff;\n border-radius: 12px;\n border: 1px solid #e5e7eb;\n margin-bottom: 12px;\n overflow: hidden;\n transition: box-shadow 0.12s;\n cursor: pointer;\n}\n.styles-module__card___F8qwd:hover {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n}\n\n.styles-module__cardHeader___QOVGR {\n padding: 14px 16px 8px;\n display: flex;\n align-items: flex-start;\n gap: 10px;\n}\n\n.styles-module__cardAvatar___FfKmW {\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: #16a34a;\n color: #fff;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.styles-module__cardInfo___BmrdF {\n flex: 1;\n min-width: 0;\n}\n\n.styles-module__cardMeta___7p9KD {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 4px;\n}\n\n.styles-module__cardAuthor___YvnuR {\n font-size: 13px;\n font-weight: 600;\n color: #18181b;\n}\n\n.styles-module__cardTime___N1Png {\n font-size: 12px;\n color: #9ca3af;\n}\n\n.styles-module__cardActions___7QF72 {\n display: flex;\n gap: 2px;\n flex-shrink: 0;\n}\n\n.styles-module__cardAction___t4b3V {\n width: 26px;\n height: 26px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 5px;\n color: #9ca3af;\n transition: background 0.12s, color 0.12s;\n padding: 0;\n}\n.styles-module__cardAction___t4b3V:hover {\n background: #f3f4f6;\n color: #374151;\n}\n.styles-module__cardAction___t4b3V svg {\n width: 14px;\n height: 14px;\n}\n\n.styles-module__cardTitle___xJxDN {\n font-size: 13px;\n color: #1a1a1a;\n line-height: 1.5;\n padding: 0 16px 8px;\n}\n\n.styles-module__cardScreenshot___I5-QL {\n margin: 0 16px 8px;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n overflow: hidden;\n position: relative;\n max-height: 160px;\n}\n.styles-module__cardScreenshot___I5-QL img {\n width: 100%;\n height: auto;\n display: block;\n object-fit: cover;\n}\n\n.styles-module__cardRoute___U4gB6 {\n margin: 0 16px 10px;\n padding: 8px 12px;\n background: #f9fafb;\n border: 1px solid #f3f4f6;\n border-radius: 8px;\n font-size: 12px;\n color: #6b7280;\n line-height: 1.4;\n}\n\n.styles-module__cardRouteName___BDH75 {\n font-weight: 500;\n color: #374151;\n}\n\n.styles-module__cardRoutePath___zP-fh {\n color: #9ca3af;\n}\n\n.styles-module__cardFooter___wfPa4 {\n padding: 8px 16px 12px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.styles-module__cardReplyDot___YnqzI {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #16a34a;\n flex-shrink: 0;\n}\n\n.styles-module__cardReplyCount___O1khL {\n font-size: 12px;\n font-weight: 500;\n color: #374151;\n}\n\n.styles-module__statusDot___l4IHG {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n.styles-module__statusDot___l4IHG.styles-module__todo___894P6 {\n background: #f59e0b;\n}\n.styles-module__statusDot___l4IHG.styles-module__inProgress___IZ1mJ {\n background: #3b82f6;\n}\n.styles-module__statusDot___l4IHG.styles-module__done___n4cWP {\n background: #16a34a;\n}\n\n.styles-module__empty___IADrw {\n text-align: center;\n padding: 48px 20px;\n color: #9ca3af;\n font-size: 13px;\n line-height: 1.6;\n}\n\n.styles-module__emptyIcon___1x5wT {\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: #f3f4f6;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 12px;\n color: #9ca3af;\n}\n.styles-module__emptyIcon___1x5wT svg {\n width: 24px;\n height: 24px;\n}\n\n.styles-module__checkBtn___KjHxm {\n width: 28px;\n height: 28px;\n border: 2px solid #d1d5db;\n border-radius: 50%;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: transparent;\n transition: all 0.15s;\n padding: 0;\n flex-shrink: 0;\n}\n.styles-module__checkBtn___KjHxm svg {\n width: 14px;\n height: 14px;\n}\n.styles-module__checkBtn___KjHxm:hover {\n border-color: #16a34a;\n color: #16a34a;\n}\n.styles-module__checkBtn___KjHxm.styles-module__checked___8pype {\n border-color: #16a34a;\n background: #16a34a;\n color: #fff;\n}\n\n.styles-module__cardDone___-m4w- {\n opacity: 0.6;\n}\n.styles-module__cardDone___-m4w- .styles-module__cardTitle___xJxDN {\n text-decoration: line-through;\n color: #9ca3af;\n}\n\n.styles-module__backBtn___PTIAl {\n width: 28px;\n height: 28px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: #6b7280;\n transition: background 0.12s, color 0.12s;\n padding: 0;\n flex-shrink: 0;\n}\n.styles-module__backBtn___PTIAl:hover {\n background: #f3f4f6;\n color: #18181b;\n}\n\n.styles-module__detailView___36cvH {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.styles-module__detailHeader___Hepgq {\n display: flex;\n gap: 10px;\n padding: 16px 20px;\n border-bottom: 1px solid #f3f4f6;\n}\n\n.styles-module__detailTitle___7TvrX {\n font-size: 13px;\n color: #1a1a1a;\n line-height: 1.5;\n margin-top: 4px;\n}\n\n.styles-module__detailScreenshot___UPF0f {\n margin: 0 20px 0;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n overflow: hidden;\n max-height: 180px;\n}\n.styles-module__detailScreenshot___UPF0f img {\n width: 100%;\n height: auto;\n display: block;\n object-fit: cover;\n}\n\n.styles-module__commentsList___5Uigg {\n flex: 1;\n overflow-y: auto;\n padding: 8px 0;\n}\n.styles-module__commentsList___5Uigg::-webkit-scrollbar {\n width: 4px;\n}\n.styles-module__commentsList___5Uigg::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 2px;\n}\n\n.styles-module__commentItem___5u78u {\n display: flex;\n gap: 10px;\n padding: 10px 20px;\n}\n.styles-module__commentItem___5u78u:hover {\n background: #f9fafb;\n}\n\n.styles-module__commentAvatar___OatKg {\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: #16a34a;\n color: #fff;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.styles-module__commentBody___gmv1J {\n flex: 1;\n min-width: 0;\n}\n\n.styles-module__commentMeta___JNJa3 {\n display: flex;\n gap: 6px;\n align-items: center;\n margin-bottom: 2px;\n}\n\n.styles-module__commentAuthorName___XNVRk {\n font-size: 13px;\n font-weight: 600;\n color: #1a1a1a;\n}\n\n.styles-module__commentTime___CokGf {\n font-size: 12px;\n color: #9ca3af;\n}\n\n.styles-module__commentContent___yMiLR {\n font-size: 13px;\n color: #374151;\n line-height: 1.5;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.styles-module__loadingComments___zpATD, .styles-module__noComments___kvl90 {\n text-align: center;\n padding: 24px 20px;\n color: #9ca3af;\n font-size: 13px;\n}\n\n.styles-module__replyBox___FO-XS {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n padding: 12px 20px;\n border-top: 1px solid #f3f4f6;\n background: #fff;\n}\n\n.styles-module__replyInput___k8C9e {\n flex: 1;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n padding: 8px 12px;\n font-size: 13px;\n font-family: inherit;\n color: #1a1a1a;\n resize: none;\n outline: none;\n min-height: 20px;\n max-height: 80px;\n line-height: 1.5;\n transition: border-color 0.12s;\n}\n.styles-module__replyInput___k8C9e:focus {\n border-color: #18181b;\n}\n.styles-module__replyInput___k8C9e::placeholder {\n color: #9ca3af;\n}\n\n.styles-module__sendBtn___pBzWa {\n width: 32px;\n height: 32px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: #d1d5db;\n transition: color 0.12s;\n padding: 0;\n flex-shrink: 0;\n}\n.styles-module__sendBtn___pBzWa.styles-module__active___ZQzA5 {\n color: #3b82f6;\n}\n.styles-module__sendBtn___pBzWa:hover {\n color: #3b82f6;\n}\n\n.styles-module__commentImage___LuH8X {\n margin-top: 6px;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n overflow: hidden;\n max-width: 240px;\n cursor: pointer;\n transition: opacity 0.12s;\n}\n.styles-module__commentImage___LuH8X:hover {\n opacity: 0.9;\n}\n.styles-module__commentImage___LuH8X img {\n width: 100%;\n height: auto;\n display: block;\n}\n\n.styles-module__lightbox___8CDdt {\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n background: rgba(0, 0, 0, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: zoom-out;\n}\n.styles-module__lightbox___8CDdt img {\n max-width: 90vw;\n max-height: 90vh;\n border-radius: 8px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n cursor: default;\n}\n\n.styles-module__lightboxClose___VGfjh {\n position: absolute;\n top: 16px;\n right: 16px;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.15);\n color: #fff;\n border: none;\n cursor: pointer;\n font-size: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.styles-module__lightboxClose___VGfjh:hover {\n background: rgba(255, 255, 255, 0.25);\n}';
|
|
2479
|
-
var classNames5 = { "backdrop": "styles-module__backdrop___zYhcU", "fadeIn": "styles-module__fadeIn___j09Ts", "panel": "styles-module__panel___6YS8k", "slideIn": "styles-module__slideIn___0o0s-", "exiting": "styles-module__exiting___6A-Ag", "slideOut": "styles-module__slideOut___nKrBX", "header": "styles-module__header___fBbGz", "headerLeft": "styles-module__headerLeft___e0YLf", "headerTitle": "styles-module__headerTitle___oEPJa", "closeBtn": "styles-module__closeBtn___-H8ra", "tabs": "styles-module__tabs___nfuX7", "tab": "styles-module__tab___Hc-jn", "active": "styles-module__active___ZQzA5", "tabBadge": "styles-module__tabBadge___IdFDQ", "content": "styles-module__content___L2lRw", "card": "styles-module__card___F8qwd", "cardHeader": "styles-module__cardHeader___QOVGR", "cardAvatar": "styles-module__cardAvatar___FfKmW", "cardInfo": "styles-module__cardInfo___BmrdF", "cardMeta": "styles-module__cardMeta___7p9KD", "cardAuthor": "styles-module__cardAuthor___YvnuR", "cardTime": "styles-module__cardTime___N1Png", "cardActions": "styles-module__cardActions___7QF72", "cardAction": "styles-module__cardAction___t4b3V", "cardTitle": "styles-module__cardTitle___xJxDN", "cardScreenshot": "styles-module__cardScreenshot___I5-QL", "cardRoute": "styles-module__cardRoute___U4gB6", "cardRouteName": "styles-module__cardRouteName___BDH75", "cardRoutePath": "styles-module__cardRoutePath___zP-fh", "cardFooter": "styles-module__cardFooter___wfPa4", "cardReplyDot": "styles-module__cardReplyDot___YnqzI", "cardReplyCount": "styles-module__cardReplyCount___O1khL", "statusDot": "styles-module__statusDot___l4IHG", "todo": "styles-module__todo___894P6", "inProgress": "styles-module__inProgress___IZ1mJ", "done": "styles-module__done___n4cWP", "empty": "styles-module__empty___IADrw", "emptyIcon": "styles-module__emptyIcon___1x5wT", "checkBtn": "styles-module__checkBtn___KjHxm", "checked": "styles-module__checked___8pype", "cardDone": "styles-module__cardDone___-m4w-", "backBtn": "styles-module__backBtn___PTIAl", "detailView": "styles-module__detailView___36cvH", "detailHeader": "styles-module__detailHeader___Hepgq", "detailTitle": "styles-module__detailTitle___7TvrX", "detailScreenshot": "styles-module__detailScreenshot___UPF0f", "commentsList": "styles-module__commentsList___5Uigg", "commentItem": "styles-module__commentItem___5u78u", "commentAvatar": "styles-module__commentAvatar___OatKg", "commentBody": "styles-module__commentBody___gmv1J", "commentMeta": "styles-module__commentMeta___JNJa3", "commentAuthorName": "styles-module__commentAuthorName___XNVRk", "commentTime": "styles-module__commentTime___CokGf", "commentContent": "styles-module__commentContent___yMiLR", "loadingComments": "styles-module__loadingComments___zpATD", "noComments": "styles-module__noComments___kvl90", "replyBox": "styles-module__replyBox___FO-XS", "replyInput": "styles-module__replyInput___k8C9e", "sendBtn": "styles-module__sendBtn___pBzWa", "commentImage": "styles-module__commentImage___LuH8X", "lightbox": "styles-module__lightbox___8CDdt", "lightboxClose": "styles-module__lightboxClose___VGfjh" };
|
|
2716
|
+
var css5 = '@keyframes styles-module__slideIn___0o0s- {\n from {\n transform: translateX(100%);\n }\n to {\n transform: translateX(0);\n }\n}\n@keyframes styles-module__slideOut___nKrBX {\n from {\n transform: translateX(0);\n }\n to {\n transform: translateX(100%);\n }\n}\n@keyframes styles-module__fadeIn___j09Ts {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n.styles-module__backdrop___zYhcU {\n position: fixed;\n inset: 0;\n z-index: 100003;\n animation: styles-module__fadeIn___j09Ts 0.15s ease-out;\n}\n\n.styles-module__panel___6YS8k {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 420px;\n max-width: 100vw;\n background: #fafafa;\n z-index: 100004;\n display: flex;\n flex-direction: column;\n box-shadow: -4px 0 24px rgba(0, 0, 0, 0.08);\n animation: styles-module__slideIn___0o0s- 0.2s ease-out;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n}\n.styles-module__panel___6YS8k.styles-module__exiting___6A-Ag {\n animation: styles-module__slideOut___nKrBX 0.15s ease-in forwards;\n}\n\n.styles-module__header___fBbGz {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid #e5e7eb;\n background: #fff;\n flex-shrink: 0;\n}\n\n.styles-module__headerLeft___e0YLf {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.styles-module__headerTitle___oEPJa {\n font-size: 14px;\n font-weight: 600;\n color: #18181b;\n}\n\n.styles-module__closeBtn___-H8ra {\n width: 32px;\n height: 32px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: #6b7280;\n transition: background 0.12s, color 0.12s;\n}\n.styles-module__closeBtn___-H8ra:hover {\n background: #f3f4f6;\n color: #18181b;\n}\n.styles-module__closeBtn___-H8ra svg {\n width: 18px;\n height: 18px;\n}\n\n.styles-module__tabs___nfuX7 {\n display: flex;\n padding: 0 20px;\n gap: 0;\n border-bottom: 1px solid #e5e7eb;\n background: #fff;\n flex-shrink: 0;\n}\n\n.styles-module__tab___Hc-jn {\n padding: 10px 16px;\n font-size: 13px;\n font-weight: 500;\n color: #6b7280;\n border: none;\n background: none;\n cursor: pointer;\n border-bottom: 2px solid transparent;\n transition: color 0.12s, border-color 0.12s;\n font-family: inherit;\n}\n.styles-module__tab___Hc-jn:hover {\n color: #374151;\n}\n.styles-module__tab___Hc-jn.styles-module__active___ZQzA5 {\n color: #18181b;\n border-bottom-color: #18181b;\n}\n\n.styles-module__tabBadge___IdFDQ {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n border-radius: 9px;\n background: #e5e7eb;\n color: #374151;\n font-size: 11px;\n font-weight: 600;\n padding: 0 5px;\n margin-left: 6px;\n}\n\n.styles-module__content___L2lRw {\n flex: 1;\n overflow-y: auto;\n padding: 12px;\n}\n.styles-module__content___L2lRw::-webkit-scrollbar {\n width: 4px;\n}\n.styles-module__content___L2lRw::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 2px;\n}\n\n.styles-module__card___F8qwd {\n background: #fff;\n border-radius: 12px;\n border: 1px solid #e5e7eb;\n margin-bottom: 12px;\n overflow: hidden;\n transition: box-shadow 0.12s;\n cursor: pointer;\n}\n.styles-module__card___F8qwd:hover {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n}\n\n.styles-module__cardHeader___QOVGR {\n padding: 14px 16px 8px;\n display: flex;\n align-items: flex-start;\n gap: 10px;\n}\n\n.styles-module__cardAvatar___FfKmW {\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: #16a34a;\n color: #fff;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.styles-module__cardInfo___BmrdF {\n flex: 1;\n min-width: 0;\n}\n\n.styles-module__cardMeta___7p9KD {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 4px;\n}\n\n.styles-module__cardAuthor___YvnuR {\n font-size: 13px;\n font-weight: 600;\n color: #18181b;\n}\n\n.styles-module__cardTime___N1Png {\n font-size: 12px;\n color: #9ca3af;\n}\n\n.styles-module__cardActions___7QF72 {\n display: flex;\n gap: 2px;\n flex-shrink: 0;\n}\n\n.styles-module__cardAction___t4b3V {\n width: 26px;\n height: 26px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 5px;\n color: #9ca3af;\n transition: background 0.12s, color 0.12s;\n padding: 0;\n}\n.styles-module__cardAction___t4b3V:hover {\n background: #f3f4f6;\n color: #374151;\n}\n.styles-module__cardAction___t4b3V svg {\n width: 14px;\n height: 14px;\n}\n\n.styles-module__cardTitle___xJxDN {\n font-size: 13px;\n color: #1a1a1a;\n line-height: 1.5;\n padding: 0 16px 8px;\n}\n\n.styles-module__cardScreenshot___I5-QL {\n margin: 0 16px 8px;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n overflow: hidden;\n position: relative;\n max-height: 160px;\n}\n.styles-module__cardScreenshot___I5-QL img {\n width: 100%;\n height: auto;\n display: block;\n object-fit: cover;\n}\n\n.styles-module__cardRoute___U4gB6 {\n margin: 0 16px 10px;\n padding: 8px 12px;\n background: #f9fafb;\n border: 1px solid #f3f4f6;\n border-radius: 8px;\n font-size: 12px;\n color: #6b7280;\n line-height: 1.4;\n}\n\n.styles-module__cardRouteName___BDH75 {\n font-weight: 500;\n color: #374151;\n}\n\n.styles-module__cardRoutePath___zP-fh {\n color: #9ca3af;\n}\n\n.styles-module__cardFooter___wfPa4 {\n padding: 8px 16px 12px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.styles-module__cardReplyDot___YnqzI {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #16a34a;\n flex-shrink: 0;\n}\n\n.styles-module__cardReplyCount___O1khL {\n font-size: 12px;\n font-weight: 500;\n color: #374151;\n}\n\n.styles-module__statusDot___l4IHG {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n.styles-module__statusDot___l4IHG.styles-module__todo___894P6 {\n background: #f59e0b;\n}\n.styles-module__statusDot___l4IHG.styles-module__inProgress___IZ1mJ {\n background: #3b82f6;\n}\n.styles-module__statusDot___l4IHG.styles-module__done___n4cWP {\n background: #16a34a;\n}\n\n.styles-module__empty___IADrw {\n text-align: center;\n padding: 48px 20px;\n color: #9ca3af;\n font-size: 13px;\n line-height: 1.6;\n}\n\n.styles-module__emptyIcon___1x5wT {\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: #f3f4f6;\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 12px;\n color: #9ca3af;\n}\n.styles-module__emptyIcon___1x5wT svg {\n width: 24px;\n height: 24px;\n}\n\n.styles-module__checkBtn___KjHxm {\n width: 28px;\n height: 28px;\n border: 2px solid #d1d5db;\n border-radius: 50%;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: transparent;\n transition: all 0.15s;\n padding: 0;\n flex-shrink: 0;\n}\n.styles-module__checkBtn___KjHxm svg {\n width: 14px;\n height: 14px;\n}\n.styles-module__checkBtn___KjHxm:hover {\n border-color: #16a34a;\n color: #16a34a;\n}\n.styles-module__checkBtn___KjHxm.styles-module__checked___8pype {\n border-color: #16a34a;\n background: #16a34a;\n color: #fff;\n}\n\n.styles-module__cardDone___-m4w- {\n opacity: 0.6;\n}\n.styles-module__cardDone___-m4w- .styles-module__cardTitle___xJxDN {\n text-decoration: line-through;\n color: #9ca3af;\n}\n\n.styles-module__backBtn___PTIAl {\n width: 28px;\n height: 28px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: #6b7280;\n transition: background 0.12s, color 0.12s;\n padding: 0;\n flex-shrink: 0;\n}\n.styles-module__backBtn___PTIAl:hover {\n background: #f3f4f6;\n color: #18181b;\n}\n\n.styles-module__detailView___36cvH {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.styles-module__detailHeader___Hepgq {\n display: flex;\n gap: 10px;\n padding: 16px 20px;\n border-bottom: 1px solid #f3f4f6;\n}\n\n.styles-module__detailTitle___7TvrX {\n font-size: 13px;\n color: #1a1a1a;\n line-height: 1.5;\n margin-top: 4px;\n}\n\n.styles-module__detailScreenshot___UPF0f {\n margin: 0 20px 0;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n overflow: hidden;\n max-height: 180px;\n}\n.styles-module__detailScreenshot___UPF0f img {\n width: 100%;\n height: auto;\n display: block;\n object-fit: cover;\n}\n\n.styles-module__commentsList___5Uigg {\n flex: 1;\n overflow-y: auto;\n padding: 8px 0;\n}\n.styles-module__commentsList___5Uigg::-webkit-scrollbar {\n width: 4px;\n}\n.styles-module__commentsList___5Uigg::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 2px;\n}\n\n.styles-module__commentItem___5u78u {\n display: flex;\n gap: 10px;\n padding: 10px 20px;\n}\n.styles-module__commentItem___5u78u:hover {\n background: #f9fafb;\n}\n\n.styles-module__commentAvatar___OatKg {\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: #16a34a;\n color: #fff;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 11px;\n font-weight: 600;\n flex-shrink: 0;\n}\n\n.styles-module__commentBody___gmv1J {\n flex: 1;\n min-width: 0;\n}\n\n.styles-module__commentMeta___JNJa3 {\n display: flex;\n gap: 6px;\n align-items: center;\n margin-bottom: 2px;\n}\n\n.styles-module__commentAuthorName___XNVRk {\n font-size: 13px;\n font-weight: 600;\n color: #1a1a1a;\n}\n\n.styles-module__commentTime___CokGf {\n font-size: 12px;\n color: #9ca3af;\n}\n\n.styles-module__commentContent___yMiLR {\n font-size: 13px;\n color: #374151;\n line-height: 1.5;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.styles-module__loadingComments___zpATD, .styles-module__noComments___kvl90 {\n text-align: center;\n padding: 24px 20px;\n color: #9ca3af;\n font-size: 13px;\n}\n\n.styles-module__replyBox___FO-XS {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n padding: 12px 20px;\n border-top: 1px solid #f3f4f6;\n background: #fff;\n}\n\n.styles-module__replyInput___k8C9e {\n flex: 1;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n padding: 8px 12px;\n font-size: 13px;\n font-family: inherit;\n color: #1a1a1a;\n resize: none;\n outline: none;\n min-height: 20px;\n max-height: 80px;\n line-height: 1.5;\n transition: border-color 0.12s;\n}\n.styles-module__replyInput___k8C9e:focus {\n border-color: #18181b;\n}\n.styles-module__replyInput___k8C9e::placeholder {\n color: #9ca3af;\n}\n\n.styles-module__sendBtn___pBzWa {\n width: 32px;\n height: 32px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: #d1d5db;\n transition: color 0.12s;\n padding: 0;\n flex-shrink: 0;\n}\n.styles-module__sendBtn___pBzWa.styles-module__active___ZQzA5 {\n color: #3b82f6;\n}\n.styles-module__sendBtn___pBzWa:hover {\n color: #3b82f6;\n}\n\n.styles-module__commentImage___LuH8X {\n margin-top: 6px;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n overflow: hidden;\n max-width: 240px;\n cursor: pointer;\n transition: opacity 0.12s;\n}\n.styles-module__commentImage___LuH8X:hover {\n opacity: 0.9;\n}\n.styles-module__commentImage___LuH8X img {\n width: 100%;\n height: auto;\n display: block;\n}\n\n.styles-module__commentFileCard___XE44y {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 6px;\n padding: 8px 10px;\n border-radius: 8px;\n border: 1px solid #e5e7eb;\n background: #f9fafb;\n cursor: pointer;\n transition: background 0.12s;\n max-width: 240px;\n}\n.styles-module__commentFileCard___XE44y:hover {\n background: #f3f4f6;\n}\n\n.styles-module__commentFileIcon___G58-y {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n background: #e5e7eb;\n color: #374151;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 10px;\n font-weight: 700;\n flex-shrink: 0;\n letter-spacing: 0.5px;\n}\n\n.styles-module__commentFileInfo___OFIhR {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 1px;\n}\n\n.styles-module__commentFileName___NUoII {\n font-size: 12px;\n font-weight: 500;\n color: #1a1a1a;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.styles-module__commentFileSize___sokU8 {\n font-size: 11px;\n color: #9ca3af;\n}\n\n.styles-module__filePreviewOverlay___5RxYd {\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n background: rgba(0, 0, 0, 0.6);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.styles-module__filePreviewModal___MGJLW {\n width: 90vw;\n max-width: 960px;\n height: 80vh;\n background: #fff;\n border-radius: 12px;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n}\n\n.styles-module__filePreviewHeader___E9SWJ {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid #e5e7eb;\n flex-shrink: 0;\n}\n\n.styles-module__filePreviewName___z8t-L {\n font-size: 14px;\n font-weight: 600;\n color: #18181b;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n flex: 1;\n min-width: 0;\n}\n\n.styles-module__filePreviewActions___weizo {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.styles-module__filePreviewOpen___JpaEs {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n font-weight: 500;\n color: #3b82f6;\n text-decoration: none;\n padding: 4px 8px;\n border-radius: 6px;\n transition: background 0.12s;\n}\n.styles-module__filePreviewOpen___JpaEs:hover {\n background: #eff6ff;\n}\n\n.styles-module__filePreviewClose___TFcbr {\n width: 28px;\n height: 28px;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n color: #6b7280;\n font-size: 18px;\n transition: background 0.12s, color 0.12s;\n}\n.styles-module__filePreviewClose___TFcbr:hover {\n background: #f3f4f6;\n color: #18181b;\n}\n\n.styles-module__filePreviewBody___gwg1S {\n flex: 1;\n overflow: hidden;\n}\n\n.styles-module__filePreviewIframe___OQ3Oo {\n width: 100%;\n height: 100%;\n border: none;\n}\n\n.styles-module__filePreviewFallback___U1rB2 {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 12px;\n color: #6b7280;\n font-size: 14px;\n}\n.styles-module__filePreviewFallback___U1rB2 a {\n color: #3b82f6;\n text-decoration: none;\n font-weight: 500;\n}\n.styles-module__filePreviewFallback___U1rB2 a:hover {\n text-decoration: underline;\n}\n\n.styles-module__filePreviewFallbackIcon___0--41 {\n width: 56px;\n height: 56px;\n border-radius: 12px;\n background: #f3f4f6;\n color: #6b7280;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: 700;\n}\n\n.styles-module__lightbox___8CDdt {\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n background: rgba(0, 0, 0, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: zoom-out;\n}\n.styles-module__lightbox___8CDdt img {\n max-width: 90vw;\n max-height: 90vh;\n border-radius: 8px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n cursor: default;\n}\n\n.styles-module__lightboxClose___VGfjh {\n position: absolute;\n top: 16px;\n right: 16px;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.15);\n color: #fff;\n border: none;\n cursor: pointer;\n font-size: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.styles-module__lightboxClose___VGfjh:hover {\n background: rgba(255, 255, 255, 0.25);\n}';
|
|
2717
|
+
var classNames5 = { "backdrop": "styles-module__backdrop___zYhcU", "fadeIn": "styles-module__fadeIn___j09Ts", "panel": "styles-module__panel___6YS8k", "slideIn": "styles-module__slideIn___0o0s-", "exiting": "styles-module__exiting___6A-Ag", "slideOut": "styles-module__slideOut___nKrBX", "header": "styles-module__header___fBbGz", "headerLeft": "styles-module__headerLeft___e0YLf", "headerTitle": "styles-module__headerTitle___oEPJa", "closeBtn": "styles-module__closeBtn___-H8ra", "tabs": "styles-module__tabs___nfuX7", "tab": "styles-module__tab___Hc-jn", "active": "styles-module__active___ZQzA5", "tabBadge": "styles-module__tabBadge___IdFDQ", "content": "styles-module__content___L2lRw", "card": "styles-module__card___F8qwd", "cardHeader": "styles-module__cardHeader___QOVGR", "cardAvatar": "styles-module__cardAvatar___FfKmW", "cardInfo": "styles-module__cardInfo___BmrdF", "cardMeta": "styles-module__cardMeta___7p9KD", "cardAuthor": "styles-module__cardAuthor___YvnuR", "cardTime": "styles-module__cardTime___N1Png", "cardActions": "styles-module__cardActions___7QF72", "cardAction": "styles-module__cardAction___t4b3V", "cardTitle": "styles-module__cardTitle___xJxDN", "cardScreenshot": "styles-module__cardScreenshot___I5-QL", "cardRoute": "styles-module__cardRoute___U4gB6", "cardRouteName": "styles-module__cardRouteName___BDH75", "cardRoutePath": "styles-module__cardRoutePath___zP-fh", "cardFooter": "styles-module__cardFooter___wfPa4", "cardReplyDot": "styles-module__cardReplyDot___YnqzI", "cardReplyCount": "styles-module__cardReplyCount___O1khL", "statusDot": "styles-module__statusDot___l4IHG", "todo": "styles-module__todo___894P6", "inProgress": "styles-module__inProgress___IZ1mJ", "done": "styles-module__done___n4cWP", "empty": "styles-module__empty___IADrw", "emptyIcon": "styles-module__emptyIcon___1x5wT", "checkBtn": "styles-module__checkBtn___KjHxm", "checked": "styles-module__checked___8pype", "cardDone": "styles-module__cardDone___-m4w-", "backBtn": "styles-module__backBtn___PTIAl", "detailView": "styles-module__detailView___36cvH", "detailHeader": "styles-module__detailHeader___Hepgq", "detailTitle": "styles-module__detailTitle___7TvrX", "detailScreenshot": "styles-module__detailScreenshot___UPF0f", "commentsList": "styles-module__commentsList___5Uigg", "commentItem": "styles-module__commentItem___5u78u", "commentAvatar": "styles-module__commentAvatar___OatKg", "commentBody": "styles-module__commentBody___gmv1J", "commentMeta": "styles-module__commentMeta___JNJa3", "commentAuthorName": "styles-module__commentAuthorName___XNVRk", "commentTime": "styles-module__commentTime___CokGf", "commentContent": "styles-module__commentContent___yMiLR", "loadingComments": "styles-module__loadingComments___zpATD", "noComments": "styles-module__noComments___kvl90", "replyBox": "styles-module__replyBox___FO-XS", "replyInput": "styles-module__replyInput___k8C9e", "sendBtn": "styles-module__sendBtn___pBzWa", "commentImage": "styles-module__commentImage___LuH8X", "commentFileCard": "styles-module__commentFileCard___XE44y", "commentFileIcon": "styles-module__commentFileIcon___G58-y", "commentFileInfo": "styles-module__commentFileInfo___OFIhR", "commentFileName": "styles-module__commentFileName___NUoII", "commentFileSize": "styles-module__commentFileSize___sokU8", "filePreviewOverlay": "styles-module__filePreviewOverlay___5RxYd", "filePreviewModal": "styles-module__filePreviewModal___MGJLW", "filePreviewHeader": "styles-module__filePreviewHeader___E9SWJ", "filePreviewName": "styles-module__filePreviewName___z8t-L", "filePreviewActions": "styles-module__filePreviewActions___weizo", "filePreviewOpen": "styles-module__filePreviewOpen___JpaEs", "filePreviewClose": "styles-module__filePreviewClose___TFcbr", "filePreviewBody": "styles-module__filePreviewBody___gwg1S", "filePreviewIframe": "styles-module__filePreviewIframe___OQ3Oo", "filePreviewFallback": "styles-module__filePreviewFallback___U1rB2", "filePreviewFallbackIcon": "styles-module__filePreviewFallbackIcon___0--41", "lightbox": "styles-module__lightbox___8CDdt", "lightboxClose": "styles-module__lightboxClose___VGfjh" };
|
|
2480
2718
|
if (typeof document !== "undefined") {
|
|
2481
2719
|
let style = document.getElementById("impakers-debug-styles-inbox-panel-styles");
|
|
2482
2720
|
if (!style) {
|
|
@@ -2503,6 +2741,74 @@ function ImageLightbox({ src, onClose }) {
|
|
|
2503
2741
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: styles_module_default5.lightboxClose, onClick: onClose, type: "button", children: "\xD7" })
|
|
2504
2742
|
] });
|
|
2505
2743
|
}
|
|
2744
|
+
function formatFileSize2(bytes) {
|
|
2745
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
2746
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)}KB`;
|
|
2747
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
2748
|
+
}
|
|
2749
|
+
function getFileIcon2(mimeType) {
|
|
2750
|
+
if (mimeType.includes("pdf")) return "PDF";
|
|
2751
|
+
if (mimeType.includes("spreadsheet") || mimeType.includes("excel") || mimeType.includes("csv")) return "XLS";
|
|
2752
|
+
if (mimeType.includes("presentation") || mimeType.includes("powerpoint")) return "PPT";
|
|
2753
|
+
if (mimeType.includes("document") || mimeType.includes("word")) return "DOC";
|
|
2754
|
+
if (mimeType.includes("zip") || mimeType.includes("compressed") || mimeType.includes("archive")) return "ZIP";
|
|
2755
|
+
if (mimeType.includes("video")) return "VID";
|
|
2756
|
+
if (mimeType.includes("audio")) return "AUD";
|
|
2757
|
+
return "FILE";
|
|
2758
|
+
}
|
|
2759
|
+
function extractDriveFileId(url) {
|
|
2760
|
+
const match = url.match(/\/d\/([^/]+)/);
|
|
2761
|
+
return match ? match[1] : null;
|
|
2762
|
+
}
|
|
2763
|
+
function getPreviewSrc(fileUrl, fileType, fileSource) {
|
|
2764
|
+
const isOffice = /\.(pptx?|xlsx?|docx?)$/i.test(fileUrl) || fileType.includes("presentation") || fileType.includes("powerpoint") || fileType.includes("spreadsheet") || fileType.includes("excel") || fileType.includes("document") || fileType.includes("word") || fileType.includes("msword");
|
|
2765
|
+
if (fileSource === "google_drive") {
|
|
2766
|
+
const fileId = extractDriveFileId(fileUrl);
|
|
2767
|
+
if (fileId) return `https://drive.google.com/file/d/${fileId}/preview`;
|
|
2768
|
+
}
|
|
2769
|
+
if (isOffice && fileSource !== "google_drive") {
|
|
2770
|
+
return `https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(fileUrl)}`;
|
|
2771
|
+
}
|
|
2772
|
+
if (fileType.includes("pdf")) return fileUrl;
|
|
2773
|
+
return null;
|
|
2774
|
+
}
|
|
2775
|
+
function FilePreviewModal({
|
|
2776
|
+
fileUrl,
|
|
2777
|
+
fileName,
|
|
2778
|
+
fileType,
|
|
2779
|
+
fileSource,
|
|
2780
|
+
onClose
|
|
2781
|
+
}) {
|
|
2782
|
+
(0, import_react5.useEffect)(() => {
|
|
2783
|
+
const handler = (e) => {
|
|
2784
|
+
if (e.key === "Escape") onClose();
|
|
2785
|
+
};
|
|
2786
|
+
document.addEventListener("keydown", handler);
|
|
2787
|
+
return () => document.removeEventListener("keydown", handler);
|
|
2788
|
+
}, [onClose]);
|
|
2789
|
+
const previewSrc = getPreviewSrc(fileUrl, fileType, fileSource);
|
|
2790
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: styles_module_default5.filePreviewOverlay, onClick: onClose, "data-impakers-debug": "", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: styles_module_default5.filePreviewModal, onClick: (e) => e.stopPropagation(), children: [
|
|
2791
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: styles_module_default5.filePreviewHeader, children: [
|
|
2792
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: styles_module_default5.filePreviewName, children: fileName }),
|
|
2793
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: styles_module_default5.filePreviewActions, children: [
|
|
2794
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("a", { href: fileUrl, target: "_blank", rel: "noopener noreferrer", className: styles_module_default5.filePreviewOpen, children: [
|
|
2795
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", width: "14", height: "14", children: [
|
|
2796
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" }),
|
|
2797
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("polyline", { points: "15 3 21 3 21 9" }),
|
|
2798
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
|
|
2799
|
+
] }),
|
|
2800
|
+
"\uC5F4\uAE30"
|
|
2801
|
+
] }),
|
|
2802
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: styles_module_default5.filePreviewClose, onClick: onClose, type: "button", children: "\xD7" })
|
|
2803
|
+
] })
|
|
2804
|
+
] }),
|
|
2805
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: styles_module_default5.filePreviewBody, children: previewSrc ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("iframe", { src: previewSrc, className: styles_module_default5.filePreviewIframe, title: fileName }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: styles_module_default5.filePreviewFallback, children: [
|
|
2806
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: styles_module_default5.filePreviewFallbackIcon, children: getFileIcon2(fileType) }),
|
|
2807
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "\uBBF8\uB9AC\uBCF4\uAE30\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C \uD615\uC2DD\uC785\uB2C8\uB2E4" }),
|
|
2808
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("a", { href: fileUrl, target: "_blank", rel: "noopener noreferrer", children: "\uD30C\uC77C \uC5F4\uAE30" })
|
|
2809
|
+
] }) })
|
|
2810
|
+
] }) });
|
|
2811
|
+
}
|
|
2506
2812
|
function timeAgo2(dateStr) {
|
|
2507
2813
|
const diff = Date.now() - new Date(dateStr).getTime();
|
|
2508
2814
|
const m = Math.floor(diff / 6e4);
|
|
@@ -2535,6 +2841,7 @@ function InboxPanel({
|
|
|
2535
2841
|
const [loadingComments, setLoadingComments] = (0, import_react5.useState)(false);
|
|
2536
2842
|
const [replyText, setReplyText] = (0, import_react5.useState)("");
|
|
2537
2843
|
const [lightboxSrc, setLightboxSrc] = (0, import_react5.useState)(null);
|
|
2844
|
+
const [filePreview, setFilePreview] = (0, import_react5.useState)(null);
|
|
2538
2845
|
const replyRef = (0, import_react5.useRef)(null);
|
|
2539
2846
|
const commentsEndRef = (0, import_react5.useRef)(null);
|
|
2540
2847
|
const handleClose = (0, import_react5.useCallback)(() => {
|
|
@@ -2553,16 +2860,30 @@ function InboxPanel({
|
|
|
2553
2860
|
return;
|
|
2554
2861
|
}
|
|
2555
2862
|
setSelectedItem(item);
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2863
|
+
const cached = getCachedSnapshot(getCommentsCacheKey(item.id));
|
|
2864
|
+
setComments(cached || []);
|
|
2865
|
+
setLoadingComments(!cached);
|
|
2866
|
+
}, [endpoint]);
|
|
2867
|
+
(0, import_react5.useEffect)(() => {
|
|
2868
|
+
if (!selectedItem) return;
|
|
2869
|
+
const cacheKey = getCommentsCacheKey(selectedItem.id);
|
|
2870
|
+
const cached = getCachedSnapshot(cacheKey);
|
|
2871
|
+
if (cached) {
|
|
2872
|
+
setComments(cached);
|
|
2563
2873
|
setLoadingComments(false);
|
|
2564
2874
|
}
|
|
2565
|
-
|
|
2875
|
+
const unsubscribe = subscribeCache(cacheKey, (nextComments) => {
|
|
2876
|
+
setComments(nextComments);
|
|
2877
|
+
setLoadingComments(false);
|
|
2878
|
+
});
|
|
2879
|
+
fetchComments(endpoint, selectedItem.id, { staleWhileRevalidate: true }).then((data) => {
|
|
2880
|
+
setComments(data);
|
|
2881
|
+
setLoadingComments(false);
|
|
2882
|
+
}).catch(() => {
|
|
2883
|
+
setLoadingComments(false);
|
|
2884
|
+
});
|
|
2885
|
+
return unsubscribe;
|
|
2886
|
+
}, [selectedItem, endpoint]);
|
|
2566
2887
|
(0, import_react5.useEffect)(() => {
|
|
2567
2888
|
commentsEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
2568
2889
|
}, [comments.length]);
|
|
@@ -2573,17 +2894,8 @@ function InboxPanel({
|
|
|
2573
2894
|
if (!replyText.trim() || !selectedItem) return;
|
|
2574
2895
|
const content = replyText.trim();
|
|
2575
2896
|
setReplyText("");
|
|
2576
|
-
const temp = {
|
|
2577
|
-
id: `temp-${Date.now()}`,
|
|
2578
|
-
content,
|
|
2579
|
-
authorName: currentUserName,
|
|
2580
|
-
authorId: currentUserId,
|
|
2581
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2582
|
-
};
|
|
2583
|
-
setComments((prev) => [...prev, temp]);
|
|
2584
2897
|
try {
|
|
2585
|
-
|
|
2586
|
-
setComments((prev) => prev.map((c) => c.id === temp.id ? serverComment : c));
|
|
2898
|
+
await postComment(endpoint, selectedItem.id, content, currentUserName, currentUserId);
|
|
2587
2899
|
} catch (err) {
|
|
2588
2900
|
console.error("[@impakers/debug] \uCF54\uBA58\uD2B8 \uC804\uC1A1 \uC2E4\uD328:", err);
|
|
2589
2901
|
}
|
|
@@ -2597,15 +2909,12 @@ function InboxPanel({
|
|
|
2597
2909
|
}
|
|
2598
2910
|
if (e.key === "Escape") handleClose();
|
|
2599
2911
|
}, [handleSendReply, handleClose]);
|
|
2600
|
-
const [statusOverrides, setStatusOverrides] = (0, import_react5.useState)({});
|
|
2601
2912
|
const handleToggleStatus = (0, import_react5.useCallback)((item, e) => {
|
|
2602
2913
|
e.stopPropagation();
|
|
2603
2914
|
const newStatus = item.status === "done" ? "todo" : "done";
|
|
2604
|
-
setStatusOverrides((prev) => ({ ...prev, [item.id]: newStatus }));
|
|
2605
2915
|
onStatusChange?.(item.id, newStatus);
|
|
2606
2916
|
}, [onStatusChange]);
|
|
2607
|
-
const
|
|
2608
|
-
const items = applyOverrides(tab === "page" ? pageItems : allItems);
|
|
2917
|
+
const items = tab === "page" ? pageItems : allItems;
|
|
2609
2918
|
if (typeof document === "undefined") return null;
|
|
2610
2919
|
return (0, import_react_dom.createPortal)(
|
|
2611
2920
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { "data-impakers-debug": "", children: [
|
|
@@ -2654,6 +2963,28 @@ function InboxPanel({
|
|
|
2654
2963
|
},
|
|
2655
2964
|
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("img", { src: c.imageUrl, alt: "attachment" })
|
|
2656
2965
|
}
|
|
2966
|
+
),
|
|
2967
|
+
c.fileUrl && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2968
|
+
"div",
|
|
2969
|
+
{
|
|
2970
|
+
className: styles_module_default5.commentFileCard,
|
|
2971
|
+
onClick: (e) => {
|
|
2972
|
+
e.stopPropagation();
|
|
2973
|
+
setFilePreview({
|
|
2974
|
+
url: c.fileUrl,
|
|
2975
|
+
name: c.fileName || "\uD30C\uC77C",
|
|
2976
|
+
type: c.fileType || "",
|
|
2977
|
+
source: c.fileSource
|
|
2978
|
+
});
|
|
2979
|
+
},
|
|
2980
|
+
children: [
|
|
2981
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: styles_module_default5.commentFileIcon, children: getFileIcon2(c.fileType || "") }),
|
|
2982
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: styles_module_default5.commentFileInfo, children: [
|
|
2983
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: styles_module_default5.commentFileName, children: c.fileName || "\uD30C\uC77C" }),
|
|
2984
|
+
c.fileSize != null && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: styles_module_default5.commentFileSize, children: formatFileSize2(c.fileSize) })
|
|
2985
|
+
] })
|
|
2986
|
+
]
|
|
2987
|
+
}
|
|
2657
2988
|
)
|
|
2658
2989
|
] })
|
|
2659
2990
|
] }, c.id)),
|
|
@@ -2732,7 +3063,17 @@ function InboxPanel({
|
|
|
2732
3063
|
] }, item.id)) })
|
|
2733
3064
|
] })
|
|
2734
3065
|
] }),
|
|
2735
|
-
lightboxSrc && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ImageLightbox, { src: lightboxSrc, onClose: () => setLightboxSrc(null) })
|
|
3066
|
+
lightboxSrc && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ImageLightbox, { src: lightboxSrc, onClose: () => setLightboxSrc(null) }),
|
|
3067
|
+
filePreview && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3068
|
+
FilePreviewModal,
|
|
3069
|
+
{
|
|
3070
|
+
fileUrl: filePreview.url,
|
|
3071
|
+
fileName: filePreview.name,
|
|
3072
|
+
fileType: filePreview.type,
|
|
3073
|
+
fileSource: filePreview.source,
|
|
3074
|
+
onClose: () => setFilePreview(null)
|
|
3075
|
+
}
|
|
3076
|
+
)
|
|
2736
3077
|
] }),
|
|
2737
3078
|
document.body
|
|
2738
3079
|
);
|
|
@@ -2915,6 +3256,20 @@ function saveRouteAnnotations(annotations) {
|
|
|
2915
3256
|
} catch {
|
|
2916
3257
|
}
|
|
2917
3258
|
}
|
|
3259
|
+
function taskToAnnotation(task) {
|
|
3260
|
+
if (!task.feedbackMarker) return null;
|
|
3261
|
+
return {
|
|
3262
|
+
id: task.id,
|
|
3263
|
+
x: task.feedbackMarker.x,
|
|
3264
|
+
y: task.feedbackMarker.y,
|
|
3265
|
+
comment: task.title.replace(/^\[피드백\]\s*/, ""),
|
|
3266
|
+
element: task.feedbackMarker.element || "",
|
|
3267
|
+
elementPath: "",
|
|
3268
|
+
timestamp: new Date(task.createdAt).getTime(),
|
|
3269
|
+
isFixed: task.feedbackMarker.isFixed,
|
|
3270
|
+
boundingBox: task.feedbackMarker.boundingBox
|
|
3271
|
+
};
|
|
3272
|
+
}
|
|
2918
3273
|
function DebugWidget({ endpoint, getUser, onHide }) {
|
|
2919
3274
|
const [isActive, setIsActive] = (0, import_react7.useState)(false);
|
|
2920
3275
|
const [annotations, setAnnotations] = (0, import_react7.useState)(() => loadRouteAnnotations());
|
|
@@ -2933,6 +3288,8 @@ function DebugWidget({ endpoint, getUser, onHide }) {
|
|
|
2933
3288
|
const [showInbox, setShowInbox] = (0, import_react7.useState)(false);
|
|
2934
3289
|
const [showSettings, setShowSettings] = (0, import_react7.useState)(false);
|
|
2935
3290
|
const [settings, setSettings] = (0, import_react7.useState)(() => loadSettings());
|
|
3291
|
+
const [routePath, setRoutePath] = (0, import_react7.useState)(() => window.location.pathname);
|
|
3292
|
+
const [hasHydratedServerTasks, setHasHydratedServerTasks] = (0, import_react7.useState)(false);
|
|
2936
3293
|
const popupRef = (0, import_react7.useRef)(null);
|
|
2937
3294
|
const recentlyAddedIdRef = (0, import_react7.useRef)(null);
|
|
2938
3295
|
const justSubmittedRef = (0, import_react7.useRef)(false);
|
|
@@ -2976,6 +3333,7 @@ function DebugWidget({ endpoint, getUser, onHide }) {
|
|
|
2976
3333
|
(0, import_react7.useEffect)(() => {
|
|
2977
3334
|
setAnnotations(loadRouteAnnotations());
|
|
2978
3335
|
const handleRouteChange = () => {
|
|
3336
|
+
setRoutePath(window.location.pathname);
|
|
2979
3337
|
setAnnotations(loadRouteAnnotations());
|
|
2980
3338
|
setPendingAnnotation(null);
|
|
2981
3339
|
setHoverInfo(null);
|
|
@@ -2992,25 +3350,29 @@ function DebugWidget({ endpoint, getUser, onHide }) {
|
|
|
2992
3350
|
};
|
|
2993
3351
|
}, []);
|
|
2994
3352
|
(0, import_react7.useEffect)(() => {
|
|
2995
|
-
const
|
|
2996
|
-
|
|
3353
|
+
const cacheKey = getFeedbacksCacheKey(routePath);
|
|
3354
|
+
const cached = getCachedSnapshot(cacheKey);
|
|
3355
|
+
if (cached) {
|
|
3356
|
+
setServerTasks(cached);
|
|
3357
|
+
setHasHydratedServerTasks(true);
|
|
3358
|
+
}
|
|
3359
|
+
const unsubscribe = subscribeCache(cacheKey, (tasks) => {
|
|
3360
|
+
setServerTasks(tasks);
|
|
3361
|
+
setHasHydratedServerTasks(true);
|
|
3362
|
+
});
|
|
3363
|
+
fetchFeedbacks(endpoint, routePath, { staleWhileRevalidate: true }).then((tasks) => {
|
|
2997
3364
|
setServerTasks(tasks);
|
|
2998
|
-
|
|
2999
|
-
id: t.id,
|
|
3000
|
-
x: t.feedbackMarker.x,
|
|
3001
|
-
y: t.feedbackMarker.y,
|
|
3002
|
-
comment: t.title.replace(/^\[피드백\]\s*/, ""),
|
|
3003
|
-
element: t.feedbackMarker.element || "",
|
|
3004
|
-
elementPath: "",
|
|
3005
|
-
timestamp: new Date(t.createdAt).getTime(),
|
|
3006
|
-
isFixed: t.feedbackMarker.isFixed,
|
|
3007
|
-
boundingBox: t.feedbackMarker.boundingBox
|
|
3008
|
-
}));
|
|
3009
|
-
setAnnotations(serverAnnotations);
|
|
3010
|
-
saveRouteAnnotations(serverAnnotations);
|
|
3365
|
+
setHasHydratedServerTasks(true);
|
|
3011
3366
|
}).catch(() => {
|
|
3012
3367
|
});
|
|
3013
|
-
|
|
3368
|
+
return unsubscribe;
|
|
3369
|
+
}, [endpoint, routePath]);
|
|
3370
|
+
(0, import_react7.useEffect)(() => {
|
|
3371
|
+
if (!hasHydratedServerTasks) return;
|
|
3372
|
+
const serverAnnotations = serverTasks.map(taskToAnnotation).filter((annotation) => annotation !== null);
|
|
3373
|
+
setAnnotations(serverAnnotations);
|
|
3374
|
+
saveRouteAnnotations(serverAnnotations);
|
|
3375
|
+
}, [serverTasks, hasHydratedServerTasks]);
|
|
3014
3376
|
const isInitialMount = (0, import_react7.useRef)(true);
|
|
3015
3377
|
(0, import_react7.useEffect)(() => {
|
|
3016
3378
|
if (isInitialMount.current) {
|
|
@@ -3216,11 +3578,6 @@ ${elementInfo.join("\n")}`);
|
|
|
3216
3578
|
**\uCD5C\uADFC \uCF58\uC194 \uC5D0\uB7EC**:`);
|
|
3217
3579
|
metadata.consoleErrors.forEach((e) => descriptionParts.push(`- \`${e.slice(0, 200)}\``));
|
|
3218
3580
|
}
|
|
3219
|
-
if (metadata.networkErrors?.length) {
|
|
3220
|
-
descriptionParts.push(`
|
|
3221
|
-
**\uCD5C\uADFC \uB124\uD2B8\uC6CC\uD06C \uC2E4\uD328**:`);
|
|
3222
|
-
metadata.networkErrors.forEach((e) => descriptionParts.push(`- ${e.method} ${e.url} \u2192 ${e.status || "FAILED"}`));
|
|
3223
|
-
}
|
|
3224
3581
|
const result = await submitFeedback(endpoint, {
|
|
3225
3582
|
title: comment.slice(0, 100),
|
|
3226
3583
|
description: descriptionParts.join("\n"),
|
|
@@ -3238,26 +3595,14 @@ ${elementInfo.join("\n")}`);
|
|
|
3238
3595
|
});
|
|
3239
3596
|
setShowToast(true);
|
|
3240
3597
|
originalSetTimeout(() => setShowToast(false), 3e3);
|
|
3241
|
-
const
|
|
3242
|
-
|
|
3243
|
-
// 서버 UUID 사용
|
|
3244
|
-
x: pendingAnnotation.x,
|
|
3245
|
-
y: pendingAnnotation.y,
|
|
3246
|
-
comment,
|
|
3247
|
-
element: pendingAnnotation.element,
|
|
3248
|
-
elementPath: pendingAnnotation.elementPath,
|
|
3249
|
-
timestamp: Date.now(),
|
|
3250
|
-
selectedText: pendingAnnotation.selectedText,
|
|
3251
|
-
boundingBox: pendingAnnotation.boundingBox,
|
|
3252
|
-
isFixed: pendingAnnotation.isFixed
|
|
3253
|
-
};
|
|
3254
|
-
setAnnotations((prev) => [...prev, newAnnotation]);
|
|
3255
|
-
recentlyAddedIdRef.current = newAnnotation.id;
|
|
3598
|
+
const newTaskId = result.taskId || null;
|
|
3599
|
+
recentlyAddedIdRef.current = newTaskId;
|
|
3256
3600
|
originalSetTimeout(() => {
|
|
3257
3601
|
recentlyAddedIdRef.current = null;
|
|
3258
3602
|
}, 300);
|
|
3259
3603
|
originalSetTimeout(() => {
|
|
3260
|
-
|
|
3604
|
+
if (!newTaskId) return;
|
|
3605
|
+
setAnimatedMarkers((prev) => new Set(prev).add(newTaskId));
|
|
3261
3606
|
}, 250);
|
|
3262
3607
|
setPendingExiting(true);
|
|
3263
3608
|
originalSetTimeout(() => {
|
|
@@ -3296,43 +3641,34 @@ ${elementInfo.join("\n")}`);
|
|
|
3296
3641
|
const newId = annotation.id;
|
|
3297
3642
|
setActiveThread((prev) => {
|
|
3298
3643
|
if (prev === newId) return null;
|
|
3299
|
-
fetchComments(endpoint, newId).then((comments) => {
|
|
3300
|
-
setThreadComments((prev2) => ({ ...prev2, [newId]: comments }));
|
|
3301
|
-
}).catch(() => {
|
|
3302
|
-
});
|
|
3303
3644
|
return newId;
|
|
3304
3645
|
});
|
|
3305
|
-
}, [
|
|
3306
|
-
|
|
3646
|
+
}, []);
|
|
3647
|
+
(0, import_react7.useEffect)(() => {
|
|
3648
|
+
if (!activeThread) return;
|
|
3649
|
+
const cacheKey = getCommentsCacheKey(activeThread);
|
|
3650
|
+
const cached = getCachedSnapshot(cacheKey);
|
|
3651
|
+
if (cached) {
|
|
3652
|
+
setThreadComments((prev) => ({ ...prev, [activeThread]: cached }));
|
|
3653
|
+
}
|
|
3654
|
+
const unsubscribe = subscribeCache(cacheKey, (comments) => {
|
|
3655
|
+
setThreadComments((prev) => ({ ...prev, [activeThread]: comments }));
|
|
3656
|
+
});
|
|
3657
|
+
fetchComments(endpoint, activeThread, { staleWhileRevalidate: true }).catch(() => {
|
|
3658
|
+
});
|
|
3659
|
+
return unsubscribe;
|
|
3660
|
+
}, [activeThread, endpoint]);
|
|
3661
|
+
const handleThreadReply = (0, import_react7.useCallback)(async (taskId, content, screenshot, file) => {
|
|
3307
3662
|
const authorName = getUser?.()?.name ? String(getUser().name) : "\uC775\uBA85";
|
|
3308
3663
|
const authorId = getUser?.()?.id ? String(getUser().id) : void 0;
|
|
3309
|
-
const tempComment = {
|
|
3310
|
-
id: `temp-${Date.now()}`,
|
|
3311
|
-
content,
|
|
3312
|
-
authorName,
|
|
3313
|
-
authorId,
|
|
3314
|
-
imageUrl: screenshot ? screenshot : void 0,
|
|
3315
|
-
// 로컬 미리보기
|
|
3316
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3317
|
-
};
|
|
3318
|
-
setThreadComments((prev) => ({
|
|
3319
|
-
...prev,
|
|
3320
|
-
[taskId]: [...prev[taskId] || [], tempComment]
|
|
3321
|
-
}));
|
|
3322
3664
|
try {
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
)
|
|
3329
|
-
}));
|
|
3665
|
+
let fileResult;
|
|
3666
|
+
if (file) {
|
|
3667
|
+
fileResult = await uploadFile(endpoint, file, "comment", taskId);
|
|
3668
|
+
}
|
|
3669
|
+
await postComment(endpoint, taskId, content, authorName, authorId, screenshot, fileResult);
|
|
3330
3670
|
} catch (err) {
|
|
3331
3671
|
console.error("[@impakers/debug] \uCF54\uBA58\uD2B8 \uC804\uC1A1 \uC2E4\uD328:", err);
|
|
3332
|
-
setThreadComments((prev) => ({
|
|
3333
|
-
...prev,
|
|
3334
|
-
[taskId]: (prev[taskId] || []).filter((c) => c.id !== tempComment.id)
|
|
3335
|
-
}));
|
|
3336
3672
|
}
|
|
3337
3673
|
}, [getUser, endpoint]);
|
|
3338
3674
|
const handleThreadClose = (0, import_react7.useCallback)(() => {
|
|
@@ -3400,16 +3736,16 @@ ${elementInfo.join("\n")}`);
|
|
|
3400
3736
|
] })
|
|
3401
3737
|
}
|
|
3402
3738
|
];
|
|
3403
|
-
const currentPath =
|
|
3404
|
-
const allInboxItems =
|
|
3405
|
-
id:
|
|
3406
|
-
title:
|
|
3407
|
-
status:
|
|
3408
|
-
priority:
|
|
3739
|
+
const currentPath = routePath;
|
|
3740
|
+
const allInboxItems = serverTasks.map((task) => ({
|
|
3741
|
+
id: task.id,
|
|
3742
|
+
title: task.title || "\uD53C\uB4DC\uBC31",
|
|
3743
|
+
status: task.status,
|
|
3744
|
+
priority: task.priority,
|
|
3409
3745
|
authorName: getUser?.()?.name ? String(getUser().name) : "\uC775\uBA85",
|
|
3410
|
-
feedbackUrl: currentPath,
|
|
3411
|
-
createdAt:
|
|
3412
|
-
commentCount:
|
|
3746
|
+
feedbackUrl: task.feedbackUrl || currentPath,
|
|
3747
|
+
createdAt: task.createdAt,
|
|
3748
|
+
commentCount: task.commentCount || 0
|
|
3413
3749
|
}));
|
|
3414
3750
|
const allRouteItems = (() => {
|
|
3415
3751
|
const items = [...allInboxItems];
|
|
@@ -3461,9 +3797,6 @@ ${elementInfo.join("\n")}`);
|
|
|
3461
3797
|
onStatusChange: async (taskId, status) => {
|
|
3462
3798
|
try {
|
|
3463
3799
|
await updateTaskStatus(endpoint, taskId, status);
|
|
3464
|
-
const currentPath2 = window.location.pathname;
|
|
3465
|
-
const tasks = await fetchFeedbacks(endpoint, currentPath2);
|
|
3466
|
-
setServerTasks(tasks);
|
|
3467
3800
|
} catch (err) {
|
|
3468
3801
|
console.error("[@impakers/debug] \uC0C1\uD0DC \uBCC0\uACBD \uC2E4\uD328:", err);
|
|
3469
3802
|
}
|
|
@@ -3596,6 +3929,7 @@ ${elementInfo.join("\n")}`);
|
|
|
3596
3929
|
),
|
|
3597
3930
|
activeThread && (() => {
|
|
3598
3931
|
const annotation = annotations.find((a) => a.id === activeThread);
|
|
3932
|
+
const taskData = serverTasks.find((task2) => task2.id === activeThread);
|
|
3599
3933
|
if (!annotation) return null;
|
|
3600
3934
|
const markerX = annotation.x / 100 * window.innerWidth;
|
|
3601
3935
|
const markerY = annotation.isFixed ? annotation.y : annotation.y - window.scrollY;
|
|
@@ -3603,9 +3937,9 @@ ${elementInfo.join("\n")}`);
|
|
|
3603
3937
|
const threadTop = Math.max(10, Math.min(markerY, window.innerHeight - 400));
|
|
3604
3938
|
const task = {
|
|
3605
3939
|
id: annotation.id,
|
|
3606
|
-
title: annotation.comment || "\uD53C\uB4DC\uBC31",
|
|
3607
|
-
status: "todo",
|
|
3608
|
-
createdAt: new Date(annotation.timestamp).toISOString(),
|
|
3940
|
+
title: taskData?.title || annotation.comment || "\uD53C\uB4DC\uBC31",
|
|
3941
|
+
status: taskData?.status || "todo",
|
|
3942
|
+
createdAt: taskData?.createdAt || new Date(annotation.timestamp).toISOString(),
|
|
3609
3943
|
comments: threadComments[annotation.id] || []
|
|
3610
3944
|
};
|
|
3611
3945
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|