issue-sticker 0.4.0 → 0.6.0
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/CHANGELOG.md +40 -0
- package/dist/{createLucideIcon-C0Ldhp96.js → createLucideIcon-BzRMP02h.js} +12 -12
- package/dist/{externalUserPayload-BVNl_35M.js → externalUserPayload-B7zThnol.js} +444 -184
- package/dist/issue-sticker-headless-react.js +2 -2
- package/dist/issue-sticker-headless.js +124 -15
- package/dist/issue-sticker-react.js +1712 -889
- package/dist/{tooltip-CEc_RGfI.js → tooltip-B6UPO-U8.js} +1 -1
- package/headless.d.ts +35 -2
- package/package.json +3 -2
|
@@ -15,14 +15,14 @@ var __privateWrapper = (obj, member, setter, getter) => ({
|
|
|
15
15
|
}
|
|
16
16
|
});
|
|
17
17
|
var _focused, _cleanup, _setup, _b, _provider, _providerCalled, _c, _online, _cleanup2, _setup2, _d, _gcTimeout, _e, _queryType, _initialState, _revertState, _cache, _client, _retryer, _defaultOptions, _abortSignalConsumed, _Query_instances, isInitialPausedFetch_fn, dispatch_fn, _f, _client2, _currentQuery, _currentQueryInitialState, _currentResult, _currentResultState, _currentResultOptions, _currentThenable, _selectError, _selectFn, _selectResult, _lastQueryWithDefinedData, _staleTimeoutId, _refetchIntervalId, _currentRefetchInterval, _trackedProps, _QueryObserver_instances, executeFetch_fn, updateStaleTimeout_fn, computeRefetchInterval_fn, updateRefetchInterval_fn, updateTimers_fn, clearStaleTimeout_fn, clearRefetchInterval_fn, updateQuery_fn, notify_fn, _g, _client3, _observers, _mutationCache, _retryer2, _Mutation_instances, dispatch_fn2, _h, _mutations, _scopes, _mutationId, _i, _client4, _currentResult2, _currentMutation, _mutateOptions, _MutationObserver_instances, updateResult_fn, notify_fn2, _j, _queries, _k, _queryCache, _mutationCache2, _defaultOptions2, _queryDefaults, _mutationDefaults, _mountCount, _unsubscribeFocus, _unsubscribeOnline, _l, _m;
|
|
18
|
-
import { A as trimLogBackupPayload, B as createSafeLogBackup, D as getLogBackupSessionId, N as NetworkCollector, C as ConsoleCollector, E as createIndexedDbLogBackup, e as buildJiraCreateFields, P as Popover, F as PopoverTrigger,
|
|
18
|
+
import { A as trimLogBackupPayload, B as createSafeLogBackup, D as getLogBackupSessionId, N as NetworkCollector, C as ConsoleCollector, E as createIndexedDbLogBackup, e as buildJiraCreateFields, P as Popover, F as PopoverTrigger, G as Input, H as PopoverContent, L as Label, J as Select, K as SelectTrigger, M as SelectValue, O as SelectContent, Q as SelectItem, R as getJiraMetadata, T as buildJiraIssueFields, U as Button, V as Root2$2, W as Trigger$2, X as ChevronDown, Y as Portal, Z as Content2$1, _ as Check, $ as X$1, a0 as DatePicker, f as buildNotionCreateFields, a1 as getNotionPageMetadata, a2 as buildNotionFieldViews, c as captureWithModernScreenshot, p as pristineFetch, d as directUploadToSignedUrl, a3 as DirectUploadError, a4 as toast, a5 as getSnapshot, a6 as subscribe, a as uploadSignedMediaWithApi, v as sanitizeString, a7 as getRegisteredUploadId, h as buildGuestOwnerQuery, j as devLogger, w as getCurrentPageUrl, a8 as ChevronRight, a9 as ReactRemoveScroll, aa as hideOthers, ab as useFocusGuards, ac as FocusScope, ad as getExposedJiraFields, ae as isJiraFieldExposed, n as normalizeExposedJiraFields, y as preloadModernScreenshot, u as uploadScreenshotDataUrls, k as filterExcludeServiceRelatedLogs, l as filterExcludeServiceRelatedConsoleLogs, s as selectNetworkLogsForSubmit, m as compactNetworkLogsForTransport, o as CONSOLE_LOG_SUBMIT_LIMIT, g as getElementPosition, q as buildExternalUserPayload, r as shrinkNetworkLogsToFit, t as measureJsonBytes, i as buildIssueIntegrationsPayload, x as SessionReplayCaptureController, af as getPrimaryJiraMapping, ag as createCollection, ah as useDirection, ai as getPrimaryNotionMapping, aj as buttonVariants, ak as findElementBySelector, al as findElementByXPath, S as ScreenRecordingController, am as OnboardingProvider, an as useOnboardingTarget, ao as useOnboardingFlow, ap as ISSUE_STICKER_HOST_ELEMENT_ID, aq as getIssueStickerRuntimeOwner, ar as ISSUE_STICKER_RUNTIME_OWNER, z as isIssueStickerExtensionRuntimeActive, as as createRuntimeHostElement, at as attachHostTypingGuard, au as ISSUE_STICKER_EXTENSION_RUNTIME_READY_EVENT } from "./externalUserPayload-B7zThnol.js";
|
|
19
19
|
import * as React from "react";
|
|
20
20
|
import { useRef, useState, useEffect, useId, useLayoutEffect, useCallback, forwardRef, createElement, createContext, useContext, Component, Suspense, useInsertionEffect, useMemo, Children, isValidElement, Fragment as Fragment$1, useSyncExternalStore } from "react";
|
|
21
21
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
22
|
-
import { c as createLucideIcon$1, b as usePortalContainer, a as cn$1, O as OVERLAY_LAYER, s as stopEscapePropagation, d as OVERLAY_LAYER_INDEX,
|
|
22
|
+
import { c as createLucideIcon$1, b as usePortalContainer, a as cn$1, O as OVERLAY_LAYER, s as stopEscapePropagation, d as OVERLAY_LAYER_INDEX, P as Presence, e as Primitive, f as composeEventHandlers, g as useDismissableLayerSurface, h as useComposedRefs$1, i as Portal$1, j as createContextScope, k as createSlot, D as DismissableLayer, l as useControllableState, m as useId$1, n as useLayoutEffect2, o as useCallbackRef, p as PortalContainerProvider } from "./createLucideIcon-BzRMP02h.js";
|
|
23
23
|
import { createRoot } from "react-dom/client";
|
|
24
24
|
import { createPortal } from "react-dom";
|
|
25
|
-
import { T as TooltipProvider, a as Tooltip, b as TooltipTrigger, c as TooltipContent } from "./tooltip-
|
|
25
|
+
import { T as TooltipProvider, a as Tooltip, b as TooltipTrigger, c as TooltipContent } from "./tooltip-B6UPO-U8.js";
|
|
26
26
|
function readReleaseMarker() {
|
|
27
27
|
try {
|
|
28
28
|
const g = globalThis.__ISSUE_STICKER_RELEASE__;
|
|
@@ -167,9 +167,10 @@ function createCollectorSession(options = {}) {
|
|
|
167
167
|
console: consoleCollector,
|
|
168
168
|
backup,
|
|
169
169
|
async start() {
|
|
170
|
+
var _a, _b2;
|
|
170
171
|
network.start();
|
|
171
172
|
consoleCollector.start();
|
|
172
|
-
const navigationEntry = performanceApi == null ? void 0 : performanceApi.getEntriesByType("navigation")[0];
|
|
173
|
+
const navigationEntry = (_b2 = (_a = performanceApi == null ? void 0 : performanceApi.getEntriesByType) == null ? void 0 : _a.call(performanceApi, "navigation")) == null ? void 0 : _b2[0];
|
|
173
174
|
const navigationLog = createNavigationLog(navigationEntry, (performanceApi == null ? void 0 : performanceApi.timeOrigin) ?? 0);
|
|
174
175
|
if (navigationLog) network.ingest(navigationLog);
|
|
175
176
|
stopResourceObserver = observeResourceLogs(
|
|
@@ -491,6 +492,16 @@ function AsyncSearchSelect({
|
|
|
491
492
|
}
|
|
492
493
|
);
|
|
493
494
|
}
|
|
495
|
+
/**
|
|
496
|
+
* @license lucide-react v0.468.0 - ISC
|
|
497
|
+
*
|
|
498
|
+
* This source code is licensed under the ISC license.
|
|
499
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
500
|
+
*/
|
|
501
|
+
const ArrowUp = createLucideIcon$1("ArrowUp", [
|
|
502
|
+
["path", { d: "m5 12 7-7 7 7", key: "hav0vg" }],
|
|
503
|
+
["path", { d: "M12 19V5", key: "x0mq9r" }]
|
|
504
|
+
]);
|
|
494
505
|
/**
|
|
495
506
|
* @license lucide-react v0.468.0 - ISC
|
|
496
507
|
*
|
|
@@ -684,6 +695,22 @@ const MapPin = createLucideIcon$1("MapPin", [
|
|
|
684
695
|
],
|
|
685
696
|
["circle", { cx: "12", cy: "10", r: "3", key: "ilqhr7" }]
|
|
686
697
|
]);
|
|
698
|
+
/**
|
|
699
|
+
* @license lucide-react v0.468.0 - ISC
|
|
700
|
+
*
|
|
701
|
+
* This source code is licensed under the ISC license.
|
|
702
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
703
|
+
*/
|
|
704
|
+
const PenLine = createLucideIcon$1("PenLine", [
|
|
705
|
+
["path", { d: "M12 20h9", key: "t2du7b" }],
|
|
706
|
+
[
|
|
707
|
+
"path",
|
|
708
|
+
{
|
|
709
|
+
d: "M16.376 3.622a1 1 0 0 1 3.002 3.002L7.368 18.635a2 2 0 0 1-.855.506l-2.872.838a.5.5 0 0 1-.62-.62l.838-2.872a2 2 0 0 1 .506-.854z",
|
|
710
|
+
key: "1ykcvy"
|
|
711
|
+
}
|
|
712
|
+
]
|
|
713
|
+
]);
|
|
687
714
|
/**
|
|
688
715
|
* @license lucide-react v0.468.0 - ISC
|
|
689
716
|
*
|
|
@@ -696,6 +723,25 @@ const RefreshCw = createLucideIcon$1("RefreshCw", [
|
|
|
696
723
|
["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
|
|
697
724
|
["path", { d: "M8 16H3v5", key: "1cv678" }]
|
|
698
725
|
]);
|
|
726
|
+
/**
|
|
727
|
+
* @license lucide-react v0.468.0 - ISC
|
|
728
|
+
*
|
|
729
|
+
* This source code is licensed under the ISC license.
|
|
730
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
731
|
+
*/
|
|
732
|
+
const Sparkles = createLucideIcon$1("Sparkles", [
|
|
733
|
+
[
|
|
734
|
+
"path",
|
|
735
|
+
{
|
|
736
|
+
d: "M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z",
|
|
737
|
+
key: "4pj2yx"
|
|
738
|
+
}
|
|
739
|
+
],
|
|
740
|
+
["path", { d: "M20 3v4", key: "1olli1" }],
|
|
741
|
+
["path", { d: "M22 5h-4", key: "1gvqau" }],
|
|
742
|
+
["path", { d: "M4 17v2", key: "vumght" }],
|
|
743
|
+
["path", { d: "M5 18H3", key: "zchphs" }]
|
|
744
|
+
]);
|
|
699
745
|
/**
|
|
700
746
|
* @license lucide-react v0.468.0 - ISC
|
|
701
747
|
*
|
|
@@ -1816,9 +1862,9 @@ var FocusManager = (_b = class extends Subscribable {
|
|
|
1816
1862
|
}
|
|
1817
1863
|
}
|
|
1818
1864
|
onFocus() {
|
|
1819
|
-
const
|
|
1865
|
+
const isFocused2 = this.isFocused();
|
|
1820
1866
|
this.listeners.forEach((listener) => {
|
|
1821
|
-
listener(
|
|
1867
|
+
listener(isFocused2);
|
|
1822
1868
|
});
|
|
1823
1869
|
}
|
|
1824
1870
|
isFocused() {
|
|
@@ -4537,9 +4583,10 @@ function useMutation(options, queryClient2) {
|
|
|
4537
4583
|
return { ...result, mutate, mutateAsync: result.mutate };
|
|
4538
4584
|
}
|
|
4539
4585
|
const BODY_SCROLLBAR_WIDTH_CSS_VAR = "--issue-sticker-scrollbar-width";
|
|
4540
|
-
const useIsomorphicLayoutEffect$
|
|
4541
|
-
function useDisableBodyScroll() {
|
|
4542
|
-
useIsomorphicLayoutEffect$
|
|
4586
|
+
const useIsomorphicLayoutEffect$2 = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
4587
|
+
function useDisableBodyScroll(enabled = true) {
|
|
4588
|
+
useIsomorphicLayoutEffect$2(() => {
|
|
4589
|
+
if (!enabled) return;
|
|
4543
4590
|
const body = document.body;
|
|
4544
4591
|
const root2 = document.documentElement;
|
|
4545
4592
|
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
@@ -4560,7 +4607,7 @@ function useDisableBodyScroll() {
|
|
|
4560
4607
|
root2.style.removeProperty(BODY_SCROLLBAR_WIDTH_CSS_VAR);
|
|
4561
4608
|
}
|
|
4562
4609
|
};
|
|
4563
|
-
}, []);
|
|
4610
|
+
}, [enabled]);
|
|
4564
4611
|
}
|
|
4565
4612
|
function useGuardedCallback(callback) {
|
|
4566
4613
|
const guardRef = useRef(false);
|
|
@@ -5904,355 +5951,22 @@ function DefaultErrorFallback({ resetErrorBoundary }) {
|
|
|
5904
5951
|
/* @__PURE__ */ jsx(Button, { variant: "outline", className: "mt-3", onClick: resetErrorBoundary, children: "다시 시도" })
|
|
5905
5952
|
] });
|
|
5906
5953
|
}
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
{
|
|
5914
|
-
post: (endpoint, body) => apiClient.post(endpoint, body),
|
|
5915
|
-
directUpload
|
|
5916
|
-
},
|
|
5917
|
-
file,
|
|
5918
|
-
mediaType,
|
|
5919
|
-
{ issueId }
|
|
5920
|
-
);
|
|
5921
|
-
}
|
|
5922
|
-
function issuesEndpoint() {
|
|
5923
|
-
return "/api/sdk/issues";
|
|
5924
|
-
}
|
|
5925
|
-
function guestOwnerQuery() {
|
|
5926
|
-
var _a;
|
|
5927
|
-
const mode = getSdkMode();
|
|
5928
|
-
if (mode !== "public") return "";
|
|
5929
|
-
return buildGuestOwnerQuery(mode, (_a = SDKManager.getInstance().config.user) == null ? void 0 : _a.id);
|
|
5930
|
-
}
|
|
5931
|
-
let issuesCache = null;
|
|
5932
|
-
const CACHE_DURATION_MS = 30 * 1e3;
|
|
5933
|
-
const STICKER_PAGE_SIZE = 500;
|
|
5934
|
-
const STICKER_FETCH_LIMIT = 2e3;
|
|
5935
|
-
function getFilterKey(filters) {
|
|
5936
|
-
var _a;
|
|
5937
|
-
const normalizeArray = (value) => {
|
|
5938
|
-
if (value === "all" || !value) return "all";
|
|
5939
|
-
if (Array.isArray(value)) {
|
|
5940
|
-
return value.length === 0 ? "all" : [...value].sort().join(",");
|
|
5941
|
-
}
|
|
5942
|
-
return String(value);
|
|
5943
|
-
};
|
|
5944
|
-
const normalizeRecord = (record) => {
|
|
5945
|
-
if (!record) return "";
|
|
5946
|
-
const entries = Object.entries(record).map(([k, v]) => [k, [...v].sort()]).sort(([a], [b]) => a.localeCompare(b));
|
|
5947
|
-
return JSON.stringify(entries);
|
|
5948
|
-
};
|
|
5949
|
-
return JSON.stringify({
|
|
5950
|
-
sdkMode: getSdkMode() || "public",
|
|
5951
|
-
url: normalizeArray(filters.url),
|
|
5952
|
-
projectId: filters.projectId || "all",
|
|
5953
|
-
externalUserId: filters.externalUserId || "",
|
|
5954
|
-
search: ((_a = filters.search) == null ? void 0 : _a.trim()) || "",
|
|
5955
|
-
dateFrom: filters.dateFrom || "",
|
|
5956
|
-
dateTo: filters.dateTo || "",
|
|
5957
|
-
page: filters.page ?? 0,
|
|
5958
|
-
pageSize: filters.pageSize ?? 0,
|
|
5959
|
-
custom: normalizeRecord(filters.customFieldValues),
|
|
5960
|
-
jira: normalizeRecord(filters.jiraFieldValues),
|
|
5961
|
-
notion: normalizeRecord(filters.notionFieldValues),
|
|
5962
|
-
sortOrder: filters.sortOrder || ""
|
|
5963
|
-
});
|
|
5964
|
-
}
|
|
5965
|
-
function invalidateIssuesCache() {
|
|
5966
|
-
issuesCache = null;
|
|
5967
|
-
}
|
|
5968
|
-
function recordToFilterArray(record, keyFieldName) {
|
|
5969
|
-
if (!record) return null;
|
|
5970
|
-
const entries = Object.entries(record).filter(([, values]) => values.length > 0);
|
|
5971
|
-
if (entries.length === 0) return null;
|
|
5972
|
-
return entries.map(
|
|
5973
|
-
([key, values]) => ({ [keyFieldName]: key, values })
|
|
5974
|
-
);
|
|
5975
|
-
}
|
|
5976
|
-
function buildFilterQueryParams(filters, options = {}) {
|
|
5977
|
-
var _a;
|
|
5978
|
-
const params = new URLSearchParams();
|
|
5979
|
-
if (filters.projectId) {
|
|
5980
|
-
params.set("project_id", filters.projectId);
|
|
5981
|
-
}
|
|
5982
|
-
if (filters.url && filters.url !== "all") {
|
|
5983
|
-
if (Array.isArray(filters.url) && filters.url.length > 0) {
|
|
5984
|
-
params.set("url", filters.url.join(","));
|
|
5985
|
-
} else if (typeof filters.url === "string") {
|
|
5986
|
-
params.set("url", filters.url);
|
|
5987
|
-
}
|
|
5988
|
-
}
|
|
5989
|
-
if (options.includeListFilters) {
|
|
5990
|
-
const search2 = (_a = filters.search) == null ? void 0 : _a.trim();
|
|
5991
|
-
if (search2) {
|
|
5992
|
-
params.set("search", search2);
|
|
5993
|
-
}
|
|
5994
|
-
if (filters.dateFrom) {
|
|
5995
|
-
params.set("date_from", filters.dateFrom);
|
|
5996
|
-
}
|
|
5997
|
-
if (filters.dateTo) {
|
|
5998
|
-
params.set("date_to", filters.dateTo);
|
|
5999
|
-
}
|
|
6000
|
-
const customArr = recordToFilterArray(filters.customFieldValues, "fieldDefinitionId");
|
|
6001
|
-
if (customArr) {
|
|
6002
|
-
params.set("custom_field_filters", JSON.stringify(customArr));
|
|
6003
|
-
}
|
|
6004
|
-
const jiraArr = recordToFilterArray(filters.jiraFieldValues, "fieldName");
|
|
6005
|
-
if (jiraArr) {
|
|
6006
|
-
params.set("jira_field_filters", JSON.stringify(jiraArr));
|
|
6007
|
-
}
|
|
6008
|
-
const notionArr = recordToFilterArray(filters.notionFieldValues, "fieldName");
|
|
6009
|
-
if (notionArr) {
|
|
6010
|
-
params.set("notion_field_filters", JSON.stringify(notionArr));
|
|
6011
|
-
}
|
|
6012
|
-
}
|
|
6013
|
-
if (filters.externalUserId) {
|
|
6014
|
-
params.set("external_user_id", filters.externalUserId);
|
|
6015
|
-
}
|
|
6016
|
-
if (typeof filters.page === "number" && filters.page > 0) {
|
|
6017
|
-
params.set("page", String(filters.page));
|
|
6018
|
-
}
|
|
6019
|
-
if (typeof filters.pageSize === "number" && filters.pageSize > 0) {
|
|
6020
|
-
params.set("page_size", String(filters.pageSize));
|
|
6021
|
-
}
|
|
6022
|
-
if (filters.sortOrder) {
|
|
6023
|
-
params.set("sort_order", filters.sortOrder);
|
|
6024
|
-
}
|
|
6025
|
-
const queryString = params.toString();
|
|
6026
|
-
return queryString ? `?${queryString}` : "";
|
|
6027
|
-
}
|
|
6028
|
-
const issueService = {
|
|
6029
|
-
async createIssue(issueData) {
|
|
6030
|
-
const sanitizedData = sanitizeString(issueData);
|
|
6031
|
-
const screenshotUploadIds = (sanitizedData.screenshot || []).map((url) => getRegisteredUploadId(url, "screenshot")).filter((id2) => typeof id2 === "string" && id2.length > 0);
|
|
6032
|
-
const videoUploadId = sanitizedData.video ? getRegisteredUploadId(sanitizedData.video, "video") : void 0;
|
|
6033
|
-
if (screenshotUploadIds.length > 0) {
|
|
6034
|
-
sanitizedData.screenshot_upload_ids = screenshotUploadIds;
|
|
6035
|
-
}
|
|
6036
|
-
if (videoUploadId) {
|
|
6037
|
-
sanitizedData.video_upload_id = videoUploadId;
|
|
6038
|
-
}
|
|
6039
|
-
const issue = await apiClient.post(issuesEndpoint(), sanitizedData);
|
|
6040
|
-
invalidateIssuesCache();
|
|
6041
|
-
return issue;
|
|
6042
|
-
},
|
|
6043
|
-
async getIssues(filters = {}, options = {}) {
|
|
6044
|
-
if (!filters.projectId) {
|
|
6045
|
-
throw new Error("프로젝트 ID가 필요합니다. 로그인 상태를 확인해주세요.");
|
|
6046
|
-
}
|
|
6047
|
-
const filterKey = getFilterKey(filters);
|
|
6048
|
-
const now2 = Date.now();
|
|
6049
|
-
if (!options.forceRefresh && issuesCache && issuesCache.filterKey === filterKey && now2 - issuesCache.timestamp < CACHE_DURATION_MS) {
|
|
6050
|
-
return issuesCache.data;
|
|
6051
|
-
}
|
|
6052
|
-
const queryParams = buildFilterQueryParams(filters, { includeListFilters: true });
|
|
6053
|
-
const { items: issues = [] } = await apiClient.get(
|
|
6054
|
-
`${issuesEndpoint()}${queryParams}`
|
|
6055
|
-
);
|
|
6056
|
-
issuesCache = {
|
|
6057
|
-
data: issues,
|
|
6058
|
-
timestamp: now2,
|
|
6059
|
-
filterKey
|
|
6060
|
-
};
|
|
6061
|
-
return issues;
|
|
6062
|
-
},
|
|
6063
|
-
async getIssueStickers(filters = {}, options = {}) {
|
|
6064
|
-
var _a, _b2;
|
|
6065
|
-
if (!filters.projectId) {
|
|
6066
|
-
throw new Error("프로젝트 ID가 필요합니다. 로그인 상태를 확인해주세요.");
|
|
6067
|
-
}
|
|
6068
|
-
const filterKey = `${getFilterKey(filters)}:stickers`;
|
|
6069
|
-
const now2 = Date.now();
|
|
6070
|
-
if (!options.forceRefresh && issuesCache && issuesCache.filterKey === filterKey && now2 - issuesCache.timestamp < CACHE_DURATION_MS) {
|
|
6071
|
-
return issuesCache.data;
|
|
6072
|
-
}
|
|
6073
|
-
const issues = [];
|
|
6074
|
-
let page = 1;
|
|
6075
|
-
let hasMore = true;
|
|
6076
|
-
while (hasMore && issues.length <= STICKER_FETCH_LIMIT) {
|
|
6077
|
-
const response = await apiClient.getResponse(
|
|
6078
|
-
`${issuesEndpoint()}/stickers${buildFilterQueryParams({
|
|
6079
|
-
...filters,
|
|
6080
|
-
page,
|
|
6081
|
-
pageSize: STICKER_PAGE_SIZE
|
|
6082
|
-
})}`
|
|
6083
|
-
);
|
|
6084
|
-
const pageItems = ((_a = response.data) == null ? void 0 : _a.items) ?? [];
|
|
6085
|
-
issues.push(...pageItems);
|
|
6086
|
-
hasMore = Boolean((_b2 = response.data) == null ? void 0 : _b2.hasMore) && pageItems.length > 0;
|
|
6087
|
-
page += 1;
|
|
6088
|
-
}
|
|
6089
|
-
issuesCache = {
|
|
6090
|
-
data: issues,
|
|
6091
|
-
timestamp: now2,
|
|
6092
|
-
filterKey
|
|
6093
|
-
};
|
|
6094
|
-
return issues;
|
|
6095
|
-
},
|
|
6096
|
-
invalidateCache() {
|
|
6097
|
-
invalidateIssuesCache();
|
|
6098
|
-
},
|
|
6099
|
-
// 계약 정본: 백엔드 GET /api/sdk/issues/:id 는 back#101부터 읽기-시점-스크럽된
|
|
6100
|
-
// llm_prompt 를 상세 응답에 포함한다(목록 응답에는 없음) — 스코프를 이 반환 타입에만 한정한다.
|
|
6101
|
-
async getIssue(id2) {
|
|
6102
|
-
return apiClient.get(
|
|
6103
|
-
`${issuesEndpoint()}/${id2}${guestOwnerQuery()}`
|
|
6104
|
-
);
|
|
6105
|
-
},
|
|
6106
|
-
async updateIssue(id2, updates) {
|
|
6107
|
-
const sanitizedUpdates = sanitizeString(updates);
|
|
6108
|
-
const issue = await apiClient.put(
|
|
6109
|
-
`${issuesEndpoint()}/${id2}${guestOwnerQuery()}`,
|
|
6110
|
-
sanitizedUpdates
|
|
6111
|
-
);
|
|
6112
|
-
invalidateIssuesCache();
|
|
6113
|
-
return issue;
|
|
6114
|
-
},
|
|
6115
|
-
async deleteIssue(id2, options) {
|
|
6116
|
-
const endpoint = `${issuesEndpoint()}/${id2}${guestOwnerQuery()}`;
|
|
6117
|
-
if (options == null ? void 0 : options.deleteExternal) {
|
|
6118
|
-
await apiClient.delete(endpoint, {
|
|
6119
|
-
body: { deleteExternal: true }
|
|
6120
|
-
});
|
|
6121
|
-
} else {
|
|
6122
|
-
await apiClient.delete(endpoint);
|
|
6123
|
-
}
|
|
6124
|
-
invalidateIssuesCache();
|
|
6125
|
-
}
|
|
6126
|
-
};
|
|
6127
|
-
async function loadIssuesFromServer(url, projectId, externalUserId, options = {}) {
|
|
6128
|
-
if (!projectId) return [];
|
|
6129
|
-
try {
|
|
6130
|
-
return await issueService.getIssueStickers(
|
|
6131
|
-
{
|
|
6132
|
-
url,
|
|
6133
|
-
projectId,
|
|
6134
|
-
...externalUserId ? { externalUserId } : {}
|
|
6135
|
-
},
|
|
6136
|
-
options
|
|
6137
|
-
) || [];
|
|
6138
|
-
} catch (error) {
|
|
6139
|
-
devLogger.error("useIssues", "Failed to load issues:", error);
|
|
6140
|
-
return [];
|
|
6141
|
-
}
|
|
6142
|
-
}
|
|
6143
|
-
const contentProjectIdQueryKey = ["contentProjectId"];
|
|
6144
|
-
const contentIssuesQueryRoot = ["contentIssues"];
|
|
6145
|
-
function contentIssuesQueryKey({
|
|
6146
|
-
currentUrl,
|
|
6147
|
-
projectId,
|
|
6148
|
-
isMember,
|
|
6149
|
-
externalUserId
|
|
6150
|
-
}) {
|
|
6151
|
-
return [...contentIssuesQueryRoot, currentUrl, projectId, isMember, externalUserId];
|
|
6152
|
-
}
|
|
6153
|
-
function fetchContentIssues({
|
|
6154
|
-
currentUrl,
|
|
6155
|
-
projectId,
|
|
6156
|
-
isMember,
|
|
6157
|
-
externalUserId,
|
|
6158
|
-
forceRefresh
|
|
6159
|
-
}) {
|
|
6160
|
-
return loadIssuesFromServer(currentUrl, projectId, isMember ? void 0 : externalUserId, {
|
|
6161
|
-
forceRefresh
|
|
6162
|
-
});
|
|
6163
|
-
}
|
|
6164
|
-
function useIssues(currentUrl) {
|
|
6165
|
-
var _a;
|
|
6166
|
-
const { isMember } = useAuthContext();
|
|
6167
|
-
const config = SDKManager.getInstance().config;
|
|
6168
|
-
const sessionIssuesRef = useRef([]);
|
|
6169
|
-
const projectIdQuery = useSuspenseQuery({
|
|
6170
|
-
queryKey: contentProjectIdQueryKey,
|
|
6171
|
-
queryFn: async () => {
|
|
6172
|
-
const accountInfo = await getAccountInfo();
|
|
6173
|
-
return (accountInfo == null ? void 0 : accountInfo.projectId) ?? null;
|
|
6174
|
-
}
|
|
6175
|
-
});
|
|
6176
|
-
const projectId = projectIdQuery.data;
|
|
6177
|
-
const { data: serverIssues = [] } = useSuspenseQuery({
|
|
6178
|
-
queryKey: contentIssuesQueryKey({
|
|
6179
|
-
currentUrl,
|
|
6180
|
-
projectId,
|
|
6181
|
-
isMember,
|
|
6182
|
-
externalUserId: (_a = config.user) == null ? void 0 : _a.id
|
|
6183
|
-
}),
|
|
6184
|
-
queryFn: () => {
|
|
6185
|
-
var _a2;
|
|
6186
|
-
return fetchContentIssues({
|
|
6187
|
-
currentUrl,
|
|
6188
|
-
projectId,
|
|
6189
|
-
isMember,
|
|
6190
|
-
externalUserId: (_a2 = config.user) == null ? void 0 : _a2.id
|
|
6191
|
-
});
|
|
6192
|
-
}
|
|
5954
|
+
let reloadToastId = null;
|
|
5955
|
+
function showReloadToast() {
|
|
5956
|
+
if (reloadToastId && getSnapshot().some((t) => t.id === reloadToastId)) return;
|
|
5957
|
+
reloadToastId = toast.error("이슈 정보를 불러오지 못했습니다. 페이지를 새로고침해주세요.", {
|
|
5958
|
+
// 사용자가 새로고침하거나 닫을 때까지 남긴다.
|
|
5959
|
+
duration: 0,
|
|
5960
|
+
action: { label: "새로고침", onClick: () => window.location.reload() }
|
|
6193
5961
|
});
|
|
6194
|
-
const issues = !isMember && !config.user ? [...serverIssues, ...sessionIssuesRef.current] : serverIssues;
|
|
6195
|
-
const addSessionIssue = useCallback((issue) => {
|
|
6196
|
-
sessionIssuesRef.current = [...sessionIssuesRef.current, issue];
|
|
6197
|
-
}, []);
|
|
6198
|
-
const loadIssues = useCallback(async () => {
|
|
6199
|
-
issueService.invalidateCache();
|
|
6200
|
-
await Promise.all([
|
|
6201
|
-
queryClient.invalidateQueries({ queryKey: contentIssuesQueryRoot }),
|
|
6202
|
-
queryClient.invalidateQueries({ queryKey: contentProjectIdQueryKey })
|
|
6203
|
-
]);
|
|
6204
|
-
}, []);
|
|
6205
|
-
return {
|
|
6206
|
-
issues,
|
|
6207
|
-
loadIssues,
|
|
6208
|
-
addSessionIssue
|
|
6209
|
-
};
|
|
6210
5962
|
}
|
|
6211
|
-
function
|
|
6212
|
-
|
|
5963
|
+
function OverlayErrorFallback() {
|
|
5964
|
+
useEffect(showReloadToast, []);
|
|
5965
|
+
return null;
|
|
6213
5966
|
}
|
|
6214
|
-
function
|
|
6215
|
-
const
|
|
6216
|
-
|
|
6217
|
-
useEffect(() => {
|
|
6218
|
-
var _a;
|
|
6219
|
-
if (isLoading || !isAuthenticated || !projectId) {
|
|
6220
|
-
return;
|
|
6221
|
-
}
|
|
6222
|
-
const currentUrl = readCurrentUrl();
|
|
6223
|
-
const externalUserId = (_a = SDKManager.getInstance().config.user) == null ? void 0 : _a.id;
|
|
6224
|
-
const fetchKey = [
|
|
6225
|
-
currentUrl,
|
|
6226
|
-
projectId,
|
|
6227
|
-
isMember ? "member" : "public",
|
|
6228
|
-
accountId ?? "",
|
|
6229
|
-
token ?? "",
|
|
6230
|
-
externalUserId ?? ""
|
|
6231
|
-
].join("|");
|
|
6232
|
-
if (lastFetchKeyRef.current === fetchKey) {
|
|
6233
|
-
return;
|
|
6234
|
-
}
|
|
6235
|
-
lastFetchKeyRef.current = fetchKey;
|
|
6236
|
-
queryClient.setQueryData(contentProjectIdQueryKey, projectId);
|
|
6237
|
-
void queryClient.fetchQuery({
|
|
6238
|
-
queryKey: contentIssuesQueryKey({
|
|
6239
|
-
currentUrl,
|
|
6240
|
-
projectId,
|
|
6241
|
-
isMember,
|
|
6242
|
-
externalUserId
|
|
6243
|
-
}),
|
|
6244
|
-
queryFn: () => fetchContentIssues({
|
|
6245
|
-
currentUrl,
|
|
6246
|
-
projectId,
|
|
6247
|
-
isMember,
|
|
6248
|
-
externalUserId,
|
|
6249
|
-
forceRefresh: true
|
|
6250
|
-
}),
|
|
6251
|
-
staleTime: 0
|
|
6252
|
-
}).catch((error) => {
|
|
6253
|
-
devLogger.error("usePrefetchContentIssues", "Failed to prefetch issues:", error);
|
|
6254
|
-
});
|
|
6255
|
-
}, [accountId, isAuthenticated, isLoading, isMember, projectId, token]);
|
|
5967
|
+
function QueryBoundary({ children, onError, loadingFallback }) {
|
|
5968
|
+
const ErrorFallback = onError ?? DefaultErrorFallback;
|
|
5969
|
+
return /* @__PURE__ */ jsx(QueryErrorResetBoundary, { children: ({ reset }) => /* @__PURE__ */ jsx(m, { FallbackComponent: ErrorFallback, onReset: reset, children: /* @__PURE__ */ jsx(Suspense, { fallback: loadingFallback ?? /* @__PURE__ */ jsx(Skeleton, {}), children }) }) });
|
|
6256
5970
|
}
|
|
6257
5971
|
const LayoutGroupContext = createContext({});
|
|
6258
5972
|
function useConstant(init) {
|
|
@@ -6263,7 +5977,7 @@ function useConstant(init) {
|
|
|
6263
5977
|
return ref.current;
|
|
6264
5978
|
}
|
|
6265
5979
|
const isBrowser$1 = typeof window !== "undefined";
|
|
6266
|
-
const useIsomorphicLayoutEffect = isBrowser$1 ? useLayoutEffect : useEffect;
|
|
5980
|
+
const useIsomorphicLayoutEffect$1 = isBrowser$1 ? useLayoutEffect : useEffect;
|
|
6267
5981
|
const PresenceContext = /* @__PURE__ */ createContext(null);
|
|
6268
5982
|
function addUniqueItem(arr, item) {
|
|
6269
5983
|
if (arr.indexOf(item) === -1)
|
|
@@ -12530,7 +12244,7 @@ const PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, p
|
|
|
12530
12244
|
const id2 = useId();
|
|
12531
12245
|
const isPresentRef = useRef(isPresent);
|
|
12532
12246
|
const onExitCompleteRef = useRef(onExitComplete);
|
|
12533
|
-
useIsomorphicLayoutEffect(() => {
|
|
12247
|
+
useIsomorphicLayoutEffect$1(() => {
|
|
12534
12248
|
isPresentRef.current = isPresent;
|
|
12535
12249
|
onExitCompleteRef.current = onExitComplete;
|
|
12536
12250
|
});
|
|
@@ -12608,7 +12322,7 @@ const AnimatePresence = ({ children, custom, initial = true, onExitComplete, pre
|
|
|
12608
12322
|
const exitingComponents = useRef(/* @__PURE__ */ new Set());
|
|
12609
12323
|
const [diffedChildren, setDiffedChildren] = useState(presentChildren);
|
|
12610
12324
|
const [renderedChildren, setRenderedChildren] = useState(presentChildren);
|
|
12611
|
-
useIsomorphicLayoutEffect(() => {
|
|
12325
|
+
useIsomorphicLayoutEffect$1(() => {
|
|
12612
12326
|
isInitialRender.current = false;
|
|
12613
12327
|
pendingPresentChildren.current = presentChildren;
|
|
12614
12328
|
for (let i = 0; i < renderedChildren.length; i++) {
|
|
@@ -13061,7 +12775,7 @@ function useVisualElement(Component2, visualState, props, createVisualElement, P
|
|
|
13061
12775
|
});
|
|
13062
12776
|
const optimisedAppearId = props[optimizedAppearDataAttribute];
|
|
13063
12777
|
const wantsHandoff = useRef(Boolean(optimisedAppearId) && typeof window !== "undefined" && !((_a = window.MotionHandoffIsComplete) == null ? void 0 : _a.call(window, optimisedAppearId)) && ((_b2 = window.MotionHasOptimisedAnimation) == null ? void 0 : _b2.call(window, optimisedAppearId)));
|
|
13064
|
-
useIsomorphicLayoutEffect(() => {
|
|
12778
|
+
useIsomorphicLayoutEffect$1(() => {
|
|
13065
12779
|
hasMountedOnce.current = true;
|
|
13066
12780
|
if (!visualElement)
|
|
13067
12781
|
return;
|
|
@@ -14391,6 +14105,11 @@ const featureBundle = {
|
|
|
14391
14105
|
...layout
|
|
14392
14106
|
};
|
|
14393
14107
|
const motion$1 = /* @__PURE__ */ createMotionProxy(featureBundle, createDomVisualElement);
|
|
14108
|
+
function useReducedMotion() {
|
|
14109
|
+
!hasReducedMotionListener.current && initPrefersReducedMotion();
|
|
14110
|
+
const [shouldReduceMotion] = useState(prefersReducedMotion.current);
|
|
14111
|
+
return shouldReduceMotion;
|
|
14112
|
+
}
|
|
14394
14113
|
const motion = motion$1;
|
|
14395
14114
|
const TYPE_STYLES = {
|
|
14396
14115
|
default: {
|
|
@@ -14504,6 +14223,407 @@ function ToastContainer({ position: position2 = "top-right" }) {
|
|
|
14504
14223
|
if (typeof document === "undefined") return null;
|
|
14505
14224
|
return createPortal(content2, portalContainer ?? document.body);
|
|
14506
14225
|
}
|
|
14226
|
+
const POLL_INTERVAL_MS = 3e3;
|
|
14227
|
+
const MAX_POLLS = 10;
|
|
14228
|
+
function isGeneratingStatus(status) {
|
|
14229
|
+
return status === "pending" || status === "processing";
|
|
14230
|
+
}
|
|
14231
|
+
function useGenerationPolling({
|
|
14232
|
+
status,
|
|
14233
|
+
onRefetch,
|
|
14234
|
+
maxPolls = MAX_POLLS,
|
|
14235
|
+
intervalMs = POLL_INTERVAL_MS,
|
|
14236
|
+
restartKey
|
|
14237
|
+
}) {
|
|
14238
|
+
const refetchRef = useRef(onRefetch);
|
|
14239
|
+
refetchRef.current = onRefetch;
|
|
14240
|
+
useEffect(() => {
|
|
14241
|
+
if (status !== "pending" && status !== "processing") return;
|
|
14242
|
+
let polls = 0;
|
|
14243
|
+
const timer = setInterval(() => {
|
|
14244
|
+
polls += 1;
|
|
14245
|
+
refetchRef.current();
|
|
14246
|
+
if (polls >= maxPolls) clearInterval(timer);
|
|
14247
|
+
}, intervalMs);
|
|
14248
|
+
return () => clearInterval(timer);
|
|
14249
|
+
}, [status, restartKey, maxPolls, intervalMs]);
|
|
14250
|
+
}
|
|
14251
|
+
function useIssueListGenerationPolling({
|
|
14252
|
+
issues,
|
|
14253
|
+
onRefetch
|
|
14254
|
+
}) {
|
|
14255
|
+
const generatingIds = issues.filter((issue) => isGeneratingStatus(issue.generation_status)).map((issue) => issue.id).sort().join(",");
|
|
14256
|
+
useGenerationPolling({
|
|
14257
|
+
status: generatingIds ? "pending" : null,
|
|
14258
|
+
restartKey: generatingIds,
|
|
14259
|
+
onRefetch
|
|
14260
|
+
});
|
|
14261
|
+
}
|
|
14262
|
+
async function uploadSignedMedia(file, mediaType, issueId) {
|
|
14263
|
+
return uploadSignedMediaWithApi(
|
|
14264
|
+
{
|
|
14265
|
+
post: (endpoint, body) => apiClient.post(endpoint, body),
|
|
14266
|
+
directUpload
|
|
14267
|
+
},
|
|
14268
|
+
file,
|
|
14269
|
+
mediaType,
|
|
14270
|
+
{ issueId }
|
|
14271
|
+
);
|
|
14272
|
+
}
|
|
14273
|
+
function issuesEndpoint() {
|
|
14274
|
+
return "/api/sdk/issues";
|
|
14275
|
+
}
|
|
14276
|
+
function guestOwnerQuery() {
|
|
14277
|
+
var _a;
|
|
14278
|
+
const mode = getSdkMode();
|
|
14279
|
+
if (mode !== "public") return "";
|
|
14280
|
+
return buildGuestOwnerQuery(mode, (_a = SDKManager.getInstance().config.user) == null ? void 0 : _a.id);
|
|
14281
|
+
}
|
|
14282
|
+
let issuesCache = null;
|
|
14283
|
+
const CACHE_DURATION_MS = 30 * 1e3;
|
|
14284
|
+
const STICKER_PAGE_SIZE = 500;
|
|
14285
|
+
const STICKER_FETCH_LIMIT = 2e3;
|
|
14286
|
+
function getFilterKey(filters) {
|
|
14287
|
+
var _a;
|
|
14288
|
+
const normalizeArray = (value) => {
|
|
14289
|
+
if (value === "all" || !value) return "all";
|
|
14290
|
+
if (Array.isArray(value)) {
|
|
14291
|
+
return value.length === 0 ? "all" : [...value].sort().join(",");
|
|
14292
|
+
}
|
|
14293
|
+
return String(value);
|
|
14294
|
+
};
|
|
14295
|
+
const normalizeRecord = (record) => {
|
|
14296
|
+
if (!record) return "";
|
|
14297
|
+
const entries = Object.entries(record).map(([k, v]) => [k, [...v].sort()]).sort(([a], [b]) => a.localeCompare(b));
|
|
14298
|
+
return JSON.stringify(entries);
|
|
14299
|
+
};
|
|
14300
|
+
return JSON.stringify({
|
|
14301
|
+
sdkMode: getSdkMode() || "public",
|
|
14302
|
+
url: normalizeArray(filters.url),
|
|
14303
|
+
projectId: filters.projectId || "all",
|
|
14304
|
+
externalUserId: filters.externalUserId || "",
|
|
14305
|
+
search: ((_a = filters.search) == null ? void 0 : _a.trim()) || "",
|
|
14306
|
+
dateFrom: filters.dateFrom || "",
|
|
14307
|
+
dateTo: filters.dateTo || "",
|
|
14308
|
+
page: filters.page ?? 0,
|
|
14309
|
+
pageSize: filters.pageSize ?? 0,
|
|
14310
|
+
custom: normalizeRecord(filters.customFieldValues),
|
|
14311
|
+
jira: normalizeRecord(filters.jiraFieldValues),
|
|
14312
|
+
notion: normalizeRecord(filters.notionFieldValues),
|
|
14313
|
+
sortOrder: filters.sortOrder || ""
|
|
14314
|
+
});
|
|
14315
|
+
}
|
|
14316
|
+
function invalidateIssuesCache() {
|
|
14317
|
+
issuesCache = null;
|
|
14318
|
+
}
|
|
14319
|
+
function recordToFilterArray(record, keyFieldName) {
|
|
14320
|
+
if (!record) return null;
|
|
14321
|
+
const entries = Object.entries(record).filter(([, values]) => values.length > 0);
|
|
14322
|
+
if (entries.length === 0) return null;
|
|
14323
|
+
return entries.map(
|
|
14324
|
+
([key, values]) => ({ [keyFieldName]: key, values })
|
|
14325
|
+
);
|
|
14326
|
+
}
|
|
14327
|
+
function buildFilterQueryParams(filters, options = {}) {
|
|
14328
|
+
var _a;
|
|
14329
|
+
const params = new URLSearchParams();
|
|
14330
|
+
if (filters.projectId) {
|
|
14331
|
+
params.set("project_id", filters.projectId);
|
|
14332
|
+
}
|
|
14333
|
+
if (filters.url && filters.url !== "all") {
|
|
14334
|
+
if (Array.isArray(filters.url) && filters.url.length > 0) {
|
|
14335
|
+
params.set("url", filters.url.join(","));
|
|
14336
|
+
} else if (typeof filters.url === "string") {
|
|
14337
|
+
params.set("url", filters.url);
|
|
14338
|
+
}
|
|
14339
|
+
}
|
|
14340
|
+
if (options.includeListFilters) {
|
|
14341
|
+
const search2 = (_a = filters.search) == null ? void 0 : _a.trim();
|
|
14342
|
+
if (search2) {
|
|
14343
|
+
params.set("search", search2);
|
|
14344
|
+
}
|
|
14345
|
+
if (filters.dateFrom) {
|
|
14346
|
+
params.set("date_from", filters.dateFrom);
|
|
14347
|
+
}
|
|
14348
|
+
if (filters.dateTo) {
|
|
14349
|
+
params.set("date_to", filters.dateTo);
|
|
14350
|
+
}
|
|
14351
|
+
const customArr = recordToFilterArray(filters.customFieldValues, "fieldDefinitionId");
|
|
14352
|
+
if (customArr) {
|
|
14353
|
+
params.set("custom_field_filters", JSON.stringify(customArr));
|
|
14354
|
+
}
|
|
14355
|
+
const jiraArr = recordToFilterArray(filters.jiraFieldValues, "fieldName");
|
|
14356
|
+
if (jiraArr) {
|
|
14357
|
+
params.set("jira_field_filters", JSON.stringify(jiraArr));
|
|
14358
|
+
}
|
|
14359
|
+
const notionArr = recordToFilterArray(filters.notionFieldValues, "fieldName");
|
|
14360
|
+
if (notionArr) {
|
|
14361
|
+
params.set("notion_field_filters", JSON.stringify(notionArr));
|
|
14362
|
+
}
|
|
14363
|
+
}
|
|
14364
|
+
if (filters.externalUserId) {
|
|
14365
|
+
params.set("external_user_id", filters.externalUserId);
|
|
14366
|
+
}
|
|
14367
|
+
if (typeof filters.page === "number" && filters.page > 0) {
|
|
14368
|
+
params.set("page", String(filters.page));
|
|
14369
|
+
}
|
|
14370
|
+
if (typeof filters.pageSize === "number" && filters.pageSize > 0) {
|
|
14371
|
+
params.set("page_size", String(filters.pageSize));
|
|
14372
|
+
}
|
|
14373
|
+
if (filters.sortOrder) {
|
|
14374
|
+
params.set("sort_order", filters.sortOrder);
|
|
14375
|
+
}
|
|
14376
|
+
const queryString = params.toString();
|
|
14377
|
+
return queryString ? `?${queryString}` : "";
|
|
14378
|
+
}
|
|
14379
|
+
const issueService = {
|
|
14380
|
+
async createIssue(issueData) {
|
|
14381
|
+
const sanitizedData = sanitizeString(issueData);
|
|
14382
|
+
const screenshotUploadIds = (sanitizedData.screenshot || []).map((url) => getRegisteredUploadId(url, "screenshot")).filter((id2) => typeof id2 === "string" && id2.length > 0);
|
|
14383
|
+
const videoUploadId = sanitizedData.video ? getRegisteredUploadId(sanitizedData.video, "video") : void 0;
|
|
14384
|
+
if (screenshotUploadIds.length > 0) {
|
|
14385
|
+
sanitizedData.screenshot_upload_ids = screenshotUploadIds;
|
|
14386
|
+
}
|
|
14387
|
+
if (videoUploadId) {
|
|
14388
|
+
sanitizedData.video_upload_id = videoUploadId;
|
|
14389
|
+
}
|
|
14390
|
+
const issue = await apiClient.post(issuesEndpoint(), sanitizedData);
|
|
14391
|
+
invalidateIssuesCache();
|
|
14392
|
+
return issue;
|
|
14393
|
+
},
|
|
14394
|
+
async getIssues(filters = {}, options = {}) {
|
|
14395
|
+
if (!filters.projectId) {
|
|
14396
|
+
throw new Error("프로젝트 ID가 필요합니다. 로그인 상태를 확인해주세요.");
|
|
14397
|
+
}
|
|
14398
|
+
const filterKey = getFilterKey(filters);
|
|
14399
|
+
const now2 = Date.now();
|
|
14400
|
+
if (!options.forceRefresh && issuesCache && issuesCache.filterKey === filterKey && now2 - issuesCache.timestamp < CACHE_DURATION_MS) {
|
|
14401
|
+
return issuesCache.data;
|
|
14402
|
+
}
|
|
14403
|
+
const queryParams = buildFilterQueryParams(filters, { includeListFilters: true });
|
|
14404
|
+
const { items: issues = [] } = await apiClient.get(
|
|
14405
|
+
`${issuesEndpoint()}${queryParams}`
|
|
14406
|
+
);
|
|
14407
|
+
issuesCache = {
|
|
14408
|
+
data: issues,
|
|
14409
|
+
timestamp: now2,
|
|
14410
|
+
filterKey
|
|
14411
|
+
};
|
|
14412
|
+
return issues;
|
|
14413
|
+
},
|
|
14414
|
+
async getIssueStickers(filters = {}, options = {}) {
|
|
14415
|
+
var _a, _b2;
|
|
14416
|
+
if (!filters.projectId) {
|
|
14417
|
+
throw new Error("프로젝트 ID가 필요합니다. 로그인 상태를 확인해주세요.");
|
|
14418
|
+
}
|
|
14419
|
+
const filterKey = `${getFilterKey(filters)}:stickers`;
|
|
14420
|
+
const now2 = Date.now();
|
|
14421
|
+
if (!options.forceRefresh && issuesCache && issuesCache.filterKey === filterKey && now2 - issuesCache.timestamp < CACHE_DURATION_MS) {
|
|
14422
|
+
return issuesCache.data;
|
|
14423
|
+
}
|
|
14424
|
+
const issues = [];
|
|
14425
|
+
let page = 1;
|
|
14426
|
+
let hasMore = true;
|
|
14427
|
+
while (hasMore && issues.length <= STICKER_FETCH_LIMIT) {
|
|
14428
|
+
const response = await apiClient.getResponse(
|
|
14429
|
+
`${issuesEndpoint()}/stickers${buildFilterQueryParams({
|
|
14430
|
+
...filters,
|
|
14431
|
+
page,
|
|
14432
|
+
pageSize: STICKER_PAGE_SIZE
|
|
14433
|
+
})}`
|
|
14434
|
+
);
|
|
14435
|
+
const pageItems = ((_a = response.data) == null ? void 0 : _a.items) ?? [];
|
|
14436
|
+
issues.push(...pageItems);
|
|
14437
|
+
hasMore = Boolean((_b2 = response.data) == null ? void 0 : _b2.hasMore) && pageItems.length > 0;
|
|
14438
|
+
page += 1;
|
|
14439
|
+
}
|
|
14440
|
+
issuesCache = {
|
|
14441
|
+
data: issues,
|
|
14442
|
+
timestamp: now2,
|
|
14443
|
+
filterKey
|
|
14444
|
+
};
|
|
14445
|
+
return issues;
|
|
14446
|
+
},
|
|
14447
|
+
invalidateCache() {
|
|
14448
|
+
invalidateIssuesCache();
|
|
14449
|
+
},
|
|
14450
|
+
// 계약 정본: 백엔드 GET /api/sdk/issues/:id 는 back#101부터 읽기-시점-스크럽된
|
|
14451
|
+
// llm_prompt 를 상세 응답에 포함한다(목록 응답에는 없음) — 스코프를 이 반환 타입에만 한정한다.
|
|
14452
|
+
async getIssue(id2) {
|
|
14453
|
+
return apiClient.get(
|
|
14454
|
+
`${issuesEndpoint()}/${id2}${guestOwnerQuery()}`
|
|
14455
|
+
);
|
|
14456
|
+
},
|
|
14457
|
+
async updateIssue(id2, updates) {
|
|
14458
|
+
const sanitizedUpdates = sanitizeString(updates);
|
|
14459
|
+
const issue = await apiClient.put(
|
|
14460
|
+
`${issuesEndpoint()}/${id2}${guestOwnerQuery()}`,
|
|
14461
|
+
sanitizedUpdates
|
|
14462
|
+
);
|
|
14463
|
+
invalidateIssuesCache();
|
|
14464
|
+
return issue;
|
|
14465
|
+
},
|
|
14466
|
+
/**
|
|
14467
|
+
* 재생성. 스펙상 세 표면 모두에서 되고 역할과 무관하다 — 게이트는 역할이 아니라
|
|
14468
|
+
* 그 이슈에 접근할 수 있는지다(백엔드가 판정한다).
|
|
14469
|
+
*
|
|
14470
|
+
* 응답으로 갱신된 이슈가 오지만 상태는 다시 pending 이다. 호출부는 응답을
|
|
14471
|
+
* 그대로 쓰지 말고 폴링으로 이어받아야 한다.
|
|
14472
|
+
*/
|
|
14473
|
+
async regenerateIssue(id2) {
|
|
14474
|
+
const issue = await apiClient.post(
|
|
14475
|
+
`${issuesEndpoint()}/${encodeURIComponent(id2)}/regenerate${guestOwnerQuery()}`,
|
|
14476
|
+
{}
|
|
14477
|
+
);
|
|
14478
|
+
invalidateIssuesCache();
|
|
14479
|
+
return issue;
|
|
14480
|
+
},
|
|
14481
|
+
async deleteIssue(id2, options) {
|
|
14482
|
+
const endpoint = `${issuesEndpoint()}/${id2}${guestOwnerQuery()}`;
|
|
14483
|
+
if (options == null ? void 0 : options.deleteExternal) {
|
|
14484
|
+
await apiClient.delete(endpoint, {
|
|
14485
|
+
body: { deleteExternal: true }
|
|
14486
|
+
});
|
|
14487
|
+
} else {
|
|
14488
|
+
await apiClient.delete(endpoint);
|
|
14489
|
+
}
|
|
14490
|
+
invalidateIssuesCache();
|
|
14491
|
+
}
|
|
14492
|
+
};
|
|
14493
|
+
async function loadIssuesFromServer(url, projectId, externalUserId, options = {}) {
|
|
14494
|
+
if (!projectId) return [];
|
|
14495
|
+
try {
|
|
14496
|
+
return await issueService.getIssueStickers(
|
|
14497
|
+
{
|
|
14498
|
+
url,
|
|
14499
|
+
projectId,
|
|
14500
|
+
...externalUserId ? { externalUserId } : {}
|
|
14501
|
+
},
|
|
14502
|
+
options
|
|
14503
|
+
) || [];
|
|
14504
|
+
} catch (error) {
|
|
14505
|
+
devLogger.error("useIssues", "Failed to load issues:", error);
|
|
14506
|
+
return [];
|
|
14507
|
+
}
|
|
14508
|
+
}
|
|
14509
|
+
const contentProjectIdQueryKey = ["contentProjectId"];
|
|
14510
|
+
const contentIssuesQueryRoot = ["contentIssues"];
|
|
14511
|
+
function contentIssuesQueryKey({
|
|
14512
|
+
currentUrl,
|
|
14513
|
+
projectId,
|
|
14514
|
+
isMember,
|
|
14515
|
+
externalUserId
|
|
14516
|
+
}) {
|
|
14517
|
+
return [...contentIssuesQueryRoot, currentUrl, projectId, isMember, externalUserId];
|
|
14518
|
+
}
|
|
14519
|
+
function fetchContentIssues({
|
|
14520
|
+
currentUrl,
|
|
14521
|
+
projectId,
|
|
14522
|
+
isMember,
|
|
14523
|
+
externalUserId,
|
|
14524
|
+
forceRefresh
|
|
14525
|
+
}) {
|
|
14526
|
+
return loadIssuesFromServer(currentUrl, projectId, isMember ? void 0 : externalUserId, {
|
|
14527
|
+
forceRefresh
|
|
14528
|
+
});
|
|
14529
|
+
}
|
|
14530
|
+
function useIssues(currentUrl) {
|
|
14531
|
+
var _a;
|
|
14532
|
+
const { isMember } = useAuthContext();
|
|
14533
|
+
const config = SDKManager.getInstance().config;
|
|
14534
|
+
const sessionIssuesRef = useRef([]);
|
|
14535
|
+
const projectIdQuery = useSuspenseQuery({
|
|
14536
|
+
queryKey: contentProjectIdQueryKey,
|
|
14537
|
+
queryFn: async () => {
|
|
14538
|
+
const accountInfo = await getAccountInfo();
|
|
14539
|
+
return (accountInfo == null ? void 0 : accountInfo.projectId) ?? null;
|
|
14540
|
+
}
|
|
14541
|
+
});
|
|
14542
|
+
const projectId = projectIdQuery.data;
|
|
14543
|
+
const { data: serverIssues = [] } = useSuspenseQuery({
|
|
14544
|
+
queryKey: contentIssuesQueryKey({
|
|
14545
|
+
currentUrl,
|
|
14546
|
+
projectId,
|
|
14547
|
+
isMember,
|
|
14548
|
+
externalUserId: (_a = config.user) == null ? void 0 : _a.id
|
|
14549
|
+
}),
|
|
14550
|
+
queryFn: () => {
|
|
14551
|
+
var _a2;
|
|
14552
|
+
return fetchContentIssues({
|
|
14553
|
+
currentUrl,
|
|
14554
|
+
projectId,
|
|
14555
|
+
isMember,
|
|
14556
|
+
externalUserId: (_a2 = config.user) == null ? void 0 : _a2.id
|
|
14557
|
+
});
|
|
14558
|
+
}
|
|
14559
|
+
});
|
|
14560
|
+
const issues = !isMember && !config.user ? [...serverIssues, ...sessionIssuesRef.current] : serverIssues;
|
|
14561
|
+
const addSessionIssue = useCallback((issue) => {
|
|
14562
|
+
sessionIssuesRef.current = [...sessionIssuesRef.current, issue];
|
|
14563
|
+
}, []);
|
|
14564
|
+
const loadIssues = useCallback(async () => {
|
|
14565
|
+
issueService.invalidateCache();
|
|
14566
|
+
await Promise.all([
|
|
14567
|
+
queryClient.invalidateQueries({ queryKey: contentIssuesQueryRoot }),
|
|
14568
|
+
queryClient.invalidateQueries({ queryKey: contentProjectIdQueryKey })
|
|
14569
|
+
]);
|
|
14570
|
+
}, []);
|
|
14571
|
+
useIssueListGenerationPolling({
|
|
14572
|
+
issues: serverIssues,
|
|
14573
|
+
onRefetch: () => void loadIssues()
|
|
14574
|
+
});
|
|
14575
|
+
return {
|
|
14576
|
+
issues,
|
|
14577
|
+
loadIssues,
|
|
14578
|
+
addSessionIssue
|
|
14579
|
+
};
|
|
14580
|
+
}
|
|
14581
|
+
function readCurrentUrl() {
|
|
14582
|
+
return getCurrentPageUrl();
|
|
14583
|
+
}
|
|
14584
|
+
function usePrefetchContentIssues() {
|
|
14585
|
+
const { isAuthenticated, isLoading, isMember, projectId, accountId, token } = useAuthContext();
|
|
14586
|
+
const lastFetchKeyRef = useRef(null);
|
|
14587
|
+
useEffect(() => {
|
|
14588
|
+
var _a;
|
|
14589
|
+
if (isLoading || !isAuthenticated || !projectId) {
|
|
14590
|
+
return;
|
|
14591
|
+
}
|
|
14592
|
+
const currentUrl = readCurrentUrl();
|
|
14593
|
+
const externalUserId = (_a = SDKManager.getInstance().config.user) == null ? void 0 : _a.id;
|
|
14594
|
+
const fetchKey = [
|
|
14595
|
+
currentUrl,
|
|
14596
|
+
projectId,
|
|
14597
|
+
isMember ? "member" : "public",
|
|
14598
|
+
accountId ?? "",
|
|
14599
|
+
token ?? "",
|
|
14600
|
+
externalUserId ?? ""
|
|
14601
|
+
].join("|");
|
|
14602
|
+
if (lastFetchKeyRef.current === fetchKey) {
|
|
14603
|
+
return;
|
|
14604
|
+
}
|
|
14605
|
+
lastFetchKeyRef.current = fetchKey;
|
|
14606
|
+
queryClient.setQueryData(contentProjectIdQueryKey, projectId);
|
|
14607
|
+
void queryClient.fetchQuery({
|
|
14608
|
+
queryKey: contentIssuesQueryKey({
|
|
14609
|
+
currentUrl,
|
|
14610
|
+
projectId,
|
|
14611
|
+
isMember,
|
|
14612
|
+
externalUserId
|
|
14613
|
+
}),
|
|
14614
|
+
queryFn: () => fetchContentIssues({
|
|
14615
|
+
currentUrl,
|
|
14616
|
+
projectId,
|
|
14617
|
+
isMember,
|
|
14618
|
+
externalUserId,
|
|
14619
|
+
forceRefresh: true
|
|
14620
|
+
}),
|
|
14621
|
+
staleTime: 0
|
|
14622
|
+
}).catch((error) => {
|
|
14623
|
+
devLogger.error("usePrefetchContentIssues", "Failed to prefetch issues:", error);
|
|
14624
|
+
});
|
|
14625
|
+
}, [accountId, isAuthenticated, isLoading, isMember, projectId, token]);
|
|
14626
|
+
}
|
|
14507
14627
|
function UnrenderedStickerDialog({
|
|
14508
14628
|
open,
|
|
14509
14629
|
items,
|
|
@@ -14587,6 +14707,74 @@ function UnrenderedStickerDialog({
|
|
|
14587
14707
|
}
|
|
14588
14708
|
);
|
|
14589
14709
|
}
|
|
14710
|
+
function getDeepActiveElement(root2 = document) {
|
|
14711
|
+
var _a;
|
|
14712
|
+
let active = root2.activeElement;
|
|
14713
|
+
while ((_a = active == null ? void 0 : active.shadowRoot) == null ? void 0 : _a.activeElement) {
|
|
14714
|
+
active = active.shadowRoot.activeElement;
|
|
14715
|
+
}
|
|
14716
|
+
return active;
|
|
14717
|
+
}
|
|
14718
|
+
const FOCUSABLE_SELECTOR = [
|
|
14719
|
+
"a[href]",
|
|
14720
|
+
"button:not([disabled])",
|
|
14721
|
+
"input:not([disabled])",
|
|
14722
|
+
"select:not([disabled])",
|
|
14723
|
+
"textarea:not([disabled])",
|
|
14724
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
14725
|
+
].join(",");
|
|
14726
|
+
function isVisible(element2, container) {
|
|
14727
|
+
if (getComputedStyle(element2).visibility === "hidden") return false;
|
|
14728
|
+
let node2 = element2;
|
|
14729
|
+
while (node2) {
|
|
14730
|
+
if (getComputedStyle(node2).display === "none") return false;
|
|
14731
|
+
if (node2 === container) break;
|
|
14732
|
+
node2 = node2.parentElement;
|
|
14733
|
+
}
|
|
14734
|
+
return true;
|
|
14735
|
+
}
|
|
14736
|
+
function tabbables(container) {
|
|
14737
|
+
return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter(
|
|
14738
|
+
(element2) => element2.tabIndex >= 0 && isVisible(element2, container)
|
|
14739
|
+
);
|
|
14740
|
+
}
|
|
14741
|
+
function useOverlayFocus({
|
|
14742
|
+
enabled,
|
|
14743
|
+
container,
|
|
14744
|
+
initialFocusRef,
|
|
14745
|
+
initialFocus = "first"
|
|
14746
|
+
}) {
|
|
14747
|
+
useEffect(() => {
|
|
14748
|
+
if (!enabled || !container) return;
|
|
14749
|
+
const restoreTo = getDeepActiveElement();
|
|
14750
|
+
const target = (initialFocusRef == null ? void 0 : initialFocusRef.current) ?? (initialFocus === "container" ? container : tabbables(container)[0] ?? container);
|
|
14751
|
+
target.focus({ preventScroll: true });
|
|
14752
|
+
const handleKeyDown = (event) => {
|
|
14753
|
+
if (event.key !== "Tab") return;
|
|
14754
|
+
const items = tabbables(container);
|
|
14755
|
+
const first = items[0];
|
|
14756
|
+
const last = items[items.length - 1];
|
|
14757
|
+
if (!first || !last) {
|
|
14758
|
+
event.preventDefault();
|
|
14759
|
+
return;
|
|
14760
|
+
}
|
|
14761
|
+
const active = getDeepActiveElement();
|
|
14762
|
+
const outside = !active || !container.contains(active);
|
|
14763
|
+
if (!event.shiftKey && (outside || active === last)) {
|
|
14764
|
+
event.preventDefault();
|
|
14765
|
+
first.focus({ preventScroll: true });
|
|
14766
|
+
} else if (event.shiftKey && (outside || active === first)) {
|
|
14767
|
+
event.preventDefault();
|
|
14768
|
+
last.focus({ preventScroll: true });
|
|
14769
|
+
}
|
|
14770
|
+
};
|
|
14771
|
+
container.addEventListener("keydown", handleKeyDown);
|
|
14772
|
+
return () => {
|
|
14773
|
+
container.removeEventListener("keydown", handleKeyDown);
|
|
14774
|
+
if (restoreTo == null ? void 0 : restoreTo.isConnected) restoreTo.focus({ preventScroll: true });
|
|
14775
|
+
};
|
|
14776
|
+
}, [enabled, container, initialFocusRef, initialFocus]);
|
|
14777
|
+
}
|
|
14590
14778
|
function OverlayShell({
|
|
14591
14779
|
open,
|
|
14592
14780
|
children,
|
|
@@ -14598,6 +14786,8 @@ function OverlayShell({
|
|
|
14598
14786
|
}) {
|
|
14599
14787
|
const onCloseRef = useRef(onClose);
|
|
14600
14788
|
onCloseRef.current = onClose;
|
|
14789
|
+
const [shell, setShell] = useState(null);
|
|
14790
|
+
useOverlayFocus({ enabled: open, container: shell, initialFocus: "container" });
|
|
14601
14791
|
useEffect(() => {
|
|
14602
14792
|
if (!open) return;
|
|
14603
14793
|
const handleKeyDown = (e) => {
|
|
@@ -14632,12 +14822,14 @@ function OverlayShell({
|
|
|
14632
14822
|
children: /* @__PURE__ */ jsx(
|
|
14633
14823
|
motion.div,
|
|
14634
14824
|
{
|
|
14825
|
+
ref: setShell,
|
|
14826
|
+
tabIndex: -1,
|
|
14635
14827
|
initial: { opacity: 0, y: 12, scale: 0.98 },
|
|
14636
14828
|
animate: { opacity: 1, y: 0, scale: 1 },
|
|
14637
14829
|
exit: { opacity: 0, y: 8, scale: 0.98 },
|
|
14638
14830
|
transition: { duration: 0.2, ease: [0.34, 1.2, 0.64, 1] },
|
|
14639
14831
|
className: cn$1(
|
|
14640
|
-
"issue-overlay-shell flex w-full flex-col overflow-hidden",
|
|
14832
|
+
"issue-overlay-shell flex w-full flex-col overflow-hidden focus:outline-none",
|
|
14641
14833
|
shellClassName
|
|
14642
14834
|
),
|
|
14643
14835
|
onClick: (e) => e.stopPropagation(),
|
|
@@ -14649,6 +14841,670 @@ function OverlayShell({
|
|
|
14649
14841
|
"overlay-backdrop"
|
|
14650
14842
|
) : null });
|
|
14651
14843
|
}
|
|
14844
|
+
const ISSUE_DRAFT_DISABLED_MESSAGE = "지금은 AI 작성을 사용할 수 없습니다. 제목과 설명을 직접 작성해주세요.";
|
|
14845
|
+
const LABEL = "기대한 동작";
|
|
14846
|
+
const PLACEHOLDER = "예: 할인 쿠폰을 적용하면 결제 금액에서 즉시 차감되어야 합니다";
|
|
14847
|
+
const SWITCH_TO_MANUAL = "직접 작성";
|
|
14848
|
+
const SUBMIT = "보내기";
|
|
14849
|
+
const MAX_INPUT_HEIGHT = 160;
|
|
14850
|
+
const FOCUS_RETRY_BUDGET_MS = 1e3;
|
|
14851
|
+
function isFocused(node2) {
|
|
14852
|
+
const root2 = node2.getRootNode();
|
|
14853
|
+
return root2 instanceof ShadowRoot ? root2.activeElement === node2 : document.activeElement === node2;
|
|
14854
|
+
}
|
|
14855
|
+
function IssueIntentBubble({
|
|
14856
|
+
value,
|
|
14857
|
+
onChange,
|
|
14858
|
+
onSubmit,
|
|
14859
|
+
onSwitchToManual,
|
|
14860
|
+
submitting = false,
|
|
14861
|
+
error = null
|
|
14862
|
+
}) {
|
|
14863
|
+
const inputRef = useRef(null);
|
|
14864
|
+
const canSubmit = !submitting && value.trim().length > 0;
|
|
14865
|
+
useEffect(() => {
|
|
14866
|
+
const node2 = inputRef.current;
|
|
14867
|
+
if (!node2) return;
|
|
14868
|
+
const deadline = Date.now() + FOCUS_RETRY_BUDGET_MS;
|
|
14869
|
+
let frame2 = 0;
|
|
14870
|
+
let abandoned = false;
|
|
14871
|
+
const abandon = () => {
|
|
14872
|
+
abandoned = true;
|
|
14873
|
+
};
|
|
14874
|
+
const attempt = () => {
|
|
14875
|
+
frame2 = 0;
|
|
14876
|
+
if (abandoned || isFocused(node2)) return;
|
|
14877
|
+
node2.focus({ preventScroll: true });
|
|
14878
|
+
if (isFocused(node2) || Date.now() >= deadline) return;
|
|
14879
|
+
frame2 = requestAnimationFrame(attempt);
|
|
14880
|
+
};
|
|
14881
|
+
window.addEventListener("pointerdown", abandon, { capture: true });
|
|
14882
|
+
window.addEventListener("keydown", abandon, { capture: true });
|
|
14883
|
+
attempt();
|
|
14884
|
+
return () => {
|
|
14885
|
+
window.removeEventListener("pointerdown", abandon, { capture: true });
|
|
14886
|
+
window.removeEventListener("keydown", abandon, { capture: true });
|
|
14887
|
+
if (frame2) cancelAnimationFrame(frame2);
|
|
14888
|
+
};
|
|
14889
|
+
}, []);
|
|
14890
|
+
useLayoutEffect(() => {
|
|
14891
|
+
const node2 = inputRef.current;
|
|
14892
|
+
if (!node2) return;
|
|
14893
|
+
node2.style.height = "auto";
|
|
14894
|
+
node2.style.height = `${Math.min(node2.scrollHeight, MAX_INPUT_HEIGHT)}px`;
|
|
14895
|
+
}, [value]);
|
|
14896
|
+
return (
|
|
14897
|
+
/*
|
|
14898
|
+
* 테두리는 포커스일 때만 브랜드 색으로 간다. 이 리포의 입력 컨트롤 관례가 그렇다
|
|
14899
|
+
* (ui/input.tsx, ui/textarea.tsx: 평소 border-line-subtle, 포커스에 line-focus).
|
|
14900
|
+
* `line-focus` 는 `--border-focus` = 브랜드 색상값이다(tokens.css).
|
|
14901
|
+
*
|
|
14902
|
+
* 관례는 `focus-visible:outline-line-focus` 지만 여기서는 border 로 바꾼다.
|
|
14903
|
+
* outline 은 border 상자 바깥에 그려지는데 말풍선 상자가 `overflow-hidden`
|
|
14904
|
+
* (IssueIntentBubbleAnchor)이라 잘린다. focus 가 아니라 focus-within 인 것은
|
|
14905
|
+
* 테두리가 카드에 있고 실제로 포커스를 받는 것은 그 안의 textarea 이기 때문이다.
|
|
14906
|
+
*/
|
|
14907
|
+
/* @__PURE__ */ jsxs(
|
|
14908
|
+
"div",
|
|
14909
|
+
{
|
|
14910
|
+
className: `${ISSUE_STICKER_REPORT_FORM_CLASS} w-80 space-y-1.5 rounded-md border border-line-subtle bg-surface-1 p-1.5 transition-colors duration-fast ease-out focus-within:border-line-focus`,
|
|
14911
|
+
children: [
|
|
14912
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-end gap-1.5", children: [
|
|
14913
|
+
/* @__PURE__ */ jsx(
|
|
14914
|
+
"textarea",
|
|
14915
|
+
{
|
|
14916
|
+
ref: inputRef,
|
|
14917
|
+
"aria-label": LABEL,
|
|
14918
|
+
rows: 1,
|
|
14919
|
+
className: "max-h-40 flex-1 resize-none overflow-y-auto bg-transparent px-1.5 py-1 text-sm text-text-primary outline-none placeholder:text-text-tertiary disabled:opacity-50",
|
|
14920
|
+
placeholder: PLACEHOLDER,
|
|
14921
|
+
value,
|
|
14922
|
+
disabled: submitting,
|
|
14923
|
+
onChange: (event) => onChange(event.target.value)
|
|
14924
|
+
}
|
|
14925
|
+
),
|
|
14926
|
+
/* @__PURE__ */ jsx(
|
|
14927
|
+
"button",
|
|
14928
|
+
{
|
|
14929
|
+
type: "button",
|
|
14930
|
+
"aria-label": SUBMIT,
|
|
14931
|
+
className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-brand text-brand-fg disabled:opacity-50",
|
|
14932
|
+
disabled: !canSubmit,
|
|
14933
|
+
onClick: () => canSubmit && onSubmit(),
|
|
14934
|
+
children: /* @__PURE__ */ jsx(ArrowUp, { className: "h-4 w-4" })
|
|
14935
|
+
}
|
|
14936
|
+
)
|
|
14937
|
+
] }),
|
|
14938
|
+
error ? /* @__PURE__ */ jsx("p", { className: "text-xs text-danger", children: error }) : null,
|
|
14939
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", variant: "secondary", size: "sm", onClick: onSwitchToManual, children: [
|
|
14940
|
+
/* @__PURE__ */ jsx(PenLine, { className: "h-3.5 w-3.5" }),
|
|
14941
|
+
SWITCH_TO_MANUAL
|
|
14942
|
+
] })
|
|
14943
|
+
]
|
|
14944
|
+
}
|
|
14945
|
+
)
|
|
14946
|
+
);
|
|
14947
|
+
}
|
|
14948
|
+
var DIALOG_NAME = "Dialog";
|
|
14949
|
+
var [createDialogContext] = createContextScope(DIALOG_NAME);
|
|
14950
|
+
var [DialogProvider, useDialogContext] = createDialogContext(DIALOG_NAME);
|
|
14951
|
+
var Dialog$1 = (props) => {
|
|
14952
|
+
const {
|
|
14953
|
+
__scopeDialog,
|
|
14954
|
+
children,
|
|
14955
|
+
open: openProp,
|
|
14956
|
+
defaultOpen,
|
|
14957
|
+
onOpenChange,
|
|
14958
|
+
modal = true
|
|
14959
|
+
} = props;
|
|
14960
|
+
const triggerRef = React.useRef(null);
|
|
14961
|
+
const contentRef = React.useRef(null);
|
|
14962
|
+
const [open, setOpen] = useControllableState({
|
|
14963
|
+
prop: openProp,
|
|
14964
|
+
defaultProp: defaultOpen ?? false,
|
|
14965
|
+
onChange: onOpenChange,
|
|
14966
|
+
caller: DIALOG_NAME
|
|
14967
|
+
});
|
|
14968
|
+
return /* @__PURE__ */ jsx(
|
|
14969
|
+
DialogProvider,
|
|
14970
|
+
{
|
|
14971
|
+
scope: __scopeDialog,
|
|
14972
|
+
triggerRef,
|
|
14973
|
+
contentRef,
|
|
14974
|
+
contentId: useId$1(),
|
|
14975
|
+
titleId: useId$1(),
|
|
14976
|
+
descriptionId: useId$1(),
|
|
14977
|
+
open,
|
|
14978
|
+
onOpenChange: setOpen,
|
|
14979
|
+
onOpenToggle: React.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen]),
|
|
14980
|
+
modal,
|
|
14981
|
+
children
|
|
14982
|
+
}
|
|
14983
|
+
);
|
|
14984
|
+
};
|
|
14985
|
+
Dialog$1.displayName = DIALOG_NAME;
|
|
14986
|
+
var TRIGGER_NAME$3 = "DialogTrigger";
|
|
14987
|
+
var DialogTrigger = React.forwardRef(
|
|
14988
|
+
(props, forwardedRef) => {
|
|
14989
|
+
const { __scopeDialog, ...triggerProps } = props;
|
|
14990
|
+
const context = useDialogContext(TRIGGER_NAME$3, __scopeDialog);
|
|
14991
|
+
const composedTriggerRef = useComposedRefs$1(forwardedRef, context.triggerRef);
|
|
14992
|
+
return /* @__PURE__ */ jsx(
|
|
14993
|
+
Primitive.button,
|
|
14994
|
+
{
|
|
14995
|
+
type: "button",
|
|
14996
|
+
"aria-haspopup": "dialog",
|
|
14997
|
+
"aria-expanded": context.open,
|
|
14998
|
+
"aria-controls": context.open ? context.contentId : void 0,
|
|
14999
|
+
"data-state": getState$2(context.open),
|
|
15000
|
+
...triggerProps,
|
|
15001
|
+
ref: composedTriggerRef,
|
|
15002
|
+
onClick: composeEventHandlers(props.onClick, context.onOpenToggle)
|
|
15003
|
+
}
|
|
15004
|
+
);
|
|
15005
|
+
}
|
|
15006
|
+
);
|
|
15007
|
+
DialogTrigger.displayName = TRIGGER_NAME$3;
|
|
15008
|
+
var PORTAL_NAME = "DialogPortal";
|
|
15009
|
+
var [PortalProvider, usePortalContext] = createDialogContext(PORTAL_NAME, {
|
|
15010
|
+
forceMount: void 0
|
|
15011
|
+
});
|
|
15012
|
+
var DialogPortal$1 = (props) => {
|
|
15013
|
+
const { __scopeDialog, forceMount, children, container } = props;
|
|
15014
|
+
const context = useDialogContext(PORTAL_NAME, __scopeDialog);
|
|
15015
|
+
return /* @__PURE__ */ jsx(PortalProvider, { scope: __scopeDialog, forceMount, children: React.Children.map(children, (child) => /* @__PURE__ */ jsx(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsx(Portal$1, { asChild: true, container, children: child }) })) });
|
|
15016
|
+
};
|
|
15017
|
+
DialogPortal$1.displayName = PORTAL_NAME;
|
|
15018
|
+
var OVERLAY_NAME = "DialogOverlay";
|
|
15019
|
+
var DialogOverlay$1 = React.forwardRef(
|
|
15020
|
+
(props, forwardedRef) => {
|
|
15021
|
+
const portalContext = usePortalContext(OVERLAY_NAME, props.__scopeDialog);
|
|
15022
|
+
const { forceMount = portalContext.forceMount, ...overlayProps } = props;
|
|
15023
|
+
const context = useDialogContext(OVERLAY_NAME, props.__scopeDialog);
|
|
15024
|
+
return context.modal ? /* @__PURE__ */ jsx(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsx(DialogOverlayImpl, { ...overlayProps, ref: forwardedRef }) }) : null;
|
|
15025
|
+
}
|
|
15026
|
+
);
|
|
15027
|
+
DialogOverlay$1.displayName = OVERLAY_NAME;
|
|
15028
|
+
var Slot = createSlot("DialogOverlay.RemoveScroll");
|
|
15029
|
+
var DialogOverlayImpl = React.forwardRef(
|
|
15030
|
+
(props, forwardedRef) => {
|
|
15031
|
+
const { __scopeDialog, ...overlayProps } = props;
|
|
15032
|
+
const context = useDialogContext(OVERLAY_NAME, __scopeDialog);
|
|
15033
|
+
const registerDismissableSurface = useDismissableLayerSurface();
|
|
15034
|
+
const composedRefs = useComposedRefs$1(forwardedRef, registerDismissableSurface);
|
|
15035
|
+
return (
|
|
15036
|
+
// Make sure `Content` is scrollable even when it doesn't live inside `RemoveScroll`
|
|
15037
|
+
// ie. when `Overlay` and `Content` are siblings
|
|
15038
|
+
/* @__PURE__ */ jsx(ReactRemoveScroll, { as: Slot, allowPinchZoom: true, shards: [context.contentRef], children: /* @__PURE__ */ jsx(
|
|
15039
|
+
Primitive.div,
|
|
15040
|
+
{
|
|
15041
|
+
"data-state": getState$2(context.open),
|
|
15042
|
+
...overlayProps,
|
|
15043
|
+
ref: composedRefs,
|
|
15044
|
+
style: { pointerEvents: "auto", ...overlayProps.style }
|
|
15045
|
+
}
|
|
15046
|
+
) })
|
|
15047
|
+
);
|
|
15048
|
+
}
|
|
15049
|
+
);
|
|
15050
|
+
var CONTENT_NAME$3 = "DialogContent";
|
|
15051
|
+
var DialogContent$1 = React.forwardRef(
|
|
15052
|
+
(props, forwardedRef) => {
|
|
15053
|
+
const portalContext = usePortalContext(CONTENT_NAME$3, props.__scopeDialog);
|
|
15054
|
+
const { forceMount = portalContext.forceMount, ...contentProps } = props;
|
|
15055
|
+
const context = useDialogContext(CONTENT_NAME$3, props.__scopeDialog);
|
|
15056
|
+
return /* @__PURE__ */ jsx(Presence, { present: forceMount || context.open, children: context.modal ? /* @__PURE__ */ jsx(DialogContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ jsx(DialogContentNonModal, { ...contentProps, ref: forwardedRef }) });
|
|
15057
|
+
}
|
|
15058
|
+
);
|
|
15059
|
+
DialogContent$1.displayName = CONTENT_NAME$3;
|
|
15060
|
+
var DialogContentModal = React.forwardRef(
|
|
15061
|
+
(props, forwardedRef) => {
|
|
15062
|
+
const context = useDialogContext(CONTENT_NAME$3, props.__scopeDialog);
|
|
15063
|
+
const contentRef = React.useRef(null);
|
|
15064
|
+
const composedRefs = useComposedRefs$1(forwardedRef, context.contentRef, contentRef);
|
|
15065
|
+
React.useEffect(() => {
|
|
15066
|
+
const content2 = contentRef.current;
|
|
15067
|
+
if (content2) return hideOthers(content2);
|
|
15068
|
+
}, []);
|
|
15069
|
+
return /* @__PURE__ */ jsx(
|
|
15070
|
+
DialogContentImpl,
|
|
15071
|
+
{
|
|
15072
|
+
...props,
|
|
15073
|
+
ref: composedRefs,
|
|
15074
|
+
trapFocus: context.open,
|
|
15075
|
+
disableOutsidePointerEvents: context.open,
|
|
15076
|
+
onCloseAutoFocus: composeEventHandlers(props.onCloseAutoFocus, (event) => {
|
|
15077
|
+
var _a;
|
|
15078
|
+
event.preventDefault();
|
|
15079
|
+
(_a = context.triggerRef.current) == null ? void 0 : _a.focus();
|
|
15080
|
+
}),
|
|
15081
|
+
onPointerDownOutside: composeEventHandlers(props.onPointerDownOutside, (event) => {
|
|
15082
|
+
const originalEvent = event.detail.originalEvent;
|
|
15083
|
+
const ctrlLeftClick = originalEvent.button === 0 && originalEvent.ctrlKey === true;
|
|
15084
|
+
const isRightClick = originalEvent.button === 2 || ctrlLeftClick;
|
|
15085
|
+
if (isRightClick) event.preventDefault();
|
|
15086
|
+
}),
|
|
15087
|
+
onFocusOutside: composeEventHandlers(
|
|
15088
|
+
props.onFocusOutside,
|
|
15089
|
+
(event) => event.preventDefault()
|
|
15090
|
+
)
|
|
15091
|
+
}
|
|
15092
|
+
);
|
|
15093
|
+
}
|
|
15094
|
+
);
|
|
15095
|
+
var DialogContentNonModal = React.forwardRef(
|
|
15096
|
+
(props, forwardedRef) => {
|
|
15097
|
+
const context = useDialogContext(CONTENT_NAME$3, props.__scopeDialog);
|
|
15098
|
+
const hasInteractedOutsideRef = React.useRef(false);
|
|
15099
|
+
const hasPointerDownOutsideRef = React.useRef(false);
|
|
15100
|
+
return /* @__PURE__ */ jsx(
|
|
15101
|
+
DialogContentImpl,
|
|
15102
|
+
{
|
|
15103
|
+
...props,
|
|
15104
|
+
ref: forwardedRef,
|
|
15105
|
+
trapFocus: false,
|
|
15106
|
+
disableOutsidePointerEvents: false,
|
|
15107
|
+
onCloseAutoFocus: (event) => {
|
|
15108
|
+
var _a, _b2;
|
|
15109
|
+
(_a = props.onCloseAutoFocus) == null ? void 0 : _a.call(props, event);
|
|
15110
|
+
if (!event.defaultPrevented) {
|
|
15111
|
+
if (!hasInteractedOutsideRef.current) (_b2 = context.triggerRef.current) == null ? void 0 : _b2.focus();
|
|
15112
|
+
event.preventDefault();
|
|
15113
|
+
}
|
|
15114
|
+
hasInteractedOutsideRef.current = false;
|
|
15115
|
+
hasPointerDownOutsideRef.current = false;
|
|
15116
|
+
},
|
|
15117
|
+
onInteractOutside: (event) => {
|
|
15118
|
+
var _a, _b2;
|
|
15119
|
+
(_a = props.onInteractOutside) == null ? void 0 : _a.call(props, event);
|
|
15120
|
+
if (!event.defaultPrevented) {
|
|
15121
|
+
hasInteractedOutsideRef.current = true;
|
|
15122
|
+
if (event.detail.originalEvent.type === "pointerdown") {
|
|
15123
|
+
hasPointerDownOutsideRef.current = true;
|
|
15124
|
+
}
|
|
15125
|
+
}
|
|
15126
|
+
const target = event.target;
|
|
15127
|
+
const targetIsTrigger = (_b2 = context.triggerRef.current) == null ? void 0 : _b2.contains(target);
|
|
15128
|
+
if (targetIsTrigger) event.preventDefault();
|
|
15129
|
+
if (event.detail.originalEvent.type === "focusin" && hasPointerDownOutsideRef.current) {
|
|
15130
|
+
event.preventDefault();
|
|
15131
|
+
}
|
|
15132
|
+
}
|
|
15133
|
+
}
|
|
15134
|
+
);
|
|
15135
|
+
}
|
|
15136
|
+
);
|
|
15137
|
+
var DialogContentImpl = React.forwardRef(
|
|
15138
|
+
(props, forwardedRef) => {
|
|
15139
|
+
const { __scopeDialog, trapFocus, onOpenAutoFocus, onCloseAutoFocus, ...contentProps } = props;
|
|
15140
|
+
const context = useDialogContext(CONTENT_NAME$3, __scopeDialog);
|
|
15141
|
+
useFocusGuards();
|
|
15142
|
+
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
|
|
15143
|
+
FocusScope,
|
|
15144
|
+
{
|
|
15145
|
+
asChild: true,
|
|
15146
|
+
loop: true,
|
|
15147
|
+
trapped: trapFocus,
|
|
15148
|
+
onMountAutoFocus: onOpenAutoFocus,
|
|
15149
|
+
onUnmountAutoFocus: onCloseAutoFocus,
|
|
15150
|
+
children: /* @__PURE__ */ jsx(
|
|
15151
|
+
DismissableLayer,
|
|
15152
|
+
{
|
|
15153
|
+
role: "dialog",
|
|
15154
|
+
id: context.contentId,
|
|
15155
|
+
"aria-describedby": context.descriptionId,
|
|
15156
|
+
"aria-labelledby": context.titleId,
|
|
15157
|
+
"data-state": getState$2(context.open),
|
|
15158
|
+
...contentProps,
|
|
15159
|
+
ref: forwardedRef,
|
|
15160
|
+
deferPointerDownOutside: true,
|
|
15161
|
+
onDismiss: () => context.onOpenChange(false)
|
|
15162
|
+
}
|
|
15163
|
+
)
|
|
15164
|
+
}
|
|
15165
|
+
) });
|
|
15166
|
+
}
|
|
15167
|
+
);
|
|
15168
|
+
var TITLE_NAME = "DialogTitle";
|
|
15169
|
+
var DialogTitle$1 = React.forwardRef(
|
|
15170
|
+
(props, forwardedRef) => {
|
|
15171
|
+
const { __scopeDialog, ...titleProps } = props;
|
|
15172
|
+
const context = useDialogContext(TITLE_NAME, __scopeDialog);
|
|
15173
|
+
return /* @__PURE__ */ jsx(Primitive.h2, { id: context.titleId, ...titleProps, ref: forwardedRef });
|
|
15174
|
+
}
|
|
15175
|
+
);
|
|
15176
|
+
DialogTitle$1.displayName = TITLE_NAME;
|
|
15177
|
+
var DESCRIPTION_NAME = "DialogDescription";
|
|
15178
|
+
var DialogDescription$1 = React.forwardRef(
|
|
15179
|
+
(props, forwardedRef) => {
|
|
15180
|
+
const { __scopeDialog, ...descriptionProps } = props;
|
|
15181
|
+
const context = useDialogContext(DESCRIPTION_NAME, __scopeDialog);
|
|
15182
|
+
return /* @__PURE__ */ jsx(Primitive.p, { id: context.descriptionId, ...descriptionProps, ref: forwardedRef });
|
|
15183
|
+
}
|
|
15184
|
+
);
|
|
15185
|
+
DialogDescription$1.displayName = DESCRIPTION_NAME;
|
|
15186
|
+
var CLOSE_NAME = "DialogClose";
|
|
15187
|
+
var DialogClose$1 = React.forwardRef(
|
|
15188
|
+
(props, forwardedRef) => {
|
|
15189
|
+
const { __scopeDialog, ...closeProps } = props;
|
|
15190
|
+
const context = useDialogContext(CLOSE_NAME, __scopeDialog);
|
|
15191
|
+
return /* @__PURE__ */ jsx(
|
|
15192
|
+
Primitive.button,
|
|
15193
|
+
{
|
|
15194
|
+
type: "button",
|
|
15195
|
+
...closeProps,
|
|
15196
|
+
ref: forwardedRef,
|
|
15197
|
+
onClick: composeEventHandlers(props.onClick, () => context.onOpenChange(false))
|
|
15198
|
+
}
|
|
15199
|
+
);
|
|
15200
|
+
}
|
|
15201
|
+
);
|
|
15202
|
+
DialogClose$1.displayName = CLOSE_NAME;
|
|
15203
|
+
function getState$2(open) {
|
|
15204
|
+
return open ? "open" : "closed";
|
|
15205
|
+
}
|
|
15206
|
+
const Dialog = Dialog$1;
|
|
15207
|
+
const DialogClose = DialogClose$1;
|
|
15208
|
+
const DialogPortal = ({ children }) => {
|
|
15209
|
+
const portalContainer = usePortalContainer();
|
|
15210
|
+
return /* @__PURE__ */ jsx(DialogPortal$1, { container: portalContainer, children });
|
|
15211
|
+
};
|
|
15212
|
+
const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
15213
|
+
DialogOverlay$1,
|
|
15214
|
+
{
|
|
15215
|
+
ref,
|
|
15216
|
+
className: cn$1(
|
|
15217
|
+
`fixed inset-0 ${OVERLAY_LAYER.dialogOverlay} bg-black/24`,
|
|
15218
|
+
"data-[state=open]:animate-fade-in data-[state=closed]:animate-fade-out",
|
|
15219
|
+
"motion-reduce:animate-none",
|
|
15220
|
+
className
|
|
15221
|
+
),
|
|
15222
|
+
...props
|
|
15223
|
+
}
|
|
15224
|
+
));
|
|
15225
|
+
DialogOverlay.displayName = DialogOverlay$1.displayName;
|
|
15226
|
+
const DialogContent = React.forwardRef(
|
|
15227
|
+
({
|
|
15228
|
+
className,
|
|
15229
|
+
children,
|
|
15230
|
+
hideCloseButton = false,
|
|
15231
|
+
initialFocusRef,
|
|
15232
|
+
onEscapeKeyDown,
|
|
15233
|
+
onOpenAutoFocus,
|
|
15234
|
+
onCloseAutoFocus,
|
|
15235
|
+
style,
|
|
15236
|
+
...props
|
|
15237
|
+
}, ref) => {
|
|
15238
|
+
const [content2, setContent] = React.useState(null);
|
|
15239
|
+
const composedRef = React.useCallback(
|
|
15240
|
+
(node2) => {
|
|
15241
|
+
setContent(node2);
|
|
15242
|
+
if (typeof ref === "function") ref(node2);
|
|
15243
|
+
else if (ref) ref.current = node2;
|
|
15244
|
+
},
|
|
15245
|
+
[ref]
|
|
15246
|
+
);
|
|
15247
|
+
useOverlayFocus({ enabled: true, container: content2, initialFocusRef });
|
|
15248
|
+
return /* @__PURE__ */ jsxs(DialogPortal, { children: [
|
|
15249
|
+
/* @__PURE__ */ jsx(DialogOverlay, {}),
|
|
15250
|
+
/* @__PURE__ */ jsxs(
|
|
15251
|
+
DialogContent$1,
|
|
15252
|
+
{
|
|
15253
|
+
ref: composedRef,
|
|
15254
|
+
onEscapeKeyDown: stopEscapePropagation(onEscapeKeyDown),
|
|
15255
|
+
onOpenAutoFocus: (event) => {
|
|
15256
|
+
onOpenAutoFocus == null ? void 0 : onOpenAutoFocus(event);
|
|
15257
|
+
event.preventDefault();
|
|
15258
|
+
},
|
|
15259
|
+
onCloseAutoFocus: (event) => {
|
|
15260
|
+
onCloseAutoFocus == null ? void 0 : onCloseAutoFocus(event);
|
|
15261
|
+
event.preventDefault();
|
|
15262
|
+
},
|
|
15263
|
+
style: {
|
|
15264
|
+
left: `calc(50% - (var(${BODY_SCROLLBAR_WIDTH_CSS_VAR}, 0px) / 2))`,
|
|
15265
|
+
...style
|
|
15266
|
+
},
|
|
15267
|
+
className: cn$1(
|
|
15268
|
+
`panel-shell fixed left-[50%] top-[50%] ${OVERLAY_LAYER.dialogContent} grid w-full max-w-[36rem] translate-x-[-50%] translate-y-[-50%] gap-5 rounded-2xl p-7 shadow-lg`,
|
|
15269
|
+
"focus:outline-none",
|
|
15270
|
+
"data-[state=open]:animate-dialog-in data-[state=closed]:animate-dialog-out",
|
|
15271
|
+
"motion-reduce:animate-none",
|
|
15272
|
+
className
|
|
15273
|
+
),
|
|
15274
|
+
...props,
|
|
15275
|
+
children: [
|
|
15276
|
+
children,
|
|
15277
|
+
!hideCloseButton ? /* @__PURE__ */ jsxs(
|
|
15278
|
+
DialogClose$1,
|
|
15279
|
+
{
|
|
15280
|
+
className: cn$1(
|
|
15281
|
+
"absolute right-4 top-4 rounded-md border border-transparent bg-surface-2 p-1.5 text-text-tertiary",
|
|
15282
|
+
"transition-colors duration-fast",
|
|
15283
|
+
"hover:border-line-subtle hover:bg-surface-3 hover:text-text-primary",
|
|
15284
|
+
"focus-visible:outline-none focus-visible:shadow-focus"
|
|
15285
|
+
),
|
|
15286
|
+
children: [
|
|
15287
|
+
/* @__PURE__ */ jsx(X$1, { className: "h-4 w-4" }),
|
|
15288
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "닫기" })
|
|
15289
|
+
]
|
|
15290
|
+
}
|
|
15291
|
+
) : null
|
|
15292
|
+
]
|
|
15293
|
+
}
|
|
15294
|
+
)
|
|
15295
|
+
] });
|
|
15296
|
+
}
|
|
15297
|
+
);
|
|
15298
|
+
DialogContent.displayName = DialogContent$1.displayName;
|
|
15299
|
+
const DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx("div", { className: cn$1("flex flex-col space-y-2 text-left", className), ...props });
|
|
15300
|
+
const DialogTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
15301
|
+
DialogTitle$1,
|
|
15302
|
+
{
|
|
15303
|
+
ref,
|
|
15304
|
+
className: cn$1("text-lg font-semibold text-text-primary", className),
|
|
15305
|
+
...props
|
|
15306
|
+
}
|
|
15307
|
+
));
|
|
15308
|
+
DialogTitle.displayName = DialogTitle$1.displayName;
|
|
15309
|
+
const DialogDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
15310
|
+
DialogDescription$1,
|
|
15311
|
+
{
|
|
15312
|
+
ref,
|
|
15313
|
+
className: cn$1("text-sm leading-relaxed text-text-secondary", className),
|
|
15314
|
+
...props
|
|
15315
|
+
}
|
|
15316
|
+
));
|
|
15317
|
+
DialogDescription.displayName = DialogDescription$1.displayName;
|
|
15318
|
+
const VIEWPORT_MARGIN = 12;
|
|
15319
|
+
const PREVIEW_STICKER_SIZE = 32;
|
|
15320
|
+
const STICKER_GAP = 8;
|
|
15321
|
+
const BUBBLE_OFFSET = PREVIEW_STICKER_SIZE / 2 + STICKER_GAP;
|
|
15322
|
+
const DISCARD_MESSAGE = "지금 닫으면 작성 중인 내용이 사라집니다. 닫으시겠습니까?";
|
|
15323
|
+
const DISCARD_CANCEL = "취소";
|
|
15324
|
+
const DISCARD_CONFIRM = "닫기";
|
|
15325
|
+
function clampBubblePosition(x, y, width, height, viewportWidth, viewportHeight, margin = VIEWPORT_MARGIN) {
|
|
15326
|
+
const maxLeft = Math.max(margin, viewportWidth - width - margin);
|
|
15327
|
+
const maxTop = Math.max(margin, viewportHeight - height - margin);
|
|
15328
|
+
return {
|
|
15329
|
+
left: Math.min(Math.max(x, margin), maxLeft),
|
|
15330
|
+
top: Math.min(Math.max(y, margin), maxTop)
|
|
15331
|
+
};
|
|
15332
|
+
}
|
|
15333
|
+
function resolveBubbleLayout(stickerLeft, stickerTop, width, height, viewportWidth, viewportHeight, margin = VIEWPORT_MARGIN) {
|
|
15334
|
+
const rightLeft = stickerLeft + BUBBLE_OFFSET;
|
|
15335
|
+
const leftLeft = stickerLeft - BUBBLE_OFFSET - width;
|
|
15336
|
+
const side = rightLeft + width <= viewportWidth - margin ? "right" : leftLeft >= margin ? "left" : "right";
|
|
15337
|
+
const { left, top } = clampBubblePosition(
|
|
15338
|
+
side === "right" ? rightLeft : leftLeft,
|
|
15339
|
+
stickerTop - PREVIEW_STICKER_SIZE / 2,
|
|
15340
|
+
width,
|
|
15341
|
+
height,
|
|
15342
|
+
viewportWidth,
|
|
15343
|
+
viewportHeight,
|
|
15344
|
+
margin
|
|
15345
|
+
);
|
|
15346
|
+
return { left, top, side };
|
|
15347
|
+
}
|
|
15348
|
+
function IssueIntentBubbleAnchor({
|
|
15349
|
+
x,
|
|
15350
|
+
y,
|
|
15351
|
+
children,
|
|
15352
|
+
onClose,
|
|
15353
|
+
dirty = false,
|
|
15354
|
+
open = true,
|
|
15355
|
+
onExitComplete
|
|
15356
|
+
}) {
|
|
15357
|
+
const contentRef = useRef(null);
|
|
15358
|
+
const onCloseRef = useRef(onClose);
|
|
15359
|
+
onCloseRef.current = onClose;
|
|
15360
|
+
const dirtyRef = useRef(dirty);
|
|
15361
|
+
dirtyRef.current = dirty;
|
|
15362
|
+
const [confirmingDiscard, setConfirmingDiscard] = useState(false);
|
|
15363
|
+
const discardCancelRef = useRef(null);
|
|
15364
|
+
const confirmingDiscardRef = useRef(confirmingDiscard);
|
|
15365
|
+
confirmingDiscardRef.current = confirmingDiscard;
|
|
15366
|
+
const [layout2, setLayout] = useState(null);
|
|
15367
|
+
const reduceMotion = useReducedMotion();
|
|
15368
|
+
useLayoutEffect(() => {
|
|
15369
|
+
let frame2 = 0;
|
|
15370
|
+
const apply = () => {
|
|
15371
|
+
frame2 = 0;
|
|
15372
|
+
const node2 = contentRef.current;
|
|
15373
|
+
if (!node2) return;
|
|
15374
|
+
const { width, height } = node2.getBoundingClientRect();
|
|
15375
|
+
const stickerLeft = x - window.scrollX;
|
|
15376
|
+
const stickerTop = y - window.scrollY;
|
|
15377
|
+
const placement = resolveBubbleLayout(
|
|
15378
|
+
stickerLeft,
|
|
15379
|
+
stickerTop,
|
|
15380
|
+
width,
|
|
15381
|
+
height,
|
|
15382
|
+
window.innerWidth,
|
|
15383
|
+
window.innerHeight
|
|
15384
|
+
);
|
|
15385
|
+
setLayout({
|
|
15386
|
+
stickerLeft,
|
|
15387
|
+
stickerTop,
|
|
15388
|
+
bubbleTop: placement.top,
|
|
15389
|
+
// 왼쪽에 열 때는 right 를 고정해야 너비가 스티커 쪽으로 자란다.
|
|
15390
|
+
bubbleLeft: placement.side === "right" ? placement.left : null,
|
|
15391
|
+
bubbleRight: placement.side === "right" ? null : window.innerWidth - (placement.left + width)
|
|
15392
|
+
});
|
|
15393
|
+
};
|
|
15394
|
+
const schedule = () => {
|
|
15395
|
+
if (frame2) return;
|
|
15396
|
+
frame2 = window.requestAnimationFrame(apply);
|
|
15397
|
+
};
|
|
15398
|
+
apply();
|
|
15399
|
+
window.addEventListener("scroll", schedule, { capture: true, passive: true });
|
|
15400
|
+
window.addEventListener("resize", schedule, { passive: true });
|
|
15401
|
+
let contentObserver = null;
|
|
15402
|
+
if (contentRef.current && typeof ResizeObserver !== "undefined") {
|
|
15403
|
+
contentObserver = new ResizeObserver(schedule);
|
|
15404
|
+
contentObserver.observe(contentRef.current);
|
|
15405
|
+
}
|
|
15406
|
+
return () => {
|
|
15407
|
+
window.removeEventListener("scroll", schedule, { capture: true });
|
|
15408
|
+
window.removeEventListener("resize", schedule);
|
|
15409
|
+
contentObserver == null ? void 0 : contentObserver.disconnect();
|
|
15410
|
+
if (frame2) window.cancelAnimationFrame(frame2);
|
|
15411
|
+
};
|
|
15412
|
+
}, [x, y]);
|
|
15413
|
+
useEffect(() => {
|
|
15414
|
+
const handleKeyDown = (event) => {
|
|
15415
|
+
if (event.key !== "Escape") return;
|
|
15416
|
+
event.preventDefault();
|
|
15417
|
+
if (confirmingDiscardRef.current) return;
|
|
15418
|
+
if (dirtyRef.current) {
|
|
15419
|
+
setConfirmingDiscard(true);
|
|
15420
|
+
return;
|
|
15421
|
+
}
|
|
15422
|
+
onCloseRef.current();
|
|
15423
|
+
};
|
|
15424
|
+
window.addEventListener("keydown", handleKeyDown, { capture: true });
|
|
15425
|
+
return () => window.removeEventListener("keydown", handleKeyDown, { capture: true });
|
|
15426
|
+
}, []);
|
|
15427
|
+
useDisableBodyScroll(confirmingDiscard);
|
|
15428
|
+
const visibility = layout2 ? "visible" : "hidden";
|
|
15429
|
+
const stickerTransition = reduceMotion ? { duration: 0 } : { duration: 0.18, ease: [0.34, 1.2, 0.64, 1] };
|
|
15430
|
+
const bubbleTransition = reduceMotion ? { duration: 0 } : { duration: 0.22, ease: [0.34, 1.2, 0.64, 1] };
|
|
15431
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
15432
|
+
/* @__PURE__ */ jsx(AnimatePresence, { onExitComplete, children: open ? [
|
|
15433
|
+
/* @__PURE__ */ jsx(
|
|
15434
|
+
motion.div,
|
|
15435
|
+
{
|
|
15436
|
+
"data-issue-sticker-preview": "",
|
|
15437
|
+
"aria-hidden": "true",
|
|
15438
|
+
className: `pointer-events-none fixed ${OVERLAY_LAYER.shell} flex h-8 w-8 items-center justify-center rounded-full border border-white/80 bg-brand text-sm font-black leading-none text-white`,
|
|
15439
|
+
style: {
|
|
15440
|
+
left: (layout2 == null ? void 0 : layout2.stickerLeft) ?? x,
|
|
15441
|
+
top: (layout2 == null ? void 0 : layout2.stickerTop) ?? y,
|
|
15442
|
+
visibility
|
|
15443
|
+
},
|
|
15444
|
+
initial: { opacity: 0, scale: 0.5, x: "-50%", y: "-50%" },
|
|
15445
|
+
animate: { opacity: 1, scale: 1, x: "-50%", y: "-50%" },
|
|
15446
|
+
exit: { opacity: 0, scale: 0.5, x: "-50%", y: "-50%" },
|
|
15447
|
+
transition: stickerTransition,
|
|
15448
|
+
children: "!"
|
|
15449
|
+
},
|
|
15450
|
+
"preview-sticker"
|
|
15451
|
+
),
|
|
15452
|
+
/* @__PURE__ */ jsx(
|
|
15453
|
+
motion.div,
|
|
15454
|
+
{
|
|
15455
|
+
"data-issue-sticker-bubble": "",
|
|
15456
|
+
className: `pointer-events-auto fixed overflow-hidden ${OVERLAY_LAYER.shell}`,
|
|
15457
|
+
style: {
|
|
15458
|
+
left: (layout2 == null ? void 0 : layout2.bubbleLeft) ?? void 0,
|
|
15459
|
+
right: (layout2 == null ? void 0 : layout2.bubbleRight) ?? void 0,
|
|
15460
|
+
top: (layout2 == null ? void 0 : layout2.bubbleTop) ?? y
|
|
15461
|
+
},
|
|
15462
|
+
initial: { width: 0, height: 0, opacity: 0 },
|
|
15463
|
+
animate: layout2 ? { width: "auto", height: "auto", opacity: 1 } : { width: 0, height: 0, opacity: 0 },
|
|
15464
|
+
exit: { width: 0, height: 0, opacity: 0 },
|
|
15465
|
+
transition: bubbleTransition,
|
|
15466
|
+
children: /* @__PURE__ */ jsx("div", { ref: contentRef, className: "w-max", children })
|
|
15467
|
+
},
|
|
15468
|
+
"bubble"
|
|
15469
|
+
)
|
|
15470
|
+
] : null }),
|
|
15471
|
+
/* @__PURE__ */ jsx(
|
|
15472
|
+
Dialog,
|
|
15473
|
+
{
|
|
15474
|
+
open: confirmingDiscard,
|
|
15475
|
+
onOpenChange: (nextOpen) => {
|
|
15476
|
+
if (!nextOpen) setConfirmingDiscard(false);
|
|
15477
|
+
},
|
|
15478
|
+
children: /* @__PURE__ */ jsxs(
|
|
15479
|
+
DialogContent,
|
|
15480
|
+
{
|
|
15481
|
+
hideCloseButton: true,
|
|
15482
|
+
initialFocusRef: discardCancelRef,
|
|
15483
|
+
"aria-describedby": void 0,
|
|
15484
|
+
className: "w-[calc(100vw-32px)] max-w-[360px] gap-4 rounded-md p-5",
|
|
15485
|
+
children: [
|
|
15486
|
+
/* @__PURE__ */ jsx(DialogTitle, { className: "text-sm font-normal leading-relaxed", children: DISCARD_MESSAGE }),
|
|
15487
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
15488
|
+
/* @__PURE__ */ jsx(
|
|
15489
|
+
Button,
|
|
15490
|
+
{
|
|
15491
|
+
ref: discardCancelRef,
|
|
15492
|
+
type: "button",
|
|
15493
|
+
variant: "secondary",
|
|
15494
|
+
size: "sm",
|
|
15495
|
+
onClick: () => setConfirmingDiscard(false),
|
|
15496
|
+
children: DISCARD_CANCEL
|
|
15497
|
+
}
|
|
15498
|
+
),
|
|
15499
|
+
/* @__PURE__ */ jsx(Button, { type: "button", size: "sm", onClick: () => onClose(), children: DISCARD_CONFIRM })
|
|
15500
|
+
] })
|
|
15501
|
+
]
|
|
15502
|
+
}
|
|
15503
|
+
)
|
|
15504
|
+
}
|
|
15505
|
+
)
|
|
15506
|
+
] });
|
|
15507
|
+
}
|
|
14652
15508
|
function useProject() {
|
|
14653
15509
|
const auth = useAuthContext();
|
|
14654
15510
|
return {
|
|
@@ -14831,6 +15687,12 @@ function useJiraConnectNudge(projectId, enabled) {
|
|
|
14831
15687
|
function useIssueFormState({ initialDescription } = {}) {
|
|
14832
15688
|
const [title, setTitle] = useState("");
|
|
14833
15689
|
const [description, setDescription] = useState(initialDescription || "");
|
|
15690
|
+
const [mode, setMode] = useState("ai");
|
|
15691
|
+
const [renderedMode, setRenderedMode] = useState("ai");
|
|
15692
|
+
const [intent, setIntent] = useState("");
|
|
15693
|
+
const modeRef = useRef(mode);
|
|
15694
|
+
modeRef.current = mode;
|
|
15695
|
+
const finishModeTransition = useCallback(() => setRenderedMode(modeRef.current), []);
|
|
14834
15696
|
useEffect(() => {
|
|
14835
15697
|
if (initialDescription !== void 0) {
|
|
14836
15698
|
setDescription(initialDescription);
|
|
@@ -14840,7 +15702,13 @@ function useIssueFormState({ initialDescription } = {}) {
|
|
|
14840
15702
|
title,
|
|
14841
15703
|
description,
|
|
14842
15704
|
setTitle,
|
|
14843
|
-
setDescription
|
|
15705
|
+
setDescription,
|
|
15706
|
+
mode,
|
|
15707
|
+
setMode,
|
|
15708
|
+
renderedMode,
|
|
15709
|
+
finishModeTransition,
|
|
15710
|
+
intent,
|
|
15711
|
+
setIntent
|
|
14844
15712
|
};
|
|
14845
15713
|
}
|
|
14846
15714
|
function useDebouncedMutation({
|
|
@@ -14979,6 +15847,12 @@ const SCREENSHOT_EXCLUDE_SELECTORS = [
|
|
|
14979
15847
|
'[data-issue-sticker-capture-ignore="true"]',
|
|
14980
15848
|
"#issue-sticker-host"
|
|
14981
15849
|
];
|
|
15850
|
+
const CAPTURE_START_DELAY_MS = 300;
|
|
15851
|
+
function waitForFormOpen() {
|
|
15852
|
+
return new Promise((resolve) => {
|
|
15853
|
+
setTimeout(resolve, CAPTURE_START_DELAY_MS);
|
|
15854
|
+
});
|
|
15855
|
+
}
|
|
14982
15856
|
function useClickPosition(isCreatingIssueRef, recordedVideoFile) {
|
|
14983
15857
|
const [clickPosition, setClickPosition] = useState(null);
|
|
14984
15858
|
const clickPositionRef = useRef(null);
|
|
@@ -15052,6 +15926,7 @@ function useClickPosition(isCreatingIssueRef, recordedVideoFile) {
|
|
|
15052
15926
|
}, [recordedVideoFile]);
|
|
15053
15927
|
useEffect(() => {
|
|
15054
15928
|
const captureScreenshotsInBackground = async (position2) => {
|
|
15929
|
+
await waitForFormOpen();
|
|
15055
15930
|
const [fullScreenshotDataUrl, elementScreenshotDataUrl] = await pauseNetworkLogCollectionWhile(
|
|
15056
15931
|
() => Promise.all([
|
|
15057
15932
|
captureScreenshot({ excludeSelectors: SCREENSHOT_EXCLUDE_SELECTORS }),
|
|
@@ -15213,6 +16088,14 @@ async function uploadSessionReplay(snapshot) {
|
|
|
15213
16088
|
return null;
|
|
15214
16089
|
}
|
|
15215
16090
|
}
|
|
16091
|
+
function assertSubmittable(data) {
|
|
16092
|
+
var _a, _b2, _c2;
|
|
16093
|
+
const hasIntent = Boolean((_a = data.intent) == null ? void 0 : _a.trim());
|
|
16094
|
+
const hasManual = Boolean((_b2 = data.title) == null ? void 0 : _b2.trim()) && Boolean((_c2 = data.description) == null ? void 0 : _c2.trim());
|
|
16095
|
+
if (!hasIntent && !hasManual) {
|
|
16096
|
+
throw new Error("제목과 설명을 입력하거나 기대한 동작을 적어주세요.");
|
|
16097
|
+
}
|
|
16098
|
+
}
|
|
15216
16099
|
function useIssueSubmission({
|
|
15217
16100
|
position: position2,
|
|
15218
16101
|
onSubmit,
|
|
@@ -15232,13 +16115,8 @@ function useIssueSubmission({
|
|
|
15232
16115
|
const { upload: uploadVideo2 } = useVideoUpload();
|
|
15233
16116
|
const createIssueMutation = useDebouncedMutation({
|
|
15234
16117
|
mutationFn: async (data) => {
|
|
15235
|
-
var _a, _b2;
|
|
15236
|
-
|
|
15237
|
-
throw new Error("제목을 입력해주세요.");
|
|
15238
|
-
}
|
|
15239
|
-
if (!data.description.trim()) {
|
|
15240
|
-
throw new Error("설명을 입력해주세요.");
|
|
15241
|
-
}
|
|
16118
|
+
var _a, _b2, _c2, _d2, _e2, _f2;
|
|
16119
|
+
assertSubmittable(data);
|
|
15242
16120
|
let screenshotUrls;
|
|
15243
16121
|
let videoUrl;
|
|
15244
16122
|
if (data.videoFile) {
|
|
@@ -15272,8 +16150,9 @@ function useIssueSubmission({
|
|
|
15272
16150
|
const currentUrl = getCurrentPageUrl();
|
|
15273
16151
|
const issueData = {
|
|
15274
16152
|
url: currentUrl,
|
|
15275
|
-
title: data.title.trim(),
|
|
15276
|
-
description: data.description.trim(),
|
|
16153
|
+
title: ((_b2 = data.title) == null ? void 0 : _b2.trim()) || void 0,
|
|
16154
|
+
description: ((_c2 = data.description) == null ? void 0 : _c2.trim()) || void 0,
|
|
16155
|
+
intent: ((_d2 = data.intent) == null ? void 0 : _d2.trim()) || void 0,
|
|
15277
16156
|
position: {
|
|
15278
16157
|
x: data.position.x,
|
|
15279
16158
|
y: data.position.y,
|
|
@@ -15294,10 +16173,10 @@ function useIssueSubmission({
|
|
|
15294
16173
|
// 비어 있는 값은 보내지 않는다 — 저장해봐야 값 없음과 같고 요청만 커진다.
|
|
15295
16174
|
custom_field_values: Object.entries(customFieldValues ?? {}).filter(([, value]) => value !== null && value !== void 0 && value !== "").map(([field_definition_id, value]) => ({ field_definition_id, value }))
|
|
15296
16175
|
};
|
|
15297
|
-
if (((
|
|
16176
|
+
if (((_e2 = issueData.custom_field_values) == null ? void 0 : _e2.length) === 0) {
|
|
15298
16177
|
delete issueData.custom_field_values;
|
|
15299
16178
|
}
|
|
15300
|
-
if (
|
|
16179
|
+
if (sessionReplay == null ? void 0 : sessionReplay.canAttach) {
|
|
15301
16180
|
try {
|
|
15302
16181
|
const snapshot = await sessionReplay.takeSnapshot();
|
|
15303
16182
|
if (snapshot) {
|
|
@@ -15336,6 +16215,9 @@ function useIssueSubmission({
|
|
|
15336
16215
|
toast.error(getIntegrationFailureMessage(service));
|
|
15337
16216
|
}
|
|
15338
16217
|
failedServicesRef.current = createdIssue.failed_services ?? [];
|
|
16218
|
+
if (((_f2 = data.intent) == null ? void 0 : _f2.trim()) && createdIssue.generation_status === "skipped") {
|
|
16219
|
+
toast.warning(ISSUE_DRAFT_DISABLED_MESSAGE);
|
|
16220
|
+
}
|
|
15339
16221
|
return createdIssue;
|
|
15340
16222
|
},
|
|
15341
16223
|
onSuccess: (createdIssue) => {
|
|
@@ -15352,11 +16234,12 @@ function useIssueSubmission({
|
|
|
15352
16234
|
}
|
|
15353
16235
|
});
|
|
15354
16236
|
const doSubmit = useCallback(
|
|
15355
|
-
async (title, description) => {
|
|
16237
|
+
async ({ title, description, intent }) => {
|
|
15356
16238
|
failedServicesRef.current = [];
|
|
15357
16239
|
await createIssueMutation.mutateAsync({
|
|
15358
16240
|
title,
|
|
15359
16241
|
description,
|
|
16242
|
+
intent,
|
|
15360
16243
|
position: position2,
|
|
15361
16244
|
jiraFields,
|
|
15362
16245
|
notionFields,
|
|
@@ -15390,12 +16273,6 @@ function useSessionReplayController() {
|
|
|
15390
16273
|
controller.destroy();
|
|
15391
16274
|
};
|
|
15392
16275
|
}, [controller]);
|
|
15393
|
-
const setPreferOn = useCallback(
|
|
15394
|
-
(next) => {
|
|
15395
|
-
controller.setEnabled(next);
|
|
15396
|
-
},
|
|
15397
|
-
[controller]
|
|
15398
|
-
);
|
|
15399
16276
|
const takeSnapshot = useCallback(async () => {
|
|
15400
16277
|
return controller.takeSnapshot();
|
|
15401
16278
|
}, [controller]);
|
|
@@ -15404,8 +16281,6 @@ function useSessionReplayController() {
|
|
|
15404
16281
|
return {
|
|
15405
16282
|
available: snapshot.available,
|
|
15406
16283
|
canAttach: snapshot.canAttach,
|
|
15407
|
-
preferOn: snapshot.enabled,
|
|
15408
|
-
setPreferOn,
|
|
15409
16284
|
takeSnapshot,
|
|
15410
16285
|
markReportStart,
|
|
15411
16286
|
clearReportStart
|
|
@@ -15414,9 +16289,6 @@ function useSessionReplayController() {
|
|
|
15414
16289
|
const DISABLED_CONTROLLER = {
|
|
15415
16290
|
available: false,
|
|
15416
16291
|
canAttach: false,
|
|
15417
|
-
preferOn: false,
|
|
15418
|
-
setPreferOn: () => {
|
|
15419
|
-
},
|
|
15420
16292
|
takeSnapshot: async () => null,
|
|
15421
16293
|
markReportStart: () => {
|
|
15422
16294
|
},
|
|
@@ -15737,12 +16609,7 @@ function IssueFormCustomFields({
|
|
|
15737
16609
|
queryKey: ["customFieldDefinitions", projectId],
|
|
15738
16610
|
queryFn: () => fetchCustomFieldDefinitions(projectId)
|
|
15739
16611
|
});
|
|
15740
|
-
|
|
15741
|
-
useEffect(() => {
|
|
15742
|
-
if (defaultsAppliedRef.current || fields.length === 0) return;
|
|
15743
|
-
defaultsAppliedRef.current = true;
|
|
15744
|
-
onDefaultsResolved(getCustomFieldDefaultValues(fields));
|
|
15745
|
-
}, [fields, onDefaultsResolved]);
|
|
16612
|
+
useCustomFieldDefaults(fields, onDefaultsResolved);
|
|
15746
16613
|
return /* @__PURE__ */ jsx(
|
|
15747
16614
|
CustomFieldsSection,
|
|
15748
16615
|
{
|
|
@@ -15754,12 +16621,57 @@ function IssueFormCustomFields({
|
|
|
15754
16621
|
}
|
|
15755
16622
|
);
|
|
15756
16623
|
}
|
|
16624
|
+
function useCustomFieldDefaults(fields, onDefaultsResolved) {
|
|
16625
|
+
const defaultsAppliedRef = useRef(false);
|
|
16626
|
+
useEffect(() => {
|
|
16627
|
+
if (defaultsAppliedRef.current || fields.length === 0) return;
|
|
16628
|
+
defaultsAppliedRef.current = true;
|
|
16629
|
+
onDefaultsResolved(getCustomFieldDefaultValues(fields));
|
|
16630
|
+
}, [fields, onDefaultsResolved]);
|
|
16631
|
+
}
|
|
16632
|
+
function IssueFormCustomFieldDefaults({
|
|
16633
|
+
projectId,
|
|
16634
|
+
onDefaultsResolved
|
|
16635
|
+
}) {
|
|
16636
|
+
const { data: fields } = useQuery({
|
|
16637
|
+
queryKey: ["customFieldDefinitions", projectId],
|
|
16638
|
+
queryFn: () => fetchCustomFieldDefinitions(projectId)
|
|
16639
|
+
});
|
|
16640
|
+
useCustomFieldDefaults(fields ?? [], onDefaultsResolved);
|
|
16641
|
+
return null;
|
|
16642
|
+
}
|
|
16643
|
+
const useIsomorphicLayoutEffect = typeof window === "undefined" ? React.useEffect : React.useLayoutEffect;
|
|
15757
16644
|
const Textarea = React.forwardRef(
|
|
15758
|
-
({ className, ...props }, ref) => {
|
|
16645
|
+
({ className, autoGrow, ...props }, ref) => {
|
|
16646
|
+
const innerRef = React.useRef(null);
|
|
16647
|
+
React.useImperativeHandle(ref, () => innerRef.current);
|
|
16648
|
+
const grow = React.useCallback(() => {
|
|
16649
|
+
const element2 = innerRef.current;
|
|
16650
|
+
if (!element2) return;
|
|
16651
|
+
const style = getComputedStyle(element2);
|
|
16652
|
+
const borders = (parseFloat(style.borderTopWidth) || 0) + (parseFloat(style.borderBottomWidth) || 0);
|
|
16653
|
+
element2.style.height = "0px";
|
|
16654
|
+
element2.style.height = `${element2.scrollHeight + borders}px`;
|
|
16655
|
+
}, []);
|
|
16656
|
+
useIsomorphicLayoutEffect(() => {
|
|
16657
|
+
if (autoGrow) grow();
|
|
16658
|
+
});
|
|
16659
|
+
useIsomorphicLayoutEffect(() => {
|
|
16660
|
+
const element2 = innerRef.current;
|
|
16661
|
+
if (!autoGrow || !element2 || typeof ResizeObserver === "undefined") return;
|
|
16662
|
+
let lastWidth = element2.clientWidth;
|
|
16663
|
+
const observer2 = new ResizeObserver(() => {
|
|
16664
|
+
if (element2.clientWidth === lastWidth) return;
|
|
16665
|
+
lastWidth = element2.clientWidth;
|
|
16666
|
+
grow();
|
|
16667
|
+
});
|
|
16668
|
+
observer2.observe(element2);
|
|
16669
|
+
return () => observer2.disconnect();
|
|
16670
|
+
}, [autoGrow, grow]);
|
|
15759
16671
|
return /* @__PURE__ */ jsx(
|
|
15760
16672
|
"textarea",
|
|
15761
16673
|
{
|
|
15762
|
-
ref,
|
|
16674
|
+
ref: innerRef,
|
|
15763
16675
|
className: cn$1(
|
|
15764
16676
|
"flex min-h-[108px] w-full rounded-md border border-line-subtle bg-surface-1 px-4 py-3 text-sm text-text-primary",
|
|
15765
16677
|
"transition-[border-color,outline-color,box-shadow,background-color,transform] duration-fast ease-out",
|
|
@@ -15768,6 +16680,7 @@ const Textarea = React.forwardRef(
|
|
|
15768
16680
|
"focus-visible:border-transparent focus-visible:outline-line-focus focus-visible:bg-surface-1",
|
|
15769
16681
|
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
15770
16682
|
"resize-y",
|
|
16683
|
+
autoGrow && "min-h-0 resize-none overflow-hidden",
|
|
15771
16684
|
className
|
|
15772
16685
|
),
|
|
15773
16686
|
...props
|
|
@@ -15803,12 +16716,55 @@ function IssueFormDescriptionField({
|
|
|
15803
16716
|
function IssueFormError({ error }) {
|
|
15804
16717
|
return /* @__PURE__ */ jsx("div", { className: "rounded-[18px] border border-danger/20 bg-danger-subtle px-4 py-3 text-sm text-danger", children: error });
|
|
15805
16718
|
}
|
|
15806
|
-
|
|
16719
|
+
const SWITCH_TO_AI = "AI 작성으로 돌아가기";
|
|
16720
|
+
function IssueFormHeader({ title, onClose, onSwitchToAi }) {
|
|
15807
16721
|
return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
|
|
15808
16722
|
/* @__PURE__ */ jsx("h2", { className: "m-0 text-lg font-semibold text-text-primary", children: title }),
|
|
15809
|
-
/* @__PURE__ */
|
|
16723
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
16724
|
+
onSwitchToAi ? /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 240, skipDelayDuration: 120, disableHoverableContent: true, children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
16725
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
16726
|
+
Button,
|
|
16727
|
+
{
|
|
16728
|
+
type: "button",
|
|
16729
|
+
variant: "ghost",
|
|
16730
|
+
size: "icon",
|
|
16731
|
+
onClick: onSwitchToAi,
|
|
16732
|
+
"aria-label": SWITCH_TO_AI,
|
|
16733
|
+
children: /* @__PURE__ */ jsx(Sparkles, { className: "h-4 w-4" })
|
|
16734
|
+
}
|
|
16735
|
+
) }),
|
|
16736
|
+
/* @__PURE__ */ jsx(TooltipContent, { side: "top", sideOffset: 10, children: SWITCH_TO_AI })
|
|
16737
|
+
] }) }) : null,
|
|
16738
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: onClose, "aria-label": "닫기", children: /* @__PURE__ */ jsx(X$1, { className: "h-4 w-4" }) })
|
|
16739
|
+
] })
|
|
15810
16740
|
] });
|
|
15811
16741
|
}
|
|
16742
|
+
function useDraftCapability() {
|
|
16743
|
+
const { data } = useQuery({
|
|
16744
|
+
queryKey: ["issueDraftCapability"],
|
|
16745
|
+
queryFn: () => apiClient.get("/api/sdk/issues/capabilities/draft")
|
|
16746
|
+
});
|
|
16747
|
+
const capability = data == null ? void 0 : data.draft.canGenerateDraft;
|
|
16748
|
+
return {
|
|
16749
|
+
/** 응답을 실제로 받았을 때만 true. 조회 전·실패·null 응답에서는 false다. */
|
|
16750
|
+
resolved: Boolean(capability),
|
|
16751
|
+
enabled: (capability == null ? void 0 : capability.enabled) ?? true
|
|
16752
|
+
};
|
|
16753
|
+
}
|
|
16754
|
+
function IssueFormDraftCapabilityGate({
|
|
16755
|
+
onResolved
|
|
16756
|
+
}) {
|
|
16757
|
+
const { resolved, enabled } = useDraftCapability();
|
|
16758
|
+
useEffect(() => {
|
|
16759
|
+
if (!resolved) {
|
|
16760
|
+
return;
|
|
16761
|
+
}
|
|
16762
|
+
onResolved({
|
|
16763
|
+
disabledReason: enabled ? null : ISSUE_DRAFT_DISABLED_MESSAGE
|
|
16764
|
+
});
|
|
16765
|
+
}, [resolved, enabled, onResolved]);
|
|
16766
|
+
return null;
|
|
16767
|
+
}
|
|
15812
16768
|
function useJiraFieldSearchConfig(projectId) {
|
|
15813
16769
|
return useMemo(
|
|
15814
16770
|
() => createJiraFieldSearchConfig(
|
|
@@ -15845,13 +16801,7 @@ function IssueFormJiraFields({
|
|
|
15845
16801
|
const { getAuthInfo } = useAuthInfo();
|
|
15846
16802
|
const { fields: fieldDefinitions, exposedFields } = useJiraIntegrationFields(integrationId);
|
|
15847
16803
|
const getSearchConfig = useJiraFieldSearchConfig(getAuthInfo().projectId);
|
|
15848
|
-
|
|
15849
|
-
useEffect(() => {
|
|
15850
|
-
if (!onDefaultsResolved) return;
|
|
15851
|
-
if (appliedForRef.current === integrationId) return;
|
|
15852
|
-
appliedForRef.current = integrationId;
|
|
15853
|
-
onDefaultsResolved(getJiraFieldDefaultValues(exposedFields, fieldDefinitions));
|
|
15854
|
-
}, [integrationId, exposedFields, fieldDefinitions, onDefaultsResolved]);
|
|
16804
|
+
useJiraFieldDefaults(integrationId, exposedFields, fieldDefinitions, onDefaultsResolved);
|
|
15855
16805
|
return /* @__PURE__ */ jsx(
|
|
15856
16806
|
JiraFormFieldsSection,
|
|
15857
16807
|
{
|
|
@@ -15864,6 +16814,36 @@ function IssueFormJiraFields({
|
|
|
15864
16814
|
}
|
|
15865
16815
|
);
|
|
15866
16816
|
}
|
|
16817
|
+
function useJiraFieldDefaults(integrationId, exposedFields, fieldDefinitions, onDefaultsResolved, ready = true) {
|
|
16818
|
+
const appliedForRef = useRef(null);
|
|
16819
|
+
useEffect(() => {
|
|
16820
|
+
if (!onDefaultsResolved || !ready) return;
|
|
16821
|
+
if (appliedForRef.current === integrationId) return;
|
|
16822
|
+
appliedForRef.current = integrationId;
|
|
16823
|
+
onDefaultsResolved(getJiraFieldDefaultValues(exposedFields, fieldDefinitions));
|
|
16824
|
+
}, [integrationId, exposedFields, fieldDefinitions, onDefaultsResolved, ready]);
|
|
16825
|
+
}
|
|
16826
|
+
function IssueFormJiraFieldDefaults({
|
|
16827
|
+
integrationId,
|
|
16828
|
+
onDefaultsResolved
|
|
16829
|
+
}) {
|
|
16830
|
+
const { data } = useQuery({
|
|
16831
|
+
queryKey: ["jiraIntegrationFields", integrationId],
|
|
16832
|
+
queryFn: () => jiraService.loadIntegrationFields(integrationId)
|
|
16833
|
+
});
|
|
16834
|
+
useEffect(() => {
|
|
16835
|
+
if (!data) return;
|
|
16836
|
+
jiraService.updateExposedFields(integrationId, data.exposedFields);
|
|
16837
|
+
}, [data, integrationId]);
|
|
16838
|
+
useJiraFieldDefaults(
|
|
16839
|
+
integrationId,
|
|
16840
|
+
data == null ? void 0 : data.exposedFields,
|
|
16841
|
+
data == null ? void 0 : data.fields,
|
|
16842
|
+
onDefaultsResolved,
|
|
16843
|
+
Boolean(data)
|
|
16844
|
+
);
|
|
16845
|
+
return null;
|
|
16846
|
+
}
|
|
15867
16847
|
function JiraConnectNudge({ onConnect, isConnecting }) {
|
|
15868
16848
|
return /* @__PURE__ */ jsx("div", { className: "rounded-[18px] border border-warning/20 bg-warning-subtle px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
|
|
15869
16849
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
@@ -15940,83 +16920,14 @@ function IssueFormTitleField({
|
|
|
15940
16920
|
)
|
|
15941
16921
|
] });
|
|
15942
16922
|
}
|
|
15943
|
-
function
|
|
15944
|
-
return cn$1(
|
|
15945
|
-
"relative inline-flex h-[22px] w-[38px] shrink-0 items-center rounded-full",
|
|
15946
|
-
"transition-colors duration-fast ease-out",
|
|
15947
|
-
checked ? "bg-brand" : "bg-line"
|
|
15948
|
-
);
|
|
15949
|
-
}
|
|
15950
|
-
function switchThumbClassName(checked) {
|
|
15951
|
-
return cn$1(
|
|
15952
|
-
"pointer-events-none block h-[18px] w-[18px] rounded-full bg-surface-1 shadow-sm",
|
|
15953
|
-
"transition-transform duration-fast ease-out",
|
|
15954
|
-
checked ? "translate-x-[18px]" : "translate-x-[2px]"
|
|
15955
|
-
);
|
|
15956
|
-
}
|
|
15957
|
-
const Switch = React.forwardRef(
|
|
15958
|
-
({ checked, onCheckedChange, disabled = false, id: id2, className, ...aria2 }, ref) => /* @__PURE__ */ jsx(
|
|
15959
|
-
"button",
|
|
15960
|
-
{
|
|
15961
|
-
ref,
|
|
15962
|
-
id: id2,
|
|
15963
|
-
type: "button",
|
|
15964
|
-
role: "switch",
|
|
15965
|
-
"aria-checked": checked,
|
|
15966
|
-
disabled,
|
|
15967
|
-
onClick: () => onCheckedChange(!checked),
|
|
15968
|
-
className: cn$1(
|
|
15969
|
-
switchTrackClassName(checked),
|
|
15970
|
-
"outline-none",
|
|
15971
|
-
"focus-visible:shadow-focus",
|
|
15972
|
-
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
15973
|
-
className
|
|
15974
|
-
),
|
|
15975
|
-
...aria2,
|
|
15976
|
-
children: /* @__PURE__ */ jsx("span", { className: switchThumbClassName(checked) })
|
|
15977
|
-
}
|
|
15978
|
-
)
|
|
15979
|
-
);
|
|
15980
|
-
Switch.displayName = "Switch";
|
|
15981
|
-
function SessionReplayAttachToggle({
|
|
16923
|
+
function SessionReplayLimitNotice({
|
|
15982
16924
|
available,
|
|
15983
|
-
canAttach
|
|
15984
|
-
preferOn,
|
|
15985
|
-
onPreferOnChange
|
|
16925
|
+
canAttach
|
|
15986
16926
|
}) {
|
|
15987
|
-
if (!available) {
|
|
16927
|
+
if (!available || canAttach) {
|
|
15988
16928
|
return null;
|
|
15989
16929
|
}
|
|
15990
|
-
return /* @__PURE__ */
|
|
15991
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
15992
|
-
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5", children: [
|
|
15993
|
-
/* @__PURE__ */ jsx(Label, { htmlFor: "session-replay-attach", children: "세션 리플레이 첨부" }),
|
|
15994
|
-
/* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
15995
|
-
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
15996
|
-
"button",
|
|
15997
|
-
{
|
|
15998
|
-
type: "button",
|
|
15999
|
-
"aria-label": "세션 리플레이 첨부 안내",
|
|
16000
|
-
className: "text-text-tertiary",
|
|
16001
|
-
children: /* @__PURE__ */ jsx(CircleHelp, { className: "h-3.5 w-3.5" })
|
|
16002
|
-
}
|
|
16003
|
-
) }),
|
|
16004
|
-
/* @__PURE__ */ jsx(TooltipContent, { className: "max-w-[240px] whitespace-normal", children: "제출 직전 최근 2분 화면 조작을 함께 기록합니다. 입력값·민감 텍스트는 자동으로 마스킹됩니다." })
|
|
16005
|
-
] }) })
|
|
16006
|
-
] }),
|
|
16007
|
-
/* @__PURE__ */ jsx(
|
|
16008
|
-
Switch,
|
|
16009
|
-
{
|
|
16010
|
-
id: "session-replay-attach",
|
|
16011
|
-
checked: canAttach && preferOn,
|
|
16012
|
-
disabled: !canAttach,
|
|
16013
|
-
onCheckedChange: onPreferOnChange,
|
|
16014
|
-
"aria-label": "세션 리플레이 첨부"
|
|
16015
|
-
}
|
|
16016
|
-
)
|
|
16017
|
-
] }),
|
|
16018
|
-
!canAttach ? /* @__PURE__ */ jsx("p", { className: "text-xs text-warning", children: "이번 달 리플레이 한도를 모두 사용했습니다. 다음 달에 한도가 초기화되거나, 플랜을 업그레이드하면 다시 첨부할 수 있습니다." }) : null
|
|
16019
|
-
] });
|
|
16930
|
+
return /* @__PURE__ */ jsx("p", { className: "text-xs text-warning", children: "이번 달 리플레이 한도를 모두 사용했습니다. 다음 달에 한도가 초기화되거나, 플랜을 업그레이드하면 다시 첨부할 수 있습니다." });
|
|
16020
16931
|
}
|
|
16021
16932
|
function IssueForm({
|
|
16022
16933
|
position: position2,
|
|
@@ -16038,6 +16949,19 @@ function IssueForm({
|
|
|
16038
16949
|
const [jiraFields, setJiraFields] = useState(
|
|
16039
16950
|
{}
|
|
16040
16951
|
);
|
|
16952
|
+
const [draftDisabledReason, setDraftDisabledReason] = useState(null);
|
|
16953
|
+
const intentRef = useRef(formState.intent);
|
|
16954
|
+
intentRef.current = formState.intent;
|
|
16955
|
+
const setFormMode = formState.setMode;
|
|
16956
|
+
const handleDraftCapabilityResolved = useCallback(
|
|
16957
|
+
({ disabledReason }) => {
|
|
16958
|
+
setDraftDisabledReason(disabledReason);
|
|
16959
|
+
if (disabledReason && intentRef.current.trim().length === 0) {
|
|
16960
|
+
setFormMode("manual");
|
|
16961
|
+
}
|
|
16962
|
+
},
|
|
16963
|
+
[setFormMode]
|
|
16964
|
+
);
|
|
16041
16965
|
const [notionFields, setNotionFields] = useState({});
|
|
16042
16966
|
const [customFieldValues, setCustomFieldValues] = useState({});
|
|
16043
16967
|
const { selectedProjectId } = useProject();
|
|
@@ -16059,6 +16983,10 @@ function IssueForm({
|
|
|
16059
16983
|
const issueSubmission = useIssueSubmission({
|
|
16060
16984
|
position: position2,
|
|
16061
16985
|
onSubmit: (hasIntegrationFailure) => {
|
|
16986
|
+
if (formState.mode === "ai") {
|
|
16987
|
+
onSubmit(hasIntegrationFailure);
|
|
16988
|
+
return;
|
|
16989
|
+
}
|
|
16062
16990
|
submitSucceededRef.current = true;
|
|
16063
16991
|
hadIntegrationFailureRef.current = hasIntegrationFailure;
|
|
16064
16992
|
setIsOpen(false);
|
|
@@ -16071,8 +16999,9 @@ function IssueForm({
|
|
|
16071
16999
|
videoFile: position2.videoFile,
|
|
16072
17000
|
sessionReplay
|
|
16073
17001
|
});
|
|
16074
|
-
useDisableBodyScroll();
|
|
17002
|
+
useDisableBodyScroll(formState.mode !== "ai");
|
|
16075
17003
|
useEffect(() => {
|
|
17004
|
+
if (formState.mode === "ai") return;
|
|
16076
17005
|
const handleKeyDown = (e) => {
|
|
16077
17006
|
const path2 = e.composedPath();
|
|
16078
17007
|
const actualTarget = path2.find(
|
|
@@ -16099,22 +17028,86 @@ function IssueForm({
|
|
|
16099
17028
|
};
|
|
16100
17029
|
window.addEventListener("keydown", handleKeyDown, { passive: false });
|
|
16101
17030
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
16102
|
-
}, []);
|
|
17031
|
+
}, [formState.mode]);
|
|
17032
|
+
const submitCurrentMode = async () => {
|
|
17033
|
+
if (formState.mode === "ai") {
|
|
17034
|
+
await issueSubmission.submitIssue({ intent: formState.intent });
|
|
17035
|
+
} else {
|
|
17036
|
+
await issueSubmission.submitIssue({
|
|
17037
|
+
title: formState.title,
|
|
17038
|
+
description: formState.description
|
|
17039
|
+
});
|
|
17040
|
+
}
|
|
17041
|
+
};
|
|
16103
17042
|
const handleSubmit = async (e) => {
|
|
16104
17043
|
e.preventDefault();
|
|
16105
17044
|
e.stopPropagation();
|
|
16106
|
-
await
|
|
17045
|
+
await submitCurrentMode();
|
|
16107
17046
|
};
|
|
16108
|
-
const handleClose = () =>
|
|
17047
|
+
const handleClose = () => {
|
|
17048
|
+
if (formState.mode === "ai") {
|
|
17049
|
+
onCancel();
|
|
17050
|
+
return;
|
|
17051
|
+
}
|
|
17052
|
+
setIsOpen(false);
|
|
17053
|
+
};
|
|
17054
|
+
if (formState.renderedMode === "ai") {
|
|
17055
|
+
return createPortal(
|
|
17056
|
+
/* @__PURE__ */ jsxs(
|
|
17057
|
+
IssueIntentBubbleAnchor,
|
|
17058
|
+
{
|
|
17059
|
+
x: position2.x,
|
|
17060
|
+
y: position2.y,
|
|
17061
|
+
onClose: handleClose,
|
|
17062
|
+
dirty: formState.intent.trim().length > 0,
|
|
17063
|
+
open: formState.mode === "ai",
|
|
17064
|
+
onExitComplete: formState.finishModeTransition,
|
|
17065
|
+
children: [
|
|
17066
|
+
showJiraFields ? /* @__PURE__ */ jsx(QueryBoundary, { loadingFallback: null, onError: () => null, children: /* @__PURE__ */ jsx(
|
|
17067
|
+
IssueFormJiraFieldDefaults,
|
|
17068
|
+
{
|
|
17069
|
+
integrationId: jiraIntegrationId,
|
|
17070
|
+
onDefaultsResolved: (defaults) => setJiraFields((current) => ({ ...defaults, ...current }))
|
|
17071
|
+
}
|
|
17072
|
+
) }) : null,
|
|
17073
|
+
showCustomFields ? /* @__PURE__ */ jsx(QueryBoundary, { loadingFallback: null, onError: () => null, children: /* @__PURE__ */ jsx(
|
|
17074
|
+
IssueFormCustomFieldDefaults,
|
|
17075
|
+
{
|
|
17076
|
+
projectId: selectedProjectId,
|
|
17077
|
+
onDefaultsResolved: (defaults) => setCustomFieldValues((current) => ({ ...defaults, ...current }))
|
|
17078
|
+
}
|
|
17079
|
+
) }) : null,
|
|
17080
|
+
/* @__PURE__ */ jsx(QueryBoundary, { loadingFallback: null, onError: () => null, children: /* @__PURE__ */ jsx(IssueFormDraftCapabilityGate, { onResolved: handleDraftCapabilityResolved }) }),
|
|
17081
|
+
/* @__PURE__ */ jsx(
|
|
17082
|
+
IssueIntentBubble,
|
|
17083
|
+
{
|
|
17084
|
+
value: formState.intent,
|
|
17085
|
+
onChange: formState.setIntent,
|
|
17086
|
+
onSubmit: () => void submitCurrentMode(),
|
|
17087
|
+
onSwitchToManual: () => formState.setMode("manual"),
|
|
17088
|
+
submitting: issueSubmission.isSubmitting,
|
|
17089
|
+
error: issueSubmission.error
|
|
17090
|
+
}
|
|
17091
|
+
)
|
|
17092
|
+
]
|
|
17093
|
+
}
|
|
17094
|
+
),
|
|
17095
|
+
getPortalContainer()
|
|
17096
|
+
);
|
|
17097
|
+
}
|
|
16109
17098
|
return createPortal(
|
|
16110
17099
|
/* @__PURE__ */ jsx(
|
|
16111
17100
|
OverlayShell,
|
|
16112
17101
|
{
|
|
16113
|
-
open: isOpen,
|
|
17102
|
+
open: isOpen && formState.mode === "manual",
|
|
16114
17103
|
shellClassName: "h-auto max-h-[min(80vh,640px)] max-w-[480px]",
|
|
16115
17104
|
closeOnBackdropClick: false,
|
|
16116
17105
|
onClose: handleClose,
|
|
16117
17106
|
onExitComplete: () => {
|
|
17107
|
+
if (formState.mode === "ai") {
|
|
17108
|
+
formState.finishModeTransition();
|
|
17109
|
+
return;
|
|
17110
|
+
}
|
|
16118
17111
|
if (submitSucceededRef.current) {
|
|
16119
17112
|
onSubmit(hadIntegrationFailureRef.current);
|
|
16120
17113
|
} else {
|
|
@@ -16127,19 +17120,24 @@ function IssueForm({
|
|
|
16127
17120
|
className: `${ISSUE_STICKER_REPORT_FORM_CLASS} flex min-h-0 flex-1 flex-col`,
|
|
16128
17121
|
onSubmit: handleSubmit,
|
|
16129
17122
|
children: [
|
|
16130
|
-
/* @__PURE__ */ jsx("div", { className: "border-b border-line-subtle px-4 py-3", children: /* @__PURE__ */ jsx(
|
|
17123
|
+
/* @__PURE__ */ jsx("div", { className: "border-b border-line-subtle px-4 py-3", children: /* @__PURE__ */ jsx(
|
|
17124
|
+
IssueFormHeader,
|
|
17125
|
+
{
|
|
17126
|
+
title: "이슈 생성",
|
|
17127
|
+
onClose: handleClose,
|
|
17128
|
+
onSwitchToAi: draftDisabledReason ? void 0 : () => formState.setMode("ai")
|
|
17129
|
+
}
|
|
17130
|
+
) }),
|
|
16131
17131
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-h-0 space-y-3 overflow-y-auto px-4 py-3", children: [
|
|
17132
|
+
issueSubmission.error && /* @__PURE__ */ jsx(IssueFormError, { error: issueSubmission.error }),
|
|
16132
17133
|
hasJiraIntegration && jiraConnect.needsConnect ? /* @__PURE__ */ jsx(JiraConnectNudge, { onConnect: () => void jiraConnect.connect() }) : null,
|
|
16133
|
-
/* @__PURE__ */ jsx(
|
|
16134
|
-
|
|
17134
|
+
isMember ? /* @__PURE__ */ jsx(
|
|
17135
|
+
SessionReplayLimitNotice,
|
|
16135
17136
|
{
|
|
16136
17137
|
available: sessionReplay.available,
|
|
16137
|
-
canAttach: sessionReplay.canAttach
|
|
16138
|
-
preferOn: sessionReplay.preferOn,
|
|
16139
|
-
onPreferOnChange: sessionReplay.setPreferOn
|
|
17138
|
+
canAttach: sessionReplay.canAttach
|
|
16140
17139
|
}
|
|
16141
|
-
),
|
|
16142
|
-
issueSubmission.error && /* @__PURE__ */ jsx(IssueFormError, { error: issueSubmission.error }),
|
|
17140
|
+
) : null,
|
|
16143
17141
|
/* @__PURE__ */ jsx(
|
|
16144
17142
|
IssueFormTitleField,
|
|
16145
17143
|
{
|
|
@@ -16156,6 +17154,7 @@ function IssueForm({
|
|
|
16156
17154
|
disabled: issueSubmission.isSubmitting
|
|
16157
17155
|
}
|
|
16158
17156
|
),
|
|
17157
|
+
draftDisabledReason ? /* @__PURE__ */ jsx("p", { className: "text-xs text-text-secondary", children: draftDisabledReason }) : null,
|
|
16159
17158
|
showIntegrationSkeleton ? /* @__PURE__ */ jsx(IntegrationFieldsSkeleton, {}) : null,
|
|
16160
17159
|
showJiraFields ? /* @__PURE__ */ jsx(
|
|
16161
17160
|
QueryBoundary,
|
|
@@ -16324,7 +17323,7 @@ var Collapsible = React.forwardRef(
|
|
|
16324
17323
|
children: /* @__PURE__ */ jsx(
|
|
16325
17324
|
Primitive.div,
|
|
16326
17325
|
{
|
|
16327
|
-
"data-state": getState$
|
|
17326
|
+
"data-state": getState$1(open),
|
|
16328
17327
|
"data-disabled": disabled ? "" : void 0,
|
|
16329
17328
|
...collapsibleProps,
|
|
16330
17329
|
ref: forwardedRef
|
|
@@ -16335,18 +17334,18 @@ var Collapsible = React.forwardRef(
|
|
|
16335
17334
|
}
|
|
16336
17335
|
);
|
|
16337
17336
|
Collapsible.displayName = COLLAPSIBLE_NAME;
|
|
16338
|
-
var TRIGGER_NAME$
|
|
17337
|
+
var TRIGGER_NAME$2 = "CollapsibleTrigger";
|
|
16339
17338
|
var CollapsibleTrigger = React.forwardRef(
|
|
16340
17339
|
(props, forwardedRef) => {
|
|
16341
17340
|
const { __scopeCollapsible, ...triggerProps } = props;
|
|
16342
|
-
const context = useCollapsibleContext(TRIGGER_NAME$
|
|
17341
|
+
const context = useCollapsibleContext(TRIGGER_NAME$2, __scopeCollapsible);
|
|
16343
17342
|
return /* @__PURE__ */ jsx(
|
|
16344
17343
|
Primitive.button,
|
|
16345
17344
|
{
|
|
16346
17345
|
type: "button",
|
|
16347
17346
|
"aria-controls": context.open ? context.contentId : void 0,
|
|
16348
17347
|
"aria-expanded": context.open || false,
|
|
16349
|
-
"data-state": getState$
|
|
17348
|
+
"data-state": getState$1(context.open),
|
|
16350
17349
|
"data-disabled": context.disabled ? "" : void 0,
|
|
16351
17350
|
disabled: context.disabled,
|
|
16352
17351
|
...triggerProps,
|
|
@@ -16356,19 +17355,19 @@ var CollapsibleTrigger = React.forwardRef(
|
|
|
16356
17355
|
);
|
|
16357
17356
|
}
|
|
16358
17357
|
);
|
|
16359
|
-
CollapsibleTrigger.displayName = TRIGGER_NAME$
|
|
16360
|
-
var CONTENT_NAME$
|
|
17358
|
+
CollapsibleTrigger.displayName = TRIGGER_NAME$2;
|
|
17359
|
+
var CONTENT_NAME$2 = "CollapsibleContent";
|
|
16361
17360
|
var CollapsibleContent = React.forwardRef(
|
|
16362
17361
|
(props, forwardedRef) => {
|
|
16363
17362
|
const { forceMount, ...contentProps } = props;
|
|
16364
|
-
const context = useCollapsibleContext(CONTENT_NAME$
|
|
17363
|
+
const context = useCollapsibleContext(CONTENT_NAME$2, props.__scopeCollapsible);
|
|
16365
17364
|
return /* @__PURE__ */ jsx(Presence, { present: forceMount || context.open, children: ({ present }) => /* @__PURE__ */ jsx(CollapsibleContentImpl, { ...contentProps, ref: forwardedRef, present }) });
|
|
16366
17365
|
}
|
|
16367
17366
|
);
|
|
16368
|
-
CollapsibleContent.displayName = CONTENT_NAME$
|
|
17367
|
+
CollapsibleContent.displayName = CONTENT_NAME$2;
|
|
16369
17368
|
var CollapsibleContentImpl = React.forwardRef((props, forwardedRef) => {
|
|
16370
17369
|
const { __scopeCollapsible, present, children, ...contentProps } = props;
|
|
16371
|
-
const context = useCollapsibleContext(CONTENT_NAME$
|
|
17370
|
+
const context = useCollapsibleContext(CONTENT_NAME$2, __scopeCollapsible);
|
|
16372
17371
|
const [isPresent, setIsPresent] = React.useState(present);
|
|
16373
17372
|
const ref = React.useRef(null);
|
|
16374
17373
|
const composedRefs = useComposedRefs$1(forwardedRef, ref);
|
|
@@ -16405,7 +17404,7 @@ var CollapsibleContentImpl = React.forwardRef((props, forwardedRef) => {
|
|
|
16405
17404
|
return /* @__PURE__ */ jsx(
|
|
16406
17405
|
Primitive.div,
|
|
16407
17406
|
{
|
|
16408
|
-
"data-state": getState$
|
|
17407
|
+
"data-state": getState$1(context.open),
|
|
16409
17408
|
"data-disabled": context.disabled ? "" : void 0,
|
|
16410
17409
|
id: context.contentId,
|
|
16411
17410
|
hidden: !isOpen,
|
|
@@ -16420,7 +17419,7 @@ var CollapsibleContentImpl = React.forwardRef((props, forwardedRef) => {
|
|
|
16420
17419
|
}
|
|
16421
17420
|
);
|
|
16422
17421
|
});
|
|
16423
|
-
function getState$
|
|
17422
|
+
function getState$1(open) {
|
|
16424
17423
|
return open ? "open" : "closed";
|
|
16425
17424
|
}
|
|
16426
17425
|
var Root$1 = Collapsible;
|
|
@@ -16626,7 +17625,7 @@ var AccordionItem$1 = React.forwardRef(
|
|
|
16626
17625
|
Root$1,
|
|
16627
17626
|
{
|
|
16628
17627
|
"data-orientation": accordionContext.orientation,
|
|
16629
|
-
"data-state": getState
|
|
17628
|
+
"data-state": getState(open),
|
|
16630
17629
|
...collapsibleScope,
|
|
16631
17630
|
...accordionItemProps,
|
|
16632
17631
|
ref: forwardedRef,
|
|
@@ -16656,7 +17655,7 @@ var AccordionHeader = React.forwardRef(
|
|
|
16656
17655
|
Primitive.h3,
|
|
16657
17656
|
{
|
|
16658
17657
|
"data-orientation": accordionContext.orientation,
|
|
16659
|
-
"data-state": getState
|
|
17658
|
+
"data-state": getState(itemContext.open),
|
|
16660
17659
|
"data-disabled": itemContext.disabled ? "" : void 0,
|
|
16661
17660
|
...headerProps,
|
|
16662
17661
|
ref: forwardedRef
|
|
@@ -16665,13 +17664,13 @@ var AccordionHeader = React.forwardRef(
|
|
|
16665
17664
|
}
|
|
16666
17665
|
);
|
|
16667
17666
|
AccordionHeader.displayName = HEADER_NAME;
|
|
16668
|
-
var TRIGGER_NAME$
|
|
17667
|
+
var TRIGGER_NAME$1 = "AccordionTrigger";
|
|
16669
17668
|
var AccordionTrigger$1 = React.forwardRef(
|
|
16670
17669
|
(props, forwardedRef) => {
|
|
16671
17670
|
const { __scopeAccordion, ...triggerProps } = props;
|
|
16672
17671
|
const accordionContext = useAccordionContext(ACCORDION_NAME, __scopeAccordion);
|
|
16673
|
-
const itemContext = useAccordionItemContext(TRIGGER_NAME$
|
|
16674
|
-
const collapsibleContext = useAccordionCollapsibleContext(TRIGGER_NAME$
|
|
17672
|
+
const itemContext = useAccordionItemContext(TRIGGER_NAME$1, __scopeAccordion);
|
|
17673
|
+
const collapsibleContext = useAccordionCollapsibleContext(TRIGGER_NAME$1, __scopeAccordion);
|
|
16675
17674
|
const collapsibleScope = useCollapsibleScope(__scopeAccordion);
|
|
16676
17675
|
return /* @__PURE__ */ jsx(Collection$1.ItemSlot, { scope: __scopeAccordion, children: /* @__PURE__ */ jsx(
|
|
16677
17676
|
Trigger$1,
|
|
@@ -16686,13 +17685,13 @@ var AccordionTrigger$1 = React.forwardRef(
|
|
|
16686
17685
|
) });
|
|
16687
17686
|
}
|
|
16688
17687
|
);
|
|
16689
|
-
AccordionTrigger$1.displayName = TRIGGER_NAME$
|
|
16690
|
-
var CONTENT_NAME$
|
|
17688
|
+
AccordionTrigger$1.displayName = TRIGGER_NAME$1;
|
|
17689
|
+
var CONTENT_NAME$1 = "AccordionContent";
|
|
16691
17690
|
var AccordionContent$1 = React.forwardRef(
|
|
16692
17691
|
(props, forwardedRef) => {
|
|
16693
17692
|
const { __scopeAccordion, ...contentProps } = props;
|
|
16694
17693
|
const accordionContext = useAccordionContext(ACCORDION_NAME, __scopeAccordion);
|
|
16695
|
-
const itemContext = useAccordionItemContext(CONTENT_NAME$
|
|
17694
|
+
const itemContext = useAccordionItemContext(CONTENT_NAME$1, __scopeAccordion);
|
|
16696
17695
|
const collapsibleScope = useCollapsibleScope(__scopeAccordion);
|
|
16697
17696
|
return /* @__PURE__ */ jsx(
|
|
16698
17697
|
Content$1,
|
|
@@ -16712,8 +17711,8 @@ var AccordionContent$1 = React.forwardRef(
|
|
|
16712
17711
|
);
|
|
16713
17712
|
}
|
|
16714
17713
|
);
|
|
16715
|
-
AccordionContent$1.displayName = CONTENT_NAME$
|
|
16716
|
-
function getState
|
|
17714
|
+
AccordionContent$1.displayName = CONTENT_NAME$1;
|
|
17715
|
+
function getState(open) {
|
|
16717
17716
|
return open ? "open" : "closed";
|
|
16718
17717
|
}
|
|
16719
17718
|
var Root2$1 = Accordion$1;
|
|
@@ -17458,11 +18457,11 @@ var TabsList$1 = React.forwardRef(
|
|
|
17458
18457
|
}
|
|
17459
18458
|
);
|
|
17460
18459
|
TabsList$1.displayName = TAB_LIST_NAME;
|
|
17461
|
-
var TRIGGER_NAME
|
|
18460
|
+
var TRIGGER_NAME = "TabsTrigger";
|
|
17462
18461
|
var TabsTrigger$1 = React.forwardRef(
|
|
17463
18462
|
(props, forwardedRef) => {
|
|
17464
18463
|
const { __scopeTabs, value, disabled = false, ...triggerProps } = props;
|
|
17465
|
-
const context = useTabsContext(TRIGGER_NAME
|
|
18464
|
+
const context = useTabsContext(TRIGGER_NAME, __scopeTabs);
|
|
17466
18465
|
const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeTabs);
|
|
17467
18466
|
const triggerId = makeTriggerId(context.baseId, value);
|
|
17468
18467
|
const contentId = makeContentId(context.baseId, value);
|
|
@@ -17509,12 +18508,12 @@ var TabsTrigger$1 = React.forwardRef(
|
|
|
17509
18508
|
);
|
|
17510
18509
|
}
|
|
17511
18510
|
);
|
|
17512
|
-
TabsTrigger$1.displayName = TRIGGER_NAME
|
|
17513
|
-
var CONTENT_NAME
|
|
18511
|
+
TabsTrigger$1.displayName = TRIGGER_NAME;
|
|
18512
|
+
var CONTENT_NAME = "TabsContent";
|
|
17514
18513
|
var TabsContent$1 = React.forwardRef(
|
|
17515
18514
|
(props, forwardedRef) => {
|
|
17516
18515
|
const { __scopeTabs, value, forceMount, children, ...contentProps } = props;
|
|
17517
|
-
const context = useTabsContext(CONTENT_NAME
|
|
18516
|
+
const context = useTabsContext(CONTENT_NAME, __scopeTabs);
|
|
17518
18517
|
const triggerId = makeTriggerId(context.baseId, value);
|
|
17519
18518
|
const contentId = makeContentId(context.baseId, value);
|
|
17520
18519
|
const isSelected = value === context.value;
|
|
@@ -17544,7 +18543,7 @@ var TabsContent$1 = React.forwardRef(
|
|
|
17544
18543
|
) });
|
|
17545
18544
|
}
|
|
17546
18545
|
);
|
|
17547
|
-
TabsContent$1.displayName = CONTENT_NAME
|
|
18546
|
+
TabsContent$1.displayName = CONTENT_NAME;
|
|
17548
18547
|
function makeTriggerId(baseId, value) {
|
|
17549
18548
|
return `${baseId}-trigger-${value}`;
|
|
17550
18549
|
}
|
|
@@ -32944,343 +33943,6 @@ function IssueDescription({
|
|
|
32944
33943
|
error ? /* @__PURE__ */ jsx("p", { className: "text-xs text-danger", children: error }) : null
|
|
32945
33944
|
] });
|
|
32946
33945
|
}
|
|
32947
|
-
var DIALOG_NAME = "Dialog";
|
|
32948
|
-
var [createDialogContext] = createContextScope(DIALOG_NAME);
|
|
32949
|
-
var [DialogProvider, useDialogContext] = createDialogContext(DIALOG_NAME);
|
|
32950
|
-
var Dialog$1 = (props) => {
|
|
32951
|
-
const {
|
|
32952
|
-
__scopeDialog,
|
|
32953
|
-
children,
|
|
32954
|
-
open: openProp,
|
|
32955
|
-
defaultOpen,
|
|
32956
|
-
onOpenChange,
|
|
32957
|
-
modal = true
|
|
32958
|
-
} = props;
|
|
32959
|
-
const triggerRef = React.useRef(null);
|
|
32960
|
-
const contentRef = React.useRef(null);
|
|
32961
|
-
const [open, setOpen] = useControllableState({
|
|
32962
|
-
prop: openProp,
|
|
32963
|
-
defaultProp: defaultOpen ?? false,
|
|
32964
|
-
onChange: onOpenChange,
|
|
32965
|
-
caller: DIALOG_NAME
|
|
32966
|
-
});
|
|
32967
|
-
return /* @__PURE__ */ jsx(
|
|
32968
|
-
DialogProvider,
|
|
32969
|
-
{
|
|
32970
|
-
scope: __scopeDialog,
|
|
32971
|
-
triggerRef,
|
|
32972
|
-
contentRef,
|
|
32973
|
-
contentId: useId$1(),
|
|
32974
|
-
titleId: useId$1(),
|
|
32975
|
-
descriptionId: useId$1(),
|
|
32976
|
-
open,
|
|
32977
|
-
onOpenChange: setOpen,
|
|
32978
|
-
onOpenToggle: React.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen]),
|
|
32979
|
-
modal,
|
|
32980
|
-
children
|
|
32981
|
-
}
|
|
32982
|
-
);
|
|
32983
|
-
};
|
|
32984
|
-
Dialog$1.displayName = DIALOG_NAME;
|
|
32985
|
-
var TRIGGER_NAME = "DialogTrigger";
|
|
32986
|
-
var DialogTrigger = React.forwardRef(
|
|
32987
|
-
(props, forwardedRef) => {
|
|
32988
|
-
const { __scopeDialog, ...triggerProps } = props;
|
|
32989
|
-
const context = useDialogContext(TRIGGER_NAME, __scopeDialog);
|
|
32990
|
-
const composedTriggerRef = useComposedRefs$1(forwardedRef, context.triggerRef);
|
|
32991
|
-
return /* @__PURE__ */ jsx(
|
|
32992
|
-
Primitive.button,
|
|
32993
|
-
{
|
|
32994
|
-
type: "button",
|
|
32995
|
-
"aria-haspopup": "dialog",
|
|
32996
|
-
"aria-expanded": context.open,
|
|
32997
|
-
"aria-controls": context.open ? context.contentId : void 0,
|
|
32998
|
-
"data-state": getState(context.open),
|
|
32999
|
-
...triggerProps,
|
|
33000
|
-
ref: composedTriggerRef,
|
|
33001
|
-
onClick: composeEventHandlers(props.onClick, context.onOpenToggle)
|
|
33002
|
-
}
|
|
33003
|
-
);
|
|
33004
|
-
}
|
|
33005
|
-
);
|
|
33006
|
-
DialogTrigger.displayName = TRIGGER_NAME;
|
|
33007
|
-
var PORTAL_NAME = "DialogPortal";
|
|
33008
|
-
var [PortalProvider, usePortalContext] = createDialogContext(PORTAL_NAME, {
|
|
33009
|
-
forceMount: void 0
|
|
33010
|
-
});
|
|
33011
|
-
var DialogPortal$1 = (props) => {
|
|
33012
|
-
const { __scopeDialog, forceMount, children, container } = props;
|
|
33013
|
-
const context = useDialogContext(PORTAL_NAME, __scopeDialog);
|
|
33014
|
-
return /* @__PURE__ */ jsx(PortalProvider, { scope: __scopeDialog, forceMount, children: React.Children.map(children, (child) => /* @__PURE__ */ jsx(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsx(Portal$1, { asChild: true, container, children: child }) })) });
|
|
33015
|
-
};
|
|
33016
|
-
DialogPortal$1.displayName = PORTAL_NAME;
|
|
33017
|
-
var OVERLAY_NAME = "DialogOverlay";
|
|
33018
|
-
var DialogOverlay$1 = React.forwardRef(
|
|
33019
|
-
(props, forwardedRef) => {
|
|
33020
|
-
const portalContext = usePortalContext(OVERLAY_NAME, props.__scopeDialog);
|
|
33021
|
-
const { forceMount = portalContext.forceMount, ...overlayProps } = props;
|
|
33022
|
-
const context = useDialogContext(OVERLAY_NAME, props.__scopeDialog);
|
|
33023
|
-
return context.modal ? /* @__PURE__ */ jsx(Presence, { present: forceMount || context.open, children: /* @__PURE__ */ jsx(DialogOverlayImpl, { ...overlayProps, ref: forwardedRef }) }) : null;
|
|
33024
|
-
}
|
|
33025
|
-
);
|
|
33026
|
-
DialogOverlay$1.displayName = OVERLAY_NAME;
|
|
33027
|
-
var Slot = createSlot("DialogOverlay.RemoveScroll");
|
|
33028
|
-
var DialogOverlayImpl = React.forwardRef(
|
|
33029
|
-
(props, forwardedRef) => {
|
|
33030
|
-
const { __scopeDialog, ...overlayProps } = props;
|
|
33031
|
-
const context = useDialogContext(OVERLAY_NAME, __scopeDialog);
|
|
33032
|
-
const registerDismissableSurface = useDismissableLayerSurface();
|
|
33033
|
-
const composedRefs = useComposedRefs$1(forwardedRef, registerDismissableSurface);
|
|
33034
|
-
return (
|
|
33035
|
-
// Make sure `Content` is scrollable even when it doesn't live inside `RemoveScroll`
|
|
33036
|
-
// ie. when `Overlay` and `Content` are siblings
|
|
33037
|
-
/* @__PURE__ */ jsx(ReactRemoveScroll, { as: Slot, allowPinchZoom: true, shards: [context.contentRef], children: /* @__PURE__ */ jsx(
|
|
33038
|
-
Primitive.div,
|
|
33039
|
-
{
|
|
33040
|
-
"data-state": getState(context.open),
|
|
33041
|
-
...overlayProps,
|
|
33042
|
-
ref: composedRefs,
|
|
33043
|
-
style: { pointerEvents: "auto", ...overlayProps.style }
|
|
33044
|
-
}
|
|
33045
|
-
) })
|
|
33046
|
-
);
|
|
33047
|
-
}
|
|
33048
|
-
);
|
|
33049
|
-
var CONTENT_NAME = "DialogContent";
|
|
33050
|
-
var DialogContent$1 = React.forwardRef(
|
|
33051
|
-
(props, forwardedRef) => {
|
|
33052
|
-
const portalContext = usePortalContext(CONTENT_NAME, props.__scopeDialog);
|
|
33053
|
-
const { forceMount = portalContext.forceMount, ...contentProps } = props;
|
|
33054
|
-
const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);
|
|
33055
|
-
return /* @__PURE__ */ jsx(Presence, { present: forceMount || context.open, children: context.modal ? /* @__PURE__ */ jsx(DialogContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ jsx(DialogContentNonModal, { ...contentProps, ref: forwardedRef }) });
|
|
33056
|
-
}
|
|
33057
|
-
);
|
|
33058
|
-
DialogContent$1.displayName = CONTENT_NAME;
|
|
33059
|
-
var DialogContentModal = React.forwardRef(
|
|
33060
|
-
(props, forwardedRef) => {
|
|
33061
|
-
const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);
|
|
33062
|
-
const contentRef = React.useRef(null);
|
|
33063
|
-
const composedRefs = useComposedRefs$1(forwardedRef, context.contentRef, contentRef);
|
|
33064
|
-
React.useEffect(() => {
|
|
33065
|
-
const content2 = contentRef.current;
|
|
33066
|
-
if (content2) return hideOthers(content2);
|
|
33067
|
-
}, []);
|
|
33068
|
-
return /* @__PURE__ */ jsx(
|
|
33069
|
-
DialogContentImpl,
|
|
33070
|
-
{
|
|
33071
|
-
...props,
|
|
33072
|
-
ref: composedRefs,
|
|
33073
|
-
trapFocus: context.open,
|
|
33074
|
-
disableOutsidePointerEvents: context.open,
|
|
33075
|
-
onCloseAutoFocus: composeEventHandlers(props.onCloseAutoFocus, (event) => {
|
|
33076
|
-
var _a;
|
|
33077
|
-
event.preventDefault();
|
|
33078
|
-
(_a = context.triggerRef.current) == null ? void 0 : _a.focus();
|
|
33079
|
-
}),
|
|
33080
|
-
onPointerDownOutside: composeEventHandlers(props.onPointerDownOutside, (event) => {
|
|
33081
|
-
const originalEvent = event.detail.originalEvent;
|
|
33082
|
-
const ctrlLeftClick = originalEvent.button === 0 && originalEvent.ctrlKey === true;
|
|
33083
|
-
const isRightClick = originalEvent.button === 2 || ctrlLeftClick;
|
|
33084
|
-
if (isRightClick) event.preventDefault();
|
|
33085
|
-
}),
|
|
33086
|
-
onFocusOutside: composeEventHandlers(
|
|
33087
|
-
props.onFocusOutside,
|
|
33088
|
-
(event) => event.preventDefault()
|
|
33089
|
-
)
|
|
33090
|
-
}
|
|
33091
|
-
);
|
|
33092
|
-
}
|
|
33093
|
-
);
|
|
33094
|
-
var DialogContentNonModal = React.forwardRef(
|
|
33095
|
-
(props, forwardedRef) => {
|
|
33096
|
-
const context = useDialogContext(CONTENT_NAME, props.__scopeDialog);
|
|
33097
|
-
const hasInteractedOutsideRef = React.useRef(false);
|
|
33098
|
-
const hasPointerDownOutsideRef = React.useRef(false);
|
|
33099
|
-
return /* @__PURE__ */ jsx(
|
|
33100
|
-
DialogContentImpl,
|
|
33101
|
-
{
|
|
33102
|
-
...props,
|
|
33103
|
-
ref: forwardedRef,
|
|
33104
|
-
trapFocus: false,
|
|
33105
|
-
disableOutsidePointerEvents: false,
|
|
33106
|
-
onCloseAutoFocus: (event) => {
|
|
33107
|
-
var _a, _b2;
|
|
33108
|
-
(_a = props.onCloseAutoFocus) == null ? void 0 : _a.call(props, event);
|
|
33109
|
-
if (!event.defaultPrevented) {
|
|
33110
|
-
if (!hasInteractedOutsideRef.current) (_b2 = context.triggerRef.current) == null ? void 0 : _b2.focus();
|
|
33111
|
-
event.preventDefault();
|
|
33112
|
-
}
|
|
33113
|
-
hasInteractedOutsideRef.current = false;
|
|
33114
|
-
hasPointerDownOutsideRef.current = false;
|
|
33115
|
-
},
|
|
33116
|
-
onInteractOutside: (event) => {
|
|
33117
|
-
var _a, _b2;
|
|
33118
|
-
(_a = props.onInteractOutside) == null ? void 0 : _a.call(props, event);
|
|
33119
|
-
if (!event.defaultPrevented) {
|
|
33120
|
-
hasInteractedOutsideRef.current = true;
|
|
33121
|
-
if (event.detail.originalEvent.type === "pointerdown") {
|
|
33122
|
-
hasPointerDownOutsideRef.current = true;
|
|
33123
|
-
}
|
|
33124
|
-
}
|
|
33125
|
-
const target = event.target;
|
|
33126
|
-
const targetIsTrigger = (_b2 = context.triggerRef.current) == null ? void 0 : _b2.contains(target);
|
|
33127
|
-
if (targetIsTrigger) event.preventDefault();
|
|
33128
|
-
if (event.detail.originalEvent.type === "focusin" && hasPointerDownOutsideRef.current) {
|
|
33129
|
-
event.preventDefault();
|
|
33130
|
-
}
|
|
33131
|
-
}
|
|
33132
|
-
}
|
|
33133
|
-
);
|
|
33134
|
-
}
|
|
33135
|
-
);
|
|
33136
|
-
var DialogContentImpl = React.forwardRef(
|
|
33137
|
-
(props, forwardedRef) => {
|
|
33138
|
-
const { __scopeDialog, trapFocus, onOpenAutoFocus, onCloseAutoFocus, ...contentProps } = props;
|
|
33139
|
-
const context = useDialogContext(CONTENT_NAME, __scopeDialog);
|
|
33140
|
-
useFocusGuards();
|
|
33141
|
-
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
|
|
33142
|
-
FocusScope,
|
|
33143
|
-
{
|
|
33144
|
-
asChild: true,
|
|
33145
|
-
loop: true,
|
|
33146
|
-
trapped: trapFocus,
|
|
33147
|
-
onMountAutoFocus: onOpenAutoFocus,
|
|
33148
|
-
onUnmountAutoFocus: onCloseAutoFocus,
|
|
33149
|
-
children: /* @__PURE__ */ jsx(
|
|
33150
|
-
DismissableLayer,
|
|
33151
|
-
{
|
|
33152
|
-
role: "dialog",
|
|
33153
|
-
id: context.contentId,
|
|
33154
|
-
"aria-describedby": context.descriptionId,
|
|
33155
|
-
"aria-labelledby": context.titleId,
|
|
33156
|
-
"data-state": getState(context.open),
|
|
33157
|
-
...contentProps,
|
|
33158
|
-
ref: forwardedRef,
|
|
33159
|
-
deferPointerDownOutside: true,
|
|
33160
|
-
onDismiss: () => context.onOpenChange(false)
|
|
33161
|
-
}
|
|
33162
|
-
)
|
|
33163
|
-
}
|
|
33164
|
-
) });
|
|
33165
|
-
}
|
|
33166
|
-
);
|
|
33167
|
-
var TITLE_NAME = "DialogTitle";
|
|
33168
|
-
var DialogTitle$1 = React.forwardRef(
|
|
33169
|
-
(props, forwardedRef) => {
|
|
33170
|
-
const { __scopeDialog, ...titleProps } = props;
|
|
33171
|
-
const context = useDialogContext(TITLE_NAME, __scopeDialog);
|
|
33172
|
-
return /* @__PURE__ */ jsx(Primitive.h2, { id: context.titleId, ...titleProps, ref: forwardedRef });
|
|
33173
|
-
}
|
|
33174
|
-
);
|
|
33175
|
-
DialogTitle$1.displayName = TITLE_NAME;
|
|
33176
|
-
var DESCRIPTION_NAME = "DialogDescription";
|
|
33177
|
-
var DialogDescription$1 = React.forwardRef(
|
|
33178
|
-
(props, forwardedRef) => {
|
|
33179
|
-
const { __scopeDialog, ...descriptionProps } = props;
|
|
33180
|
-
const context = useDialogContext(DESCRIPTION_NAME, __scopeDialog);
|
|
33181
|
-
return /* @__PURE__ */ jsx(Primitive.p, { id: context.descriptionId, ...descriptionProps, ref: forwardedRef });
|
|
33182
|
-
}
|
|
33183
|
-
);
|
|
33184
|
-
DialogDescription$1.displayName = DESCRIPTION_NAME;
|
|
33185
|
-
var CLOSE_NAME = "DialogClose";
|
|
33186
|
-
var DialogClose$1 = React.forwardRef(
|
|
33187
|
-
(props, forwardedRef) => {
|
|
33188
|
-
const { __scopeDialog, ...closeProps } = props;
|
|
33189
|
-
const context = useDialogContext(CLOSE_NAME, __scopeDialog);
|
|
33190
|
-
return /* @__PURE__ */ jsx(
|
|
33191
|
-
Primitive.button,
|
|
33192
|
-
{
|
|
33193
|
-
type: "button",
|
|
33194
|
-
...closeProps,
|
|
33195
|
-
ref: forwardedRef,
|
|
33196
|
-
onClick: composeEventHandlers(props.onClick, () => context.onOpenChange(false))
|
|
33197
|
-
}
|
|
33198
|
-
);
|
|
33199
|
-
}
|
|
33200
|
-
);
|
|
33201
|
-
DialogClose$1.displayName = CLOSE_NAME;
|
|
33202
|
-
function getState(open) {
|
|
33203
|
-
return open ? "open" : "closed";
|
|
33204
|
-
}
|
|
33205
|
-
const Dialog = Dialog$1;
|
|
33206
|
-
const DialogClose = DialogClose$1;
|
|
33207
|
-
const DialogPortal = ({ children }) => {
|
|
33208
|
-
const portalContainer = usePortalContainer();
|
|
33209
|
-
return /* @__PURE__ */ jsx(DialogPortal$1, { container: portalContainer, children });
|
|
33210
|
-
};
|
|
33211
|
-
const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
33212
|
-
DialogOverlay$1,
|
|
33213
|
-
{
|
|
33214
|
-
ref,
|
|
33215
|
-
className: cn$1(
|
|
33216
|
-
`fixed inset-0 ${OVERLAY_LAYER.dialogOverlay} bg-black/24`,
|
|
33217
|
-
"data-[state=open]:animate-fade-in data-[state=closed]:animate-fade-out",
|
|
33218
|
-
"motion-reduce:animate-none",
|
|
33219
|
-
className
|
|
33220
|
-
),
|
|
33221
|
-
...props
|
|
33222
|
-
}
|
|
33223
|
-
));
|
|
33224
|
-
DialogOverlay.displayName = DialogOverlay$1.displayName;
|
|
33225
|
-
const DialogContent = React.forwardRef(({ className, children, hideCloseButton = false, onEscapeKeyDown, style, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
|
|
33226
|
-
/* @__PURE__ */ jsx(DialogOverlay, {}),
|
|
33227
|
-
/* @__PURE__ */ jsxs(
|
|
33228
|
-
DialogContent$1,
|
|
33229
|
-
{
|
|
33230
|
-
ref,
|
|
33231
|
-
onEscapeKeyDown: stopEscapePropagation(onEscapeKeyDown),
|
|
33232
|
-
style: {
|
|
33233
|
-
left: `calc(50% - (var(${BODY_SCROLLBAR_WIDTH_CSS_VAR}, 0px) / 2))`,
|
|
33234
|
-
...style
|
|
33235
|
-
},
|
|
33236
|
-
className: cn$1(
|
|
33237
|
-
`panel-shell fixed left-[50%] top-[50%] ${OVERLAY_LAYER.dialogContent} grid w-full max-w-[36rem] translate-x-[-50%] translate-y-[-50%] gap-5 rounded-2xl p-7 shadow-lg`,
|
|
33238
|
-
"data-[state=open]:animate-dialog-in data-[state=closed]:animate-dialog-out",
|
|
33239
|
-
"motion-reduce:animate-none",
|
|
33240
|
-
className
|
|
33241
|
-
),
|
|
33242
|
-
...props,
|
|
33243
|
-
children: [
|
|
33244
|
-
children,
|
|
33245
|
-
!hideCloseButton ? /* @__PURE__ */ jsxs(
|
|
33246
|
-
DialogClose$1,
|
|
33247
|
-
{
|
|
33248
|
-
className: cn$1(
|
|
33249
|
-
"absolute right-4 top-4 rounded-md border border-transparent bg-surface-2 p-1.5 text-text-tertiary",
|
|
33250
|
-
"transition-colors duration-fast",
|
|
33251
|
-
"hover:border-line-subtle hover:bg-surface-3 hover:text-text-primary",
|
|
33252
|
-
"focus-visible:outline-none focus-visible:shadow-focus"
|
|
33253
|
-
),
|
|
33254
|
-
children: [
|
|
33255
|
-
/* @__PURE__ */ jsx(X$1, { className: "h-4 w-4" }),
|
|
33256
|
-
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "닫기" })
|
|
33257
|
-
]
|
|
33258
|
-
}
|
|
33259
|
-
) : null
|
|
33260
|
-
]
|
|
33261
|
-
}
|
|
33262
|
-
)
|
|
33263
|
-
] }));
|
|
33264
|
-
DialogContent.displayName = DialogContent$1.displayName;
|
|
33265
|
-
const DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx("div", { className: cn$1("flex flex-col space-y-2 text-left", className), ...props });
|
|
33266
|
-
const DialogTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
33267
|
-
DialogTitle$1,
|
|
33268
|
-
{
|
|
33269
|
-
ref,
|
|
33270
|
-
className: cn$1("text-lg font-semibold text-text-primary", className),
|
|
33271
|
-
...props
|
|
33272
|
-
}
|
|
33273
|
-
));
|
|
33274
|
-
DialogTitle.displayName = DialogTitle$1.displayName;
|
|
33275
|
-
const DialogDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
33276
|
-
DialogDescription$1,
|
|
33277
|
-
{
|
|
33278
|
-
ref,
|
|
33279
|
-
className: cn$1("text-sm leading-relaxed text-text-secondary", className),
|
|
33280
|
-
...props
|
|
33281
|
-
}
|
|
33282
|
-
));
|
|
33283
|
-
DialogDescription.displayName = DialogDescription$1.displayName;
|
|
33284
33946
|
function getServiceDisplayName(serviceType) {
|
|
33285
33947
|
switch (serviceType) {
|
|
33286
33948
|
case "JIRA":
|
|
@@ -33470,13 +34132,78 @@ function IssueDeleteActions({
|
|
|
33470
34132
|
}
|
|
33471
34133
|
);
|
|
33472
34134
|
}
|
|
34135
|
+
function IssueGenerationFailure$1({
|
|
34136
|
+
isRegenerating,
|
|
34137
|
+
regenerate
|
|
34138
|
+
}) {
|
|
34139
|
+
const handleClick = async () => {
|
|
34140
|
+
const success = await regenerate();
|
|
34141
|
+
if (!success) {
|
|
34142
|
+
toast.error("재생성에 실패했습니다. 잠시 후 다시 시도해주세요.");
|
|
34143
|
+
}
|
|
34144
|
+
};
|
|
34145
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 text-sm", children: [
|
|
34146
|
+
/* @__PURE__ */ jsx("span", { className: "text-danger", children: "제목과 설명을 생성하지 못했습니다. 입력한 내용은 그대로 남아 있습니다." }),
|
|
34147
|
+
/* @__PURE__ */ jsx(
|
|
34148
|
+
Button,
|
|
34149
|
+
{
|
|
34150
|
+
type: "button",
|
|
34151
|
+
variant: "outline",
|
|
34152
|
+
size: "sm",
|
|
34153
|
+
onClick: handleClick,
|
|
34154
|
+
disabled: isRegenerating,
|
|
34155
|
+
children: "다시 생성"
|
|
34156
|
+
}
|
|
34157
|
+
)
|
|
34158
|
+
] });
|
|
34159
|
+
}
|
|
34160
|
+
function useRegenerateIssue(issueId, onUpdated) {
|
|
34161
|
+
const [isRegenerating, setIsRegenerating] = useState(false);
|
|
34162
|
+
const regenerate = useCallback(async () => {
|
|
34163
|
+
setIsRegenerating(true);
|
|
34164
|
+
try {
|
|
34165
|
+
await issueService.regenerateIssue(issueId);
|
|
34166
|
+
applyIssueMutationEffects(issueId);
|
|
34167
|
+
onUpdated == null ? void 0 : onUpdated();
|
|
34168
|
+
return true;
|
|
34169
|
+
} catch {
|
|
34170
|
+
return false;
|
|
34171
|
+
} finally {
|
|
34172
|
+
setIsRegenerating(false);
|
|
34173
|
+
}
|
|
34174
|
+
}, [issueId, onUpdated]);
|
|
34175
|
+
return { isRegenerating, regenerate };
|
|
34176
|
+
}
|
|
34177
|
+
function IssueGenerationFailure({
|
|
34178
|
+
issueId,
|
|
34179
|
+
onUpdated
|
|
34180
|
+
}) {
|
|
34181
|
+
const { isRegenerating, regenerate } = useRegenerateIssue(issueId, onUpdated);
|
|
34182
|
+
return /* @__PURE__ */ jsx(IssueGenerationFailure$1, { isRegenerating, regenerate });
|
|
34183
|
+
}
|
|
34184
|
+
function IssueGenerationBadge({ status }) {
|
|
34185
|
+
if (status === "pending" || status === "processing") {
|
|
34186
|
+
return /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center gap-1.5 rounded-md bg-warning-subtle px-2 py-0.5 text-2xs font-medium text-warning", children: [
|
|
34187
|
+
/* @__PURE__ */ jsx("span", { className: "h-1.5 w-1.5 rounded-md bg-warning" }),
|
|
34188
|
+
"제목 생성 중"
|
|
34189
|
+
] });
|
|
34190
|
+
}
|
|
34191
|
+
if (status === "failed") {
|
|
34192
|
+
return /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center gap-1.5 rounded-md bg-danger-subtle px-2 py-0.5 text-2xs font-medium text-danger", children: [
|
|
34193
|
+
/* @__PURE__ */ jsx("span", { className: "h-1.5 w-1.5 rounded-md bg-danger" }),
|
|
34194
|
+
"제목 생성 실패"
|
|
34195
|
+
] });
|
|
34196
|
+
}
|
|
34197
|
+
return null;
|
|
34198
|
+
}
|
|
33473
34199
|
function IssueHeader({
|
|
33474
34200
|
issueId,
|
|
33475
34201
|
title,
|
|
33476
34202
|
adminIssueUrl,
|
|
33477
34203
|
onClose,
|
|
33478
34204
|
onUpdated,
|
|
33479
|
-
readOnly = false
|
|
34205
|
+
readOnly = false,
|
|
34206
|
+
generationStatus
|
|
33480
34207
|
}) {
|
|
33481
34208
|
const [draftTitle, setDraftTitle] = useState(title);
|
|
33482
34209
|
const [isEditing, setIsEditing] = useState(false);
|
|
@@ -33532,6 +34259,7 @@ function IssueHeader({
|
|
|
33532
34259
|
}
|
|
33533
34260
|
) : /* @__PURE__ */ jsxs("div", { className: "flex max-w-full min-w-0 items-center gap-1", children: [
|
|
33534
34261
|
/* @__PURE__ */ jsx("h2", { className: "m-0 min-w-0 max-w-[28rem] truncate text-xl font-semibold text-text-primary", children: title }),
|
|
34262
|
+
/* @__PURE__ */ jsx(IssueGenerationBadge, { status: generationStatus }),
|
|
33535
34263
|
!readOnly ? /* @__PURE__ */ jsx(
|
|
33536
34264
|
Button,
|
|
33537
34265
|
{
|
|
@@ -34493,7 +35221,7 @@ function IssuePopover({ issueId, onClose, onUpdate }) {
|
|
|
34493
35221
|
const { isMember } = useAuthContext();
|
|
34494
35222
|
const canWriteContent = canWriteIssueContent(isMember, (_a = SDKManager.getInstance().config.user) == null ? void 0 : _a.id);
|
|
34495
35223
|
const { selectedProjectId } = useProject();
|
|
34496
|
-
const { data: issue } = useSuspenseQuery({
|
|
35224
|
+
const { data: issue, refetch } = useSuspenseQuery({
|
|
34497
35225
|
queryKey: ["issue", issueId, selectedProjectId],
|
|
34498
35226
|
queryFn: async () => {
|
|
34499
35227
|
const issueData = await issueService.getIssue(issueId);
|
|
@@ -34501,6 +35229,7 @@ function IssuePopover({ issueId, onClose, onUpdate }) {
|
|
|
34501
35229
|
}
|
|
34502
35230
|
});
|
|
34503
35231
|
const adminIssueUrl = getAdminIssueUrl(issue.id);
|
|
35232
|
+
useGenerationPolling({ status: issue.generation_status, onRefetch: refetch });
|
|
34504
35233
|
useDisableBodyScroll();
|
|
34505
35234
|
const mapping = getPrimaryJiraMapping(issue);
|
|
34506
35235
|
const meta = getJiraMetadata(mapping);
|
|
@@ -34534,10 +35263,12 @@ function IssuePopover({ issueId, onClose, onUpdate }) {
|
|
|
34534
35263
|
adminIssueUrl,
|
|
34535
35264
|
onClose: handleClose,
|
|
34536
35265
|
onUpdated: onUpdate,
|
|
34537
|
-
readOnly: !canWriteContent
|
|
35266
|
+
readOnly: !canWriteContent,
|
|
35267
|
+
generationStatus: issue.generation_status
|
|
34538
35268
|
}
|
|
34539
35269
|
) }),
|
|
34540
35270
|
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-4 py-3", children: /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
35271
|
+
issue.generation_status === "failed" ? /* @__PURE__ */ jsx(IssueGenerationFailure, { issueId: issue.id, onUpdated: onUpdate }) : null,
|
|
34541
35272
|
/* @__PURE__ */ jsx(
|
|
34542
35273
|
IssueDescription,
|
|
34543
35274
|
{
|
|
@@ -34975,6 +35706,63 @@ function getExpandedClusterStack(cluster, metrics = getWindowMetrics()) {
|
|
|
34975
35706
|
function getCurrentStickerDocumentMetrics() {
|
|
34976
35707
|
return getWindowMetrics();
|
|
34977
35708
|
}
|
|
35709
|
+
const STICKER_PALETTE_WHITE = "#FFFFFF";
|
|
35710
|
+
const STICKER_PALETTE_INK = "#111827";
|
|
35711
|
+
const STICKER_PALETTE = {
|
|
35712
|
+
slate: { bg: "#475569", fg: STICKER_PALETTE_WHITE },
|
|
35713
|
+
blue: { bg: "#1D4ED8", fg: STICKER_PALETTE_WHITE },
|
|
35714
|
+
teal: { bg: "#0F766E", fg: STICKER_PALETTE_WHITE },
|
|
35715
|
+
green: { bg: "#15803D", fg: STICKER_PALETTE_WHITE },
|
|
35716
|
+
amber: { bg: "#B45309", fg: STICKER_PALETTE_WHITE },
|
|
35717
|
+
red: { bg: "#DC2626", fg: STICKER_PALETTE_WHITE },
|
|
35718
|
+
pink: { bg: "#BE185D", fg: STICKER_PALETTE_WHITE },
|
|
35719
|
+
violet: { bg: "#6D28D9", fg: STICKER_PALETTE_WHITE },
|
|
35720
|
+
orange: { bg: "#F97316", fg: STICKER_PALETTE_INK },
|
|
35721
|
+
yellow: { bg: "#FACC15", fg: STICKER_PALETTE_INK },
|
|
35722
|
+
indigo: { bg: "#4338CA", fg: STICKER_PALETTE_WHITE },
|
|
35723
|
+
cyan: { bg: "#22D3EE", fg: STICKER_PALETTE_INK }
|
|
35724
|
+
};
|
|
35725
|
+
const STICKER_PALETTE_ORDER = Object.keys(STICKER_PALETTE);
|
|
35726
|
+
function getEntry(name2) {
|
|
35727
|
+
if (!name2) return null;
|
|
35728
|
+
return STICKER_PALETTE[name2] ?? null;
|
|
35729
|
+
}
|
|
35730
|
+
function getStickerColor(name2) {
|
|
35731
|
+
var _a;
|
|
35732
|
+
return ((_a = getEntry(name2)) == null ? void 0 : _a.bg) ?? null;
|
|
35733
|
+
}
|
|
35734
|
+
function getStickerForeground(name2) {
|
|
35735
|
+
var _a;
|
|
35736
|
+
return ((_a = getEntry(name2)) == null ? void 0 : _a.fg) ?? null;
|
|
35737
|
+
}
|
|
35738
|
+
const MAX_CLUSTER_BANDS = 4;
|
|
35739
|
+
function getClusterColorNames(members) {
|
|
35740
|
+
var _a;
|
|
35741
|
+
const present = /* @__PURE__ */ new Set();
|
|
35742
|
+
for (const member of members) {
|
|
35743
|
+
const color2 = (_a = member.design) == null ? void 0 : _a.color;
|
|
35744
|
+
if (color2 && getStickerColor(color2)) {
|
|
35745
|
+
present.add(color2);
|
|
35746
|
+
}
|
|
35747
|
+
}
|
|
35748
|
+
return STICKER_PALETTE_ORDER.filter((name2) => present.has(name2)).slice(
|
|
35749
|
+
0,
|
|
35750
|
+
MAX_CLUSTER_BANDS
|
|
35751
|
+
);
|
|
35752
|
+
}
|
|
35753
|
+
function buildClusterBackground(colorNames) {
|
|
35754
|
+
const hexes = colorNames.map((name2) => getStickerColor(name2)).filter((hex2) => Boolean(hex2));
|
|
35755
|
+
if (hexes.length === 0) return null;
|
|
35756
|
+
if (hexes.length === 1) return hexes[0] ?? null;
|
|
35757
|
+
const step = 100 / hexes.length;
|
|
35758
|
+
const round = (value) => Number.parseFloat(value.toFixed(2)).toString();
|
|
35759
|
+
const stops = hexes.map((hex2, index2) => {
|
|
35760
|
+
const from = index2 === 0 ? "0" : `${round(step * index2)}%`;
|
|
35761
|
+
const to = index2 === hexes.length - 1 ? "100%" : `${round(step * (index2 + 1))}%`;
|
|
35762
|
+
return `${hex2} ${from} ${to}`;
|
|
35763
|
+
});
|
|
35764
|
+
return `linear-gradient(135deg, ${stops.join(", ")})`;
|
|
35765
|
+
}
|
|
34978
35766
|
const STICKER_MAX_WIDTH = 480;
|
|
34979
35767
|
const STICKER_NON_TEXT_WIDTH = 72;
|
|
34980
35768
|
function getEstimatedTextWidth(title) {
|
|
@@ -34988,12 +35776,15 @@ function getEstimatedTextWidth(title) {
|
|
|
34988
35776
|
return width + 7;
|
|
34989
35777
|
}, 0);
|
|
34990
35778
|
}
|
|
34991
|
-
|
|
35779
|
+
const STICKER_BADGE_GAP = 36;
|
|
35780
|
+
function getEstimatedExpandedWidth(title, badge) {
|
|
35781
|
+
const badgeWidth = badge ? getEstimatedTextWidth(badge) + STICKER_BADGE_GAP : 0;
|
|
34992
35782
|
return Math.min(
|
|
34993
|
-
Math.max(getEstimatedTextWidth(title) + STICKER_NON_TEXT_WIDTH, 112),
|
|
35783
|
+
Math.max(getEstimatedTextWidth(title) + STICKER_NON_TEXT_WIDTH + badgeWidth, 112),
|
|
34994
35784
|
STICKER_MAX_WIDTH
|
|
34995
35785
|
);
|
|
34996
35786
|
}
|
|
35787
|
+
const GENERATING_LABEL = "제목 생성 중";
|
|
34997
35788
|
function IssueSticker$1({
|
|
34998
35789
|
issue,
|
|
34999
35790
|
isPopoverOpen,
|
|
@@ -35002,30 +35793,49 @@ function IssueSticker$1({
|
|
|
35002
35793
|
clusterCount,
|
|
35003
35794
|
onClusterClick,
|
|
35004
35795
|
clusterStackAnimation,
|
|
35005
|
-
clusterStackIndex = 0
|
|
35796
|
+
clusterStackIndex = 0,
|
|
35797
|
+
clusterColorNames,
|
|
35798
|
+
alwaysExpanded = false,
|
|
35799
|
+
ariaLabel
|
|
35006
35800
|
}) {
|
|
35801
|
+
var _a, _b2, _c2;
|
|
35007
35802
|
const position2 = documentPosition;
|
|
35008
|
-
const
|
|
35803
|
+
const resolvedClusterCount = clusterCount ?? 0;
|
|
35804
|
+
const isCluster = resolvedClusterCount > 1;
|
|
35805
|
+
const clusterBackground = isCluster ? buildClusterBackground(clusterColorNames ?? []) : null;
|
|
35806
|
+
const generating = isGeneratingStatus(issue.generation_status) && !isCluster;
|
|
35807
|
+
const visibleTitle = isCluster ? `스티커 ${resolvedClusterCount}개 펼치기` : generating ? GENERATING_LABEL : issue.title;
|
|
35808
|
+
const badgeLabel = isCluster || generating ? null : ((_a = issue.design) == null ? void 0 : _a.label) ?? null;
|
|
35809
|
+
const designColor = isCluster || generating ? null : getStickerColor((_b2 = issue.design) == null ? void 0 : _b2.color);
|
|
35810
|
+
const designForeground = designColor ? getStickerForeground((_c2 = issue.design) == null ? void 0 : _c2.color) : null;
|
|
35811
|
+
const expandedWidth = getEstimatedExpandedWidth(visibleTitle, badgeLabel);
|
|
35009
35812
|
const viewportWidth = typeof window === "undefined" ? Number.POSITIVE_INFINITY : window.innerWidth;
|
|
35010
35813
|
const scrollX = typeof window === "undefined" ? 0 : window.scrollX || window.pageXOffset || 0;
|
|
35011
35814
|
const viewportX = position2.x - scrollX;
|
|
35012
|
-
const shouldExpandLeft = viewportX + expandedWidth > viewportWidth - 12;
|
|
35815
|
+
const shouldExpandLeft = !alwaysExpanded && viewportX + expandedWidth > viewportWidth - 12;
|
|
35013
35816
|
const expandSide = shouldExpandLeft ? "left" : "right";
|
|
35014
|
-
const style = {
|
|
35817
|
+
const style = alwaysExpanded ? { position: "relative" } : {
|
|
35015
35818
|
position: "absolute",
|
|
35016
35819
|
left: `${position2.x}px`,
|
|
35017
35820
|
top: `${position2.y}px`,
|
|
35018
35821
|
transform: shouldExpandLeft ? "translate3d(calc(-100% + 16px), -50%, 0)" : "translate3d(-16px, -50%, 0)"
|
|
35019
35822
|
};
|
|
35020
35823
|
const wrapperClassName = isPopoverOpen ? "z-[10001]" : "z-[9999] hover:z-[10001] focus-within:z-[10001]";
|
|
35021
|
-
const
|
|
35022
|
-
const
|
|
35023
|
-
const buttonClassName = `issue-sticker-marker issue-marker-breathe group flex h-8 w-max cursor-pointer items-center overflow-hidden rounded-full border text-white shadow-lg outline-none transition-[max-width,box-shadow,background-color,border-color,transform,opacity] duration-[var(--issue-marker-expand-duration)] ease-out focus-visible:ring-4 ${isCluster ?
|
|
35024
|
-
const
|
|
35025
|
-
const buttonStyle =
|
|
35026
|
-
|
|
35027
|
-
|
|
35028
|
-
|
|
35824
|
+
const colorClassName = designColor ? "" : "bg-brand hover:bg-brand-hover";
|
|
35825
|
+
const expandClassName = alwaysExpanded ? "max-w-[480px]" : "max-w-8 hover:max-w-[480px] hover:shadow-xl focus-visible:max-w-[480px]";
|
|
35826
|
+
const buttonClassName = `issue-sticker-marker ${generating || alwaysExpanded ? "" : "issue-marker-breathe"} group flex h-8 w-max cursor-pointer items-center overflow-hidden rounded-full border text-white shadow-lg outline-none transition-[max-width,box-shadow,background-color,border-color,transform,opacity] duration-[var(--issue-marker-expand-duration)] ease-out focus-visible:ring-4 ${isCluster ? `max-w-8 border-white/80 ${clusterBackground ? "" : "bg-brand hover:bg-brand-hover"} shadow-lg ring-2 ring-brand-subtle hover:max-w-[160px] hover:shadow-xl focus-visible:max-w-[160px] focus-visible:ring-brand-subtle` : `${expandClassName} ${colorClassName} focus-visible:ring-brand-subtle ${generating ? "border-dashed border-white/70" : "border-white/80"}`} ${shouldExpandLeft ? "flex-row-reverse" : ""} ${isPopoverOpen ? "shadow-xl ring-4 ring-brand-subtle" : ""}`;
|
|
35827
|
+
const backgroundStyle = clusterBackground ? clusterBackground.startsWith("linear-gradient") ? { background: clusterBackground } : { backgroundColor: clusterBackground } : designColor ? { backgroundColor: designColor } : {};
|
|
35828
|
+
const buttonStyle = {
|
|
35829
|
+
...backgroundStyle,
|
|
35830
|
+
// 밝은 배경(노랑·주황·하늘)은 흰 글씨로 대비가 안 나온다. 팔레트가 정한 글씨색을
|
|
35831
|
+
// inline 으로 얹어 text-white 클래스를 덮는다.
|
|
35832
|
+
...designForeground ? { color: designForeground } : {},
|
|
35833
|
+
["--issue-sticker-expanded-width"]: `${expandedWidth}px`,
|
|
35834
|
+
...clusterStackAnimation ? {
|
|
35835
|
+
animation: clusterStackAnimation === "enter" ? "issue-sticker-cluster-sticker-enter 240ms cubic-bezier(0.34, 1.2, 0.64, 1) both" : "issue-sticker-cluster-sticker-exit 220ms ease-in both",
|
|
35836
|
+
animationDelay: clusterStackAnimation === "enter" ? `${clusterStackIndex * 24}ms` : void 0
|
|
35837
|
+
} : {}
|
|
35838
|
+
};
|
|
35029
35839
|
const handleClick = () => {
|
|
35030
35840
|
if (isCluster) {
|
|
35031
35841
|
onClusterClick == null ? void 0 : onClusterClick();
|
|
@@ -35043,23 +35853,31 @@ function IssueSticker$1({
|
|
|
35043
35853
|
"data-cluster-count": isCluster ? resolvedClusterCount : void 0,
|
|
35044
35854
|
"data-expand-side": expandSide,
|
|
35045
35855
|
onClick: handleClick,
|
|
35046
|
-
"aria-label": isCluster ? `겹친 스티커 ${resolvedClusterCount}개 펼치기` : `이슈 열기: ${
|
|
35856
|
+
"aria-label": ariaLabel ?? (isCluster ? `겹친 스티커 ${resolvedClusterCount}개 펼치기` : `이슈 열기: ${visibleTitle}`),
|
|
35047
35857
|
children: [
|
|
35048
35858
|
/* @__PURE__ */ jsx(
|
|
35049
35859
|
"span",
|
|
35050
35860
|
{
|
|
35051
|
-
className: "flex
|
|
35861
|
+
className: "flex aspect-square h-full shrink-0 items-center justify-center text-sm font-black leading-none",
|
|
35052
35862
|
"aria-hidden": "true",
|
|
35053
|
-
children: isCluster ? `+${resolvedClusterCount}` : "!"
|
|
35863
|
+
children: isCluster ? `+${resolvedClusterCount}` : generating ? /* @__PURE__ */ jsx(LoaderCircle, { className: "h-4 w-4 animate-spin" }) : "!"
|
|
35054
35864
|
}
|
|
35055
35865
|
),
|
|
35056
35866
|
/* @__PURE__ */ jsx(
|
|
35057
35867
|
"span",
|
|
35058
35868
|
{
|
|
35059
|
-
className: `min-w-0 max-w-[428px] flex-1 truncate whitespace-nowrap text-xs font-semibold leading-none
|
|
35869
|
+
className: `min-w-0 max-w-[428px] flex-1 truncate whitespace-nowrap text-xs font-semibold leading-none transition-[opacity,transform] duration-[var(--issue-marker-expand-duration)] ease-out ${alwaysExpanded ? "translate-x-0 opacity-100" : "opacity-0 group-hover:translate-x-0 group-hover:opacity-100 group-focus-visible:translate-x-0 group-focus-visible:opacity-100"} ${shouldExpandLeft ? `${alwaysExpanded ? "" : "translate-x-1"} pl-3 text-right` : `${alwaysExpanded ? "" : "-translate-x-1"} pr-3 text-left`}`,
|
|
35060
35870
|
children: visibleTitle
|
|
35061
35871
|
}
|
|
35062
|
-
)
|
|
35872
|
+
),
|
|
35873
|
+
badgeLabel ? /* @__PURE__ */ jsx(
|
|
35874
|
+
"span",
|
|
35875
|
+
{
|
|
35876
|
+
"data-sticker-badge": "",
|
|
35877
|
+
className: `mx-3 shrink-0 whitespace-nowrap rounded-sm px-1.5 py-0.5 text-[10px] font-bold leading-none transition-opacity duration-[var(--issue-marker-expand-duration)] ease-out ${designForeground === STICKER_PALETTE_INK ? "bg-black/10" : "bg-white/25"} ${alwaysExpanded ? "opacity-100" : "opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100"}`,
|
|
35878
|
+
children: badgeLabel
|
|
35879
|
+
}
|
|
35880
|
+
) : null
|
|
35063
35881
|
]
|
|
35064
35882
|
}
|
|
35065
35883
|
) });
|
|
@@ -35310,7 +36128,10 @@ function IssueStickersContainer$1({
|
|
|
35310
36128
|
isPopoverOpen: false,
|
|
35311
36129
|
onStickerClick,
|
|
35312
36130
|
clusterCount: cluster.placements.length,
|
|
35313
|
-
onClusterClick: () => openCluster(cluster.id)
|
|
36131
|
+
onClusterClick: () => openCluster(cluster.id),
|
|
36132
|
+
clusterColorNames: getClusterColorNames(
|
|
36133
|
+
cluster.placements.map((placement) => placement.issue)
|
|
36134
|
+
)
|
|
35314
36135
|
},
|
|
35315
36136
|
cluster.id
|
|
35316
36137
|
);
|
|
@@ -37150,7 +37971,6 @@ function ContentAppWrapper({
|
|
|
37150
37971
|
onBeforeStart: handleBeforeOnboardingStart,
|
|
37151
37972
|
isCreatingIssueFlow: isCreatingIssue || clickPosition !== null,
|
|
37152
37973
|
children: [
|
|
37153
|
-
/* @__PURE__ */ jsx(ToastContainer, { position: "top-right" }),
|
|
37154
37974
|
fabEnabled && /* @__PURE__ */ jsx(
|
|
37155
37975
|
SdkToolbar,
|
|
37156
37976
|
{
|
|
@@ -37172,7 +37992,7 @@ function ContentAppWrapper({
|
|
|
37172
37992
|
onMenuOpenChange: setMoreMenuOpen
|
|
37173
37993
|
}
|
|
37174
37994
|
),
|
|
37175
|
-
/* @__PURE__ */ jsx(QueryBoundary, { loadingFallback: /* @__PURE__ */ jsx(Fragment, {}), children: /* @__PURE__ */ jsx(
|
|
37995
|
+
/* @__PURE__ */ jsx(QueryBoundary, { loadingFallback: /* @__PURE__ */ jsx(Fragment, {}), onError: OverlayErrorFallback, children: /* @__PURE__ */ jsx(
|
|
37176
37996
|
IssueStickersContainer,
|
|
37177
37997
|
{
|
|
37178
37998
|
issues,
|
|
@@ -37194,7 +38014,7 @@ function ContentAppWrapper({
|
|
|
37194
38014
|
renderMode
|
|
37195
38015
|
}
|
|
37196
38016
|
),
|
|
37197
|
-
openPopoverIssueId && isExtensionEnabled && /* @__PURE__ */ jsx(QueryBoundary, { loadingFallback: /* @__PURE__ */ jsx(Fragment, {}), children: /* @__PURE__ */ jsx(
|
|
38017
|
+
openPopoverIssueId && isExtensionEnabled && /* @__PURE__ */ jsx(QueryBoundary, { loadingFallback: /* @__PURE__ */ jsx(Fragment, {}), onError: OverlayErrorFallback, children: /* @__PURE__ */ jsx(
|
|
37198
38018
|
IssuePopover,
|
|
37199
38019
|
{
|
|
37200
38020
|
issueId: openPopoverIssueId,
|
|
@@ -37202,7 +38022,7 @@ function ContentAppWrapper({
|
|
|
37202
38022
|
onUpdate: loadIssues
|
|
37203
38023
|
}
|
|
37204
38024
|
) }),
|
|
37205
|
-
clickPosition && isExtensionEnabled && /* @__PURE__ */ jsx(QueryBoundary, { loadingFallback: /* @__PURE__ */ jsx(Fragment, {}), children: /* @__PURE__ */ jsx(
|
|
38025
|
+
clickPosition && isExtensionEnabled && /* @__PURE__ */ jsx(QueryBoundary, { loadingFallback: /* @__PURE__ */ jsx(Fragment, {}), onError: OverlayErrorFallback, children: /* @__PURE__ */ jsx(
|
|
37206
38026
|
IssueForm,
|
|
37207
38027
|
{
|
|
37208
38028
|
position: clickPosition,
|
|
@@ -37247,18 +38067,21 @@ function AuthGate() {
|
|
|
37247
38067
|
if (!isAuthenticated) {
|
|
37248
38068
|
return null;
|
|
37249
38069
|
}
|
|
37250
|
-
return /* @__PURE__ */
|
|
37251
|
-
|
|
37252
|
-
{
|
|
37253
|
-
|
|
37254
|
-
|
|
37255
|
-
|
|
37256
|
-
|
|
37257
|
-
|
|
38070
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
38071
|
+
/* @__PURE__ */ jsx(ToastContainer, { position: "top-right" }),
|
|
38072
|
+
/* @__PURE__ */ jsx(QueryBoundary, { loadingFallback: /* @__PURE__ */ jsx(Fragment, {}), onError: OverlayErrorFallback, children: /* @__PURE__ */ jsx(
|
|
38073
|
+
ContentAppWrapper,
|
|
38074
|
+
{
|
|
38075
|
+
fabEnabled,
|
|
38076
|
+
toolbar: sdk.config.toolbar,
|
|
38077
|
+
onboarding
|
|
38078
|
+
}
|
|
38079
|
+
) })
|
|
38080
|
+
] });
|
|
37258
38081
|
}
|
|
37259
|
-
const globalsCSS = `:root,:host{color-scheme:light;--brand-h: 150;--brand-s: 100%;--brand-l: 34%;--brand-hsl: var(--brand-h) var(--brand-s) var(--brand-l);--brand: hsl(var(--brand-hsl));--brand-hover: hsl(var(--brand-h) calc(var(--brand-s) + 3%) calc(var(--brand-l) - 4%));--brand-active: hsl(var(--brand-h) calc(var(--brand-s) + 2%) calc(var(--brand-l) - 8%));--brand-subtle: hsl(var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .14);--brand-border: hsl(var(--brand-h) calc(var(--brand-s) + 8%) calc(var(--brand-l) + 8%) / .34);--brand-fg: hsl(0 0% 100%);--brand-ring: hsl(var(--brand-h) calc(var(--brand-s) + 12%) calc(var(--brand-l) + 10%) / .22);--font-sans: "Pretendard", -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;--font-display: var(--font-sans);--font-mono: var(--font-sans);--surface-0: 0 0% 99%;--surface-1: 0 0% 100%;--surface-2: 144 8% 96%;--surface-3: 144 6% 93%;--surface-inset: 144 6% 95%;--overlay-backdrop: hsl(0 0% 0% / .24);--overlay-backdrop-strong: hsl(0 0% 0% / .48);--text-primary: 150 10% 12%;--text-secondary: 148 6% 36%;--text-tertiary: 145 5% 42%;--text-disabled: 145 4% 70%;--text-inverse: 0 0% 100%;--border-subtle: 144 8% 91%;--border-default: 144 6% 85%;--border-strong: 144 5% 72%;--border-focus: var(--brand-h) var(--brand-s) var(--brand-l);--success: var(--brand-h) var(--brand-s) var(--brand-l);--success-subtle: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .14;--success-surface: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .24;--warning: 34 82% 52%;--warning-subtle: 34 82% 52% / .14;--danger: 3 68% 56%;--danger-subtle: 3 68% 56% / .12;--info: 202 52% 44%;--info-subtle: 202 52% 44% / .12;--accent-terra: 13 52% 47%;--accent-terra-subtle: 13 52% 47% / .1;--accent-terra-deep: 13 48% 44%;--accent-blue: 213 86% 56%;--accent-blue-subtle: 213 92% 56% / .12;--accent-blue-deep: 216 78% 40%;--accent-blue-border: 213 86% 62% / .36;--accent-cream: 38 52% 88%;--accent-cream-warm: 40 56% 95%;--accent-cream-deep: 38 48% 82%;--accent-highlight: 55 96% 70%;--accent-ink: 32 13% 11%;--radius-xs: 4px;--radius-sm: 8px;--radius-md: 12px;--radius-lg: 16px;--radius-xl: 20px;--radius-2xl: 24px;--radius-pill: 9999px;--shadow-xs: 0 1px 2px 0 hsl(0 0% 0% / .04);--shadow-sm: 0 1px 3px 0 hsl(0 0% 0% / .06), 0 1px 2px -1px hsl(0 0% 0% / .06);--shadow-md: 0 4px 6px -1px hsl(0 0% 0% / .06), 0 2px 4px -2px hsl(0 0% 0% / .04);--shadow-lg: 0 10px 15px -3px hsl(0 0% 0% / .06), 0 4px 6px -4px hsl(0 0% 0% / .04);--shadow-xl: 0 20px 25px -5px hsl(0 0% 0% / .06), 0 8px 10px -6px hsl(0 0% 0% / .04);--shadow-focus: 0 0 0 3px var(--brand-ring);--shadow-inset: inset 0 1px 2px 0 hsl(0 0% 0% / .04);--shadow-brand: 0 2px 8px hsl(var(--brand-h) calc(var(--brand-s) - 60%) calc(var(--brand-l) - 14%) / .24), 0 6px 20px hsl(var(--brand-h) calc(var(--brand-s) - 70%) calc(var(--brand-l) - 19%) / .16);--duration-instant: 90ms;--duration-fast: .16s;--duration-base: .26s;--duration-out: .18s;--duration-slow: .36s;--ease-out: cubic-bezier(.23, 1, .32, 1);--ease-in-out: cubic-bezier(.45, 0, .15, 1);--ease-spring: cubic-bezier(.18, .94, .32, 1.08);--grid-line: 0 0% 92%}.dark,:host(.dark){color-scheme:dark;--brand-l: 34%;--brand-fg: hsl(0 0% 100%);--surface-0: 150 8% 7%;--surface-1: 150 6% 10%;--surface-2: 150 5% 14%;--surface-3: 150 4% 18%;--surface-inset: 150 6% 6%;--overlay-backdrop: hsl(0 0% 0% / .56);--overlay-backdrop-strong: hsl(0 0% 0% / .8);--text-primary: 40 16% 93%;--text-secondary: 36 8% 68%;--text-tertiary: 34 6% 50%;--text-disabled: 30 5% 34%;--text-inverse: 150 8% 10%;--border-subtle: 150 6% 16%;--border-default: 150 5% 22%;--border-strong: 150 4% 34%;--success: var(--brand-h) var(--brand-s) var(--brand-l);--success-subtle: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .14;--success-surface: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .24;--warning: 34 82% 62%;--danger: 2 70% 64%;--info: 202 54% 62%;--accent-terra: 13 56% 62%;--accent-terra-subtle: 13 56% 62% / .14;--accent-terra-deep: 13 52% 56%;--accent-blue: 210 92% 68%;--accent-blue-subtle: 210 92% 68% / .18;--accent-blue-deep: 209 100% 78%;--accent-blue-border: 210 92% 72% / .44;--accent-cream: 38 30% 26%;--accent-cream-warm: 38 22% 18%;--accent-cream-deep: 38 26% 32%;--accent-highlight: 55 96% 70%;--accent-ink: 32 13% 8%;--shadow-xs: 0 1px 2px 0 hsl(0 0% 0% / .2);--shadow-sm: 0 1px 3px 0 hsl(0 0% 0% / .3), 0 1px 2px -1px hsl(0 0% 0% / .24);--shadow-md: 0 4px 6px -1px hsl(0 0% 0% / .34), 0 2px 4px -2px hsl(0 0% 0% / .2);--shadow-lg: 0 10px 15px -3px hsl(0 0% 0% / .38), 0 4px 6px -4px hsl(0 0% 0% / .24);--shadow-xl: 0 20px 25px -5px hsl(0 0% 0% / .44), 0 8px 10px -6px hsl(0 0% 0% / .28);--shadow-inset: inset 0 1px 2px 0 hsl(0 0% 0% / .16);--shadow-brand: 0 2px 8px hsl(var(--brand-h) calc(var(--brand-s) - 60%) calc(var(--brand-l) - 24%) / .44), 0 6px 20px hsl(0 0% 0% / .32);--grid-line: 150 6% 14%}*{border-color:hsl(var(--border-default))}html{font-family:var(--font-sans),ui-sans-serif,system-ui,-apple-system,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;font-feature-settings:"cv11","ss01","ss03";background-color:hsl(var(--surface-0))}body{margin:0;min-height:100vh;color:hsl(var(--text-primary));background-color:hsl(var(--surface-0))}::-moz-selection{background-color:hsl(var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 16%) / .22);color:hsl(var(--text-primary))}::selection{background-color:hsl(var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 16%) / .22);color:hsl(var(--text-primary))}code,kbd,samp,pre{font-family:var(--font-mono),ui-monospace,SFMono-Regular,Menlo,monospace;font-feature-settings:"ss01","ss02","cv11"}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:hsl(var(--border-strong) / .52);border-radius:var(--radius-pill);border:2px solid transparent;background-clip:padding-box}::-webkit-scrollbar-thumb:hover{background:hsl(var(--border-strong) / .9);background-clip:padding-box;border:2px solid transparent}.app-canvas,.grid-canvas{background-color:hsl(var(--surface-0))}.onboarding-canvas{--surface-0: var(--brand-h) var(--brand-s) var(--brand-l);--surface-1: 0 0% 100%;--surface-2: var(--brand-h) 62% 28%;--surface-3: var(--brand-h) 60% 25%;--surface-inset: var(--brand-h) 62% 28%;--text-primary: 0 0% 100%;--text-secondary: var(--brand-h) 46% 90%;--text-tertiary: var(--brand-h) 34% 84%;--text-disabled: var(--brand-h) 20% 72%;--border-subtle: var(--brand-h) 44% 52%;--border-default: var(--brand-h) 40% 58%;--border-strong: var(--brand-h) 36% 70%;--border-focus: 0 0% 100%;--brand-hsl: 0 0% 100%;--brand: hsl(var(--brand-hsl));--brand-hover: hsl(var(--brand-h) 24% 94%);--brand-active: hsl(var(--brand-h) 20% 88%);--brand-fg: hsl(var(--brand-h) var(--brand-s) 24%);--brand-ring: hsl(0 0% 100% / .4);--danger: 6 96% 86%;--danger-subtle: 6 96% 86% / .18;--warning: 42 96% 82%;--warning-subtle: 42 96% 82% / .18}.onboarding-canvas .bg-surface-1,.onboarding-canvas input,.onboarding-canvas textarea,.onboarding-canvas [role=combobox]{--text-primary: 150 10% 12%;--text-secondary: 148 6% 36%;--text-tertiary: 145 5% 42%;--surface-2: 144 8% 96%;--border-subtle: 144 8% 91%;--border-default: 144 6% 85%}@keyframes onboarding-step-in{0%{opacity:0;transform:translate(96px)}to{opacity:1;transform:translate(0)}}.onboarding-step-in{animation:onboarding-step-in var(--duration-slow) var(--ease-out) forwards}@keyframes onboarding-enter-up{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.onboarding-enter{position:fixed;top:0;right:0;bottom:0;left:0;overflow-x:hidden;overflow-y:auto;animation:onboarding-enter-up var(--duration-base) var(--ease-out) forwards}@keyframes onboarding-confetti-x{0%{transform:translate(0)}to{transform:translate(var(--confetti-x))}}@keyframes onboarding-confetti-y{0%{transform:translateY(0);animation-timing-function:cubic-bezier(.12,.66,.32,1)}42%{transform:translateY(var(--confetti-lift));animation-timing-function:cubic-bezier(.58,0,.86,.32)}to{transform:translateY(var(--confetti-drop))}}@keyframes onboarding-confetti-piece{0%{opacity:0;transform:scale(.7) rotate(0)}6%{opacity:1}72%{opacity:1}to{opacity:0;transform:scale(1) rotate(var(--confetti-spin))}}.onboarding-confetti-x,.onboarding-confetti-y,.onboarding-confetti-piece{--confetti-duration: 1.9s;animation-duration:var(--confetti-duration);animation-delay:var(--confetti-delay, 0ms);animation-fill-mode:both}.onboarding-confetti-x{animation-name:onboarding-confetti-x;animation-timing-function:cubic-bezier(.08,.62,.3,1)}.onboarding-confetti-y{animation-name:onboarding-confetti-y;animation-timing-function:linear}.onboarding-confetti-piece{width:var(--confetti-size);height:var(--confetti-size);border-radius:var(--radius-pill) var(--radius-xs) var(--radius-pill) var(--radius-pill);animation-name:onboarding-confetti-piece;animation-timing-function:linear}@media(prefers-reduced-motion:reduce){.onboarding-confetti-x,.onboarding-confetti-y,.onboarding-confetti-piece{animation:none;opacity:0}}body:has(.onboarding-canvas){background-color:hsl(var(--brand-h) var(--brand-s) var(--brand-l))}.panel-shell,.surface-shell{border:1px solid hsl(var(--border-subtle));border-radius:var(--radius-xl);background:hsl(var(--surface-1));box-shadow:var(--shadow-sm)}.panel-shell-muted,.surface-shell-muted{background:hsl(var(--surface-2));box-shadow:var(--shadow-xs)}.panel-shell-subtle{border:1px solid hsl(var(--border-subtle));border-radius:var(--radius-lg);background:hsl(var(--surface-1));box-shadow:var(--shadow-xs)}.panel-shell-elevated{border:1px solid hsl(var(--border-default));border-radius:var(--radius-xl);background:hsl(var(--surface-1));box-shadow:var(--shadow-md)}.utility-chip,.floating-chip{display:inline-flex;align-items:center;gap:.5rem;border:1px solid hsl(var(--border-default));border-radius:var(--radius-pill);background:hsl(var(--surface-1));box-shadow:var(--shadow-xs)}.hairline{border-bottom:1px solid hsl(var(--border-subtle))}.mono-label{font-family:var(--font-mono),ui-monospace,monospace;font-size:11px;text-transform:uppercase;color:hsl(var(--text-tertiary))}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--font-sans),ui-sans-serif,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--font-mono),ui-monospace,SFMono-Regular,Menlo,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root,:host{--font-sans: "Pretendard", -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;--font-mono: var(--font-sans);--issue-marker-expand-duration: .52s;--surface-0: 0 0% 99%;--surface-1: 0 0% 100%;--surface-2: 144 8% 96%;--surface-3: 144 6% 93%;--surface-inset: 144 6% 95%;--overlay-backdrop: hsl(0 0% 0% / .24);--overlay-backdrop-strong: hsl(0 0% 0% / .48);--text-primary: 150 10% 12%;--text-secondary: 148 6% 36%;--text-tertiary: 145 5% 52%;--text-disabled: 145 4% 70%;--border-subtle: 144 8% 91%;--border-default: 144 6% 85%;--border-strong: 144 5% 72%;--grid-line: 0 0% 92%;--shadow-xs: 0 1px 2px 0 hsl(0 0% 0% / .04);--shadow-sm: 0 1px 3px 0 hsl(0 0% 0% / .06), 0 1px 2px -1px hsl(0 0% 0% / .06);--shadow-md: 0 4px 6px -1px hsl(0 0% 0% / .06), 0 2px 4px -2px hsl(0 0% 0% / .04);--shadow-lg: 0 10px 15px -3px hsl(0 0% 0% / .06), 0 4px 6px -4px hsl(0 0% 0% / .04);--shadow-xl: 0 20px 25px -5px hsl(0 0% 0% / .06), 0 8px 10px -6px hsl(0 0% 0% / .04);--shadow-focus: 0 0 0 4px var(--brand-ring);--shadow-inset: inset 0 1px 2px 0 hsl(0 0% 0% / .04)}*{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}#issue-sticker-shadow-root{background-color:transparent;--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.container{width:100%}@media(min-width:640px){.container{max-width:640px}}@media(min-width:768px){.container{max-width:768px}}@media(min-width:1024px){.container{max-width:1024px}}@media(min-width:1280px){.container{max-width:1280px}}@media(min-width:1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.\\!visible{visibility:visible!important}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-x-0{left:0;right:0}.inset-x-1{left:.25rem;right:.25rem}.inset-y-0{top:0;bottom:0}.-bottom-px{bottom:-1px}.bottom-0{bottom:0}.bottom-4{bottom:1rem}.bottom-6{bottom:1.5rem}.left-0{left:0}.left-1\\/2{left:50%}.left-2{left:.5rem}.left-4{left:1rem}.left-\\[50\\%\\]{left:50%}.right-0{right:0}.right-2{right:.5rem}.right-3{right:.75rem}.right-4{right:1rem}.right-5{right:1.25rem}.right-6{right:1.5rem}.top-0{top:0}.top-1{top:.25rem}.top-1\\/2{top:50%}.top-2{top:.5rem}.top-3{top:.75rem}.top-4{top:1rem}.top-5{top:1.25rem}.top-\\[50\\%\\]{top:50%}.top-\\[calc\\(\\(3\\.5rem-1\\.75rem\\)\\/2\\)\\]{top:.875rem}.top-full{top:100%}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.z-\\[1000000\\]{z-index:1000000}.z-\\[1000003\\]{z-index:1000003}.z-\\[1000004\\]{z-index:1000004}.z-\\[1000005\\]{z-index:1000005}.z-\\[1000006\\]{z-index:1000006}.z-\\[1000007\\]{z-index:1000007}.z-\\[1000008\\]{z-index:1000008}.z-\\[1000010\\]{z-index:1000010}.z-\\[1000011\\]{z-index:1000011}.z-\\[10001\\]{z-index:10001}.z-\\[999999\\]{z-index:999999}.z-\\[9999\\]{z-index:9999}.m-0{margin:0}.-mx-2{margin-left:-.5rem;margin-right:-.5rem}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-2\\.5{margin-top:.625rem;margin-bottom:.625rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.mb-0\\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-5{margin-bottom:1.25rem}.ml-0\\.5{margin-left:.125rem}.ml-4{margin-left:1rem}.mr-1\\.5{margin-right:.375rem}.mt-0{margin-top:0}.mt-0\\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.aspect-square{aspect-ratio:1 / 1}.\\!h-auto{height:auto!important}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-2{height:.5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-3\\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\\[1\\.4rem\\]{height:1.4rem}.h-\\[100vh\\]{height:100vh}.h-\\[18px\\]{height:18px}.h-\\[220px\\]{height:220px}.h-\\[22px\\]{height:22px}.h-\\[30px\\]{height:30px}.h-\\[min\\(36vh\\,320px\\)\\]{height:min(36vh,320px)}.h-\\[min\\(480px\\,calc\\(100vh-64px\\)\\)\\]{height:min(480px,calc(100vh - 64px))}.h-\\[min\\(54vh\\,520px\\)\\]{height:min(54vh,520px)}.h-\\[min\\(560px\\,calc\\(100vh-32px\\)\\)\\]{height:min(560px,calc(100vh - 32px))}.h-\\[var\\(--radix-select-trigger-height\\)\\]{height:var(--radix-select-trigger-height)}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.max-h-24{max-height:6rem}.max-h-56{max-height:14rem}.max-h-96{max-height:24rem}.max-h-\\[150px\\]{max-height:150px}.max-h-\\[220px\\]{max-height:220px}.max-h-\\[320px\\]{max-height:320px}.max-h-\\[420px\\]{max-height:420px}.max-h-\\[90vh\\]{max-height:90vh}.max-h-\\[calc\\(100vh-3rem\\)\\]{max-height:calc(100vh - 3rem)}.max-h-\\[min\\(80vh\\,640px\\)\\]{max-height:min(80vh,640px)}.min-h-0{min-height:0px}.min-h-11{min-height:2.75rem}.min-h-\\[108px\\]{min-height:108px}.min-h-\\[120px\\]{min-height:120px}.min-h-\\[140px\\]{min-height:140px}.min-h-\\[220px\\]{min-height:220px}.w-0\\.5{width:.125rem}.w-1{width:.25rem}.w-1\\/2{width:50%}.w-10{width:2.5rem}.w-14{width:3.5rem}.w-2{width:.5rem}.w-3{width:.75rem}.w-3\\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-\\[1\\.4rem\\]{width:1.4rem}.w-\\[18px\\]{width:18px}.w-\\[21rem\\]{width:21rem}.w-\\[22rem\\]{width:22rem}.w-\\[30px\\]{width:30px}.w-\\[38px\\]{width:38px}.w-\\[calc\\(100vw-32px\\)\\]{width:calc(100vw - 32px)}.w-\\[min\\(560px\\,calc\\(100vw-32px\\)\\)\\]{width:min(560px,calc(100vw - 32px))}.w-\\[var\\(--radix-popover-trigger-width\\)\\]{width:var(--radix-popover-trigger-width)}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.min-w-0{min-width:0px}.min-w-9{min-width:2.25rem}.min-w-\\[12rem\\]{min-width:12rem}.min-w-\\[200px\\]{min-width:200px}.min-w-\\[var\\(--radix-popover-trigger-width\\)\\]{min-width:var(--radix-popover-trigger-width)}.min-w-\\[var\\(--radix-select-trigger-width\\)\\]{min-width:var(--radix-select-trigger-width)}.max-w-8{max-width:2rem}.max-w-\\[120px\\]{max-width:120px}.max-w-\\[160px\\]{max-width:160px}.max-w-\\[240px\\]{max-width:240px}.max-w-\\[280px\\]{max-width:280px}.max-w-\\[28rem\\]{max-width:28rem}.max-w-\\[300px\\]{max-width:300px}.max-w-\\[360px\\]{max-width:360px}.max-w-\\[36rem\\]{max-width:36rem}.max-w-\\[400px\\]{max-width:400px}.max-w-\\[420px\\]{max-width:420px}.max-w-\\[428px\\]{max-width:428px}.max-w-\\[480px\\]{max-width:480px}.max-w-\\[62ch\\]{max-width:62ch}.max-w-\\[640px\\]{max-width:640px}.max-w-\\[70ch\\]{max-width:70ch}.max-w-\\[90vw\\]{max-width:90vw}.max-w-\\[960px\\]{max-width:960px}.max-w-\\[calc\\(100vw-24px\\)\\]{max-width:calc(100vw - 24px)}.max-w-full{max-width:100%}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.caption-bottom{caption-side:bottom}.border-collapse{border-collapse:collapse}.-translate-x-1{--tw-translate-x: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-1\\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-1{--tw-translate-x: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\\[-50\\%\\]{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\\[18px\\]{--tw-translate-x: 18px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\\[2px\\]{--tw-translate-x: 2px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\\[-50\\%\\]{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes pulse-ring{0%,to{box-shadow:0 0 0 0 var(--brand-ring)}50%{box-shadow:0 0 0 8px transparent}}.animate-pulse-ring{animation:pulse-ring 1.8s var(--ease-in-out) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-col-resize{cursor:col-resize}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize-y{resize:vertical}.resize{resize:both}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.content-center{align-content:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0px}.gap-0\\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-3\\.5{gap:.875rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-x-5{-moz-column-gap:1.25rem;column-gap:1.25rem}.gap-y-2{row-gap:.5rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-line-subtle>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-divide-opacity, 1))}.self-start{align-self:flex-start}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.break-all{word-break:break-all}.\\!rounded-none{border-radius:0!important}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\\[18px\\]{border-radius:18px}.rounded-\\[20px\\]{border-radius:20px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-none{border-radius:0}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-xs{border-radius:var(--radius-xs)}.rounded-b-md{border-bottom-right-radius:var(--radius-md);border-bottom-left-radius:var(--radius-md)}.rounded-t-md{border-top-left-radius:var(--radius-md);border-top-right-radius:var(--radius-md)}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-y{border-top-width:1px;border-bottom-width:1px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-l-2{border-left-width:2px}.border-l-4{border-left-width:4px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-t-0{border-top-width:0px}.border-\\[hsl\\(144_8\\%_91\\%\\)\\]{--tw-border-opacity: 1;border-color:hsl(144 8% 91% / var(--tw-border-opacity, 1))}.border-brand{--tw-border-opacity: 1;border-color:hsl(var(--brand-hsl) / var(--tw-border-opacity, 1))}.border-brand-border{border-color:var(--brand-border)}.border-brand\\/30{border-color:hsl(var(--brand-hsl) / .3)}.border-brand\\/40{border-color:hsl(var(--brand-hsl) / .4)}.border-danger\\/20{border-color:hsl(var(--danger) / .2)}.border-danger\\/30{border-color:hsl(var(--danger) / .3)}.border-info\\/20{border-color:hsl(var(--info) / .2)}.border-info\\/30{border-color:hsl(var(--info) / .3)}.border-line{--tw-border-opacity: 1;border-color:hsl(var(--border-default) / var(--tw-border-opacity, 1))}.border-line-strong{--tw-border-opacity: 1;border-color:hsl(var(--border-strong) / var(--tw-border-opacity, 1))}.border-line-subtle{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}.border-line-subtle\\/50{border-color:hsl(var(--border-subtle) / .5)}.border-line-subtle\\/90{border-color:hsl(var(--border-subtle) / .9)}.border-slate-100{--tw-border-opacity: 1;border-color:rgb(241 245 249 / var(--tw-border-opacity, 1))}.border-slate-200{--tw-border-opacity: 1;border-color:rgb(226 232 240 / var(--tw-border-opacity, 1))}.border-success{--tw-border-opacity: 1;border-color:hsl(var(--success) / var(--tw-border-opacity, 1))}.border-success\\/20{border-color:hsl(var(--success) / .2)}.border-success\\/30{border-color:hsl(var(--success) / .3)}.border-text-primary{--tw-border-opacity: 1;border-color:hsl(var(--text-primary) / var(--tw-border-opacity, 1))}.border-transparent{border-color:transparent}.border-warning\\/20{border-color:hsl(var(--warning) / .2)}.border-warning\\/30{border-color:hsl(var(--warning) / .3)}.border-white\\/70{border-color:#ffffffb3}.border-white\\/80{border-color:#fffc}.border-white\\/90{border-color:#ffffffe6}.border-l-brand{--tw-border-opacity: 1;border-left-color:hsl(var(--brand-hsl) / var(--tw-border-opacity, 1))}.\\!bg-success-surface{background-color:hsl(var(--success-surface))!important}.bg-\\[var\\(--overlay-backdrop-strong\\)\\]{background-color:var(--overlay-backdrop-strong)}.bg-black\\/10{background-color:#0000001a}.bg-black\\/40{background-color:#0006}.bg-black\\/80{background-color:#000c}.bg-brand{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.bg-brand-subtle{background-color:var(--brand-subtle)}.bg-brand\\/10{background-color:hsl(var(--brand-hsl) / .1)}.bg-brand\\/5{background-color:hsl(var(--brand-hsl) / .05)}.bg-danger-subtle{background-color:hsl(var(--danger-subtle))}.bg-danger\\/10{background-color:hsl(var(--danger) / .1)}.bg-info-subtle{background-color:hsl(var(--info-subtle))}.bg-line{--tw-bg-opacity: 1;background-color:hsl(var(--border-default) / var(--tw-bg-opacity, 1))}.bg-line-subtle{--tw-bg-opacity: 1;background-color:hsl(var(--border-subtle) / var(--tw-bg-opacity, 1))}.bg-success{--tw-bg-opacity: 1;background-color:hsl(var(--success) / var(--tw-bg-opacity, 1))}.bg-success-subtle{background-color:hsl(var(--success-subtle))}.bg-success-surface{background-color:hsl(var(--success-surface))}.bg-surface-0{--tw-bg-opacity: 1;background-color:hsl(var(--surface-0) / var(--tw-bg-opacity, 1))}.bg-surface-1{--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.bg-surface-2{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.bg-surface-3{--tw-bg-opacity: 1;background-color:hsl(var(--surface-3) / var(--tw-bg-opacity, 1))}.bg-surface-inset{--tw-bg-opacity: 1;background-color:hsl(var(--surface-inset) / var(--tw-bg-opacity, 1))}.bg-text-primary{--tw-bg-opacity: 1;background-color:hsl(var(--text-primary) / var(--tw-bg-opacity, 1))}.bg-text-tertiary{--tw-bg-opacity: 1;background-color:hsl(var(--text-tertiary) / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.bg-warning-subtle{background-color:hsl(var(--warning-subtle))}.bg-warning\\/10{background-color:hsl(var(--warning) / .1)}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\\/10{background-color:#ffffff1a}.fill-text-primary{fill:hsl(var(--text-primary) / 1)}.stroke-\\[3\\]{stroke-width:3}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.\\!p-0{padding:0!important}.p-0{padding:0}.p-0\\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-3\\.5{padding:.875rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-7{padding:1.75rem}.p-8{padding:2rem}.p-\\[18px\\]{padding:18px}.px-0{padding-left:0;padding-right:0}.px-1\\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-9{padding-left:2.25rem;padding-right:2.25rem}.py-0\\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\\.5{padding-top:.375rem;padding-bottom:.375rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-1{padding-bottom:.25rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pl-3{padding-left:.75rem}.pl-4{padding-left:1rem}.pl-5{padding-left:1.25rem}.pl-8{padding-left:2rem}.pr-10{padding-right:2.5rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-2\\.5{padding-top:.625rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.align-middle{vertical-align:middle}.font-display{font-family:var(--font-display),ui-sans-serif,system-ui,sans-serif}.font-mono{font-family:var(--font-mono),ui-monospace,SFMono-Regular,Menlo,monospace}.font-sans{font-family:var(--font-sans),ui-sans-serif,system-ui,sans-serif}.text-2xs{font-size:10.5px;line-height:14px}.text-\\[0\\.72rem\\]{font-size:.72rem}.text-\\[1\\.45rem\\]{font-size:1.45rem}.text-\\[1\\.75rem\\]{font-size:1.75rem}.text-\\[10px\\]{font-size:10px}.text-base{font-size:14px;line-height:21px}.text-lg{font-size:17px;line-height:25px}.text-sm{font-size:13px;line-height:19px}.text-xl{font-size:20px;line-height:29px}.text-xs{font-size:12px;line-height:16px}.font-black{font-weight:900}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-4{line-height:1rem}.leading-5{line-height:1.25rem}.leading-8{line-height:2rem}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.text-\\[hsl\\(145_5\\%_42\\%\\)\\]{--tw-text-opacity: 1;color:hsl(145 5% 42% / var(--tw-text-opacity, 1))}.text-brand{--tw-text-opacity: 1;color:hsl(var(--brand-hsl) / var(--tw-text-opacity, 1))}.text-brand-fg{color:var(--brand-fg)}.text-brand\\/50{color:hsl(var(--brand-hsl) / .5)}.text-danger{--tw-text-opacity: 1;color:hsl(var(--danger) / var(--tw-text-opacity, 1))}.text-danger\\/80{color:hsl(var(--danger) / .8)}.text-info{--tw-text-opacity: 1;color:hsl(var(--info) / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-slate-400{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1))}.text-slate-500{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity, 1))}.text-slate-700{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity, 1))}.text-slate-900{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity, 1))}.text-success{--tw-text-opacity: 1;color:hsl(var(--success) / var(--tw-text-opacity, 1))}.text-text-disabled{--tw-text-opacity: 1;color:hsl(var(--text-disabled) / var(--tw-text-opacity, 1))}.text-text-inverse{--tw-text-opacity: 1;color:hsl(var(--text-inverse) / var(--tw-text-opacity, 1))}.text-text-primary{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.text-text-secondary{--tw-text-opacity: 1;color:hsl(var(--text-secondary) / var(--tw-text-opacity, 1))}.text-text-tertiary{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.text-transparent{color:transparent}.text-warning{--tw-text-opacity: 1;color:hsl(var(--warning) / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-white\\/90{color:#ffffffe6}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.underline-offset-2{text-underline-offset:2px}.underline-offset-4{text-underline-offset:4px}.accent-brand{accent-color:hsl(var(--brand-hsl) / 1)}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.\\!shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1) !important;--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color) !important;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)!important}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\\[0_24px_70px_-28px_rgba\\(16\\,24\\,18\\,0\\.45\\)\\]{--tw-shadow: 0 24px 70px -28px rgba(16,24,18,.45);--tw-shadow-colored: 0 24px 70px -28px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: var(--shadow-lg);--tw-shadow-colored: var(--shadow-lg);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: var(--shadow-md);--tw-shadow-colored: var(--shadow-md);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: var(--shadow-sm);--tw-shadow-colored: var(--shadow-sm);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: var(--shadow-xl);--tw-shadow-colored: var(--shadow-xl);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xs{--tw-shadow: var(--shadow-xs);--tw-shadow-colored: var(--shadow-xs);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.outline-2{outline-width:2px}.outline-offset-0{outline-offset:0px}.outline-transparent{outline-color:transparent}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-4{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-brand{--tw-ring-opacity: 1;--tw-ring-color: hsl(var(--brand-hsl) / var(--tw-ring-opacity, 1))}.ring-brand-subtle{--tw-ring-color: var(--brand-subtle)}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-\\[2px\\]{--tw-backdrop-blur: blur(2px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,border-color\\,color\\,box-shadow\\]{transition-property:background-color,border-color,color,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\,border-color\\,box-shadow\\,opacity\\]{transition-property:background-color,color,border-color,box-shadow,opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\,border-color\\,box-shadow\\]{transition-property:background-color,color,border-color,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\,box-shadow\\]{transition-property:background-color,color,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\]{transition-property:background-color,color;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[border-color\\,box-shadow\\,background-color\\]{transition-property:border-color,box-shadow,background-color;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[border-color\\,outline-color\\,box-shadow\\,background-color\\,transform\\]{transition-property:border-color,outline-color,box-shadow,background-color,transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[max-width\\,box-shadow\\,background-color\\,border-color\\,transform\\,opacity\\]{transition-property:max-width,box-shadow,background-color,border-color,transform,opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[max-width\\]{transition-property:max-width;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[opacity\\,transform\\]{transition-property:opacity,transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.duration-\\[var\\(--issue-marker-expand-duration\\)\\]{transition-duration:var(--issue-marker-expand-duration)}.duration-fast{transition-duration:var(--duration-fast)}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:var(--ease-in-out)}.ease-out{transition-timing-function:var(--ease-out)}@keyframes float-gentle{0%,to{transform:translateY(0)}50%{transform:translateY(-2px)}}@keyframes toast-slide{0%{opacity:0;transform:translateY(-14px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes gradient-shift{0%,to{background-position:0% 50%}50%{background-position:100% 50%}}.issue-overlay-shell{border:1px solid hsl(var(--border-subtle));border-radius:var(--radius-lg);background:hsl(var(--surface-1));box-shadow:var(--shadow-md)}.issue-marker-breathe{animation:float-gentle 4.8s var(--ease-in-out) infinite}.issue-marker-breathe:hover,.issue-marker-breathe:focus-visible,.issue-marker-breathe:focus-within{animation-play-state:paused}.marker\\:text-text-tertiary *::marker{color:hsl(var(--text-tertiary))}.marker\\:text-text-tertiary::marker{color:hsl(var(--text-tertiary))}.file\\:border-0::file-selector-button{border-width:0px}.file\\:bg-transparent::file-selector-button{background-color:transparent}.file\\:text-sm::file-selector-button{font-size:13px;line-height:19px}.file\\:font-medium::file-selector-button{font-weight:500}.file\\:text-text-primary::file-selector-button{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.placeholder\\:text-text-tertiary::-moz-placeholder{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.placeholder\\:text-text-tertiary::placeholder{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.focus-within\\:z-\\[10001\\]:focus-within{z-index:10001}.hover\\:z-\\[10001\\]:hover{z-index:10001}.hover\\:max-w-\\[160px\\]:hover{max-width:160px}.hover\\:max-w-\\[480px\\]:hover{max-width:480px}.hover\\:border-line:hover{--tw-border-opacity: 1;border-color:hsl(var(--border-default) / var(--tw-border-opacity, 1))}.hover\\:border-line-strong:hover{--tw-border-opacity: 1;border-color:hsl(var(--border-strong) / var(--tw-border-opacity, 1))}.hover\\:border-line-subtle:hover{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}.hover\\:bg-\\[hsl\\(144_8\\%_96\\%\\)\\]:hover{--tw-bg-opacity: 1;background-color:hsl(144 8% 96% / var(--tw-bg-opacity, 1))}.hover\\:bg-blue-500:hover{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.hover\\:bg-brand-hover:hover{background-color:var(--brand-hover)}.hover\\:bg-brand\\/40:hover{background-color:hsl(var(--brand-hsl) / .4)}.hover\\:bg-danger-subtle:hover{background-color:hsl(var(--danger-subtle))}.hover\\:bg-danger\\/10:hover{background-color:hsl(var(--danger) / .1)}.hover\\:bg-slate-100:hover{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity, 1))}.hover\\:bg-slate-50:hover{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity, 1))}.hover\\:bg-surface-2:hover{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.hover\\:bg-surface-2\\/60:hover{background-color:hsl(var(--surface-2) / .6)}.hover\\:bg-surface-3:hover{--tw-bg-opacity: 1;background-color:hsl(var(--surface-3) / var(--tw-bg-opacity, 1))}.hover\\:bg-surface-inset:hover{--tw-bg-opacity: 1;background-color:hsl(var(--surface-inset) / var(--tw-bg-opacity, 1))}.hover\\:bg-transparent:hover{background-color:transparent}.hover\\:bg-white\\/20:hover{background-color:#fff3}.hover\\:text-\\[hsl\\(150_10\\%_12\\%\\)\\]:hover{--tw-text-opacity: 1;color:hsl(150 10% 12% / var(--tw-text-opacity, 1))}.hover\\:text-brand-hover:hover{color:var(--brand-hover)}.hover\\:text-danger:hover{--tw-text-opacity: 1;color:hsl(var(--danger) / var(--tw-text-opacity, 1))}.hover\\:text-slate-900:hover{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity, 1))}.hover\\:text-text-primary:hover{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.hover\\:text-text-secondary:hover{--tw-text-opacity: 1;color:hsl(var(--text-secondary) / var(--tw-text-opacity, 1))}.hover\\:underline:hover{text-decoration-line:underline}.hover\\:opacity-90:hover{opacity:.9}.hover\\:shadow-xl:hover{--tw-shadow: var(--shadow-xl);--tw-shadow-colored: var(--shadow-xl);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus\\:border-brand:focus{--tw-border-opacity: 1;border-color:hsl(var(--brand-hsl) / var(--tw-border-opacity, 1))}.focus\\:bg-surface-2:focus{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.focus\\:text-text-primary:focus{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.focus\\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus-visible\\:max-w-\\[160px\\]:focus-visible{max-width:160px}.focus-visible\\:max-w-\\[480px\\]:focus-visible{max-width:480px}.focus-visible\\:border-line-focus:focus-visible{--tw-border-opacity: 1;border-color:hsl(var(--border-focus) / var(--tw-border-opacity, 1))}.focus-visible\\:border-transparent:focus-visible{border-color:transparent}.focus-visible\\:bg-slate-50:focus-visible{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity, 1))}.focus-visible\\:bg-surface-1:focus-visible{--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.focus-visible\\:bg-surface-2:focus-visible{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.focus-visible\\:text-text-primary:focus-visible{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.focus-visible\\:shadow-focus:focus-visible{--tw-shadow: var(--shadow-focus);--tw-shadow-colored: var(--shadow-focus);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus-visible\\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\\:outline-line-focus:focus-visible{outline-color:hsl(var(--border-focus) / 1)}.focus-visible\\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\\:ring-4:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\\:ring-brand-subtle:focus-visible{--tw-ring-color: var(--brand-subtle)}.focus-visible\\:ring-white\\/40:focus-visible{--tw-ring-color: rgb(255 255 255 / .4)}.active\\:bg-brand-active:active{background-color:var(--brand-active)}.active\\:bg-brand\\/60:active{background-color:hsl(var(--brand-hsl) / .6)}.disabled\\:pointer-events-none:disabled{pointer-events:none}.disabled\\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\\:translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\\:opacity-100{opacity:1}.group:focus-visible .group-focus-visible\\:translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:focus-visible .group-focus-visible\\:opacity-100{opacity:1}.group.toaster .group-\\[\\.toaster\\]\\:isolate{isolation:isolate}.group.toast .group-\\[\\.toast\\]\\:rounded-md,.group.toaster .group-\\[\\.toaster\\]\\:rounded-md{border-radius:var(--radius-md)}.group.toaster .group-\\[\\.toaster\\]\\:border{border-width:1px}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-danger\\/30{border-color:hsl(var(--danger) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-info\\/30{border-color:hsl(var(--info) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-success\\/30{border-color:hsl(var(--success) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-warning\\/30{border-color:hsl(var(--warning) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:border-line-subtle{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}.group.toast .group-\\[\\.toast\\]\\:bg-brand{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.group.toast .group-\\[\\.toast\\]\\:bg-surface-2{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-danger-subtle{background-color:hsl(var(--danger-subtle))!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-info-subtle{background-color:hsl(var(--info-subtle))!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-success-surface{background-color:hsl(var(--success-surface))!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-warning-subtle{background-color:hsl(var(--warning-subtle))!important}.group.toaster .group-\\[\\.toaster\\]\\:bg-surface-1{--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:px-4{padding-left:1rem;padding-right:1rem}.group.toaster .group-\\[\\.toaster\\]\\:py-3{padding-top:.75rem;padding-bottom:.75rem}.group.toast .group-\\[\\.toast\\]\\:text-sm{font-size:13px;line-height:19px}.group.toast .group-\\[\\.toast\\]\\:text-xs{font-size:12px;line-height:16px}.group.toast .group-\\[\\.toast\\]\\:font-medium{font-weight:500}.group.toast .group-\\[\\.toast\\]\\:text-brand-fg{color:var(--brand-fg)}.group.toast .group-\\[\\.toast\\]\\:text-text-primary{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.group.toast .group-\\[\\.toast\\]\\:text-text-secondary{--tw-text-opacity: 1;color:hsl(var(--text-secondary) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:text-text-primary{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:shadow-sm{--tw-shadow: var(--shadow-sm);--tw-shadow-colored: var(--shadow-sm);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.group.toaster .group-\\[\\.toaster\\]\\:before\\:absolute:before{content:var(--tw-content);position:absolute}.group.toaster .group-\\[\\.toaster\\]\\:before\\:inset-0:before{content:var(--tw-content);top:0;right:0;bottom:0;left:0}.group.toaster .group-\\[\\.toaster\\]\\:before\\:-z-10:before{content:var(--tw-content);z-index:-10}.group.toaster .group-\\[\\.toaster\\]\\:before\\:rounded-md:before{content:var(--tw-content);border-radius:var(--radius-md)}.group.toaster .group-\\[\\.toaster\\]\\:before\\:bg-surface-1:before{content:var(--tw-content);--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:before\\:content-\\[\\'\\'\\]:before{--tw-content: "";content:var(--tw-content)}.peer:focus-visible~.peer-focus-visible\\:shadow-focus{--tw-shadow: var(--shadow-focus);--tw-shadow-colored: var(--shadow-focus);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.peer:disabled~.peer-disabled\\:cursor-not-allowed{cursor:not-allowed}.peer:disabled~.peer-disabled\\:opacity-60{opacity:.6}.aria-disabled\\:pointer-events-none[aria-disabled=true]{pointer-events:none}.aria-disabled\\:opacity-40[aria-disabled=true]{opacity:.4}.data-\\[disabled\\]\\:pointer-events-none[data-disabled]{pointer-events:none}@keyframes dialog-out{0%{opacity:1;transform:translate(-50%,-50%) scale(1)}to{opacity:0;transform:translate(-50%,calc(-50% + 8px)) scale(.985)}}.data-\\[state\\=closed\\]\\:animate-dialog-out[data-state=closed]{animation:dialog-out var(--duration-out) var(--ease-out) forwards}@keyframes fade-out{0%{opacity:1}to{opacity:0}}.data-\\[state\\=closed\\]\\:animate-fade-out[data-state=closed]{animation:fade-out var(--duration-out) var(--ease-out) forwards}@keyframes scale-out{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.97)}}.data-\\[state\\=closed\\]\\:animate-scale-out[data-state=closed]{animation:scale-out var(--duration-out) var(--ease-out) forwards}@keyframes sheet-out-left{0%{transform:translate(0)}to{transform:translate(-100%);opacity:.6}}.data-\\[state\\=closed\\]\\:animate-sheet-out-left[data-state=closed]{animation:sheet-out-left var(--duration-base) var(--ease-out) forwards}@keyframes sheet-out-right{0%{transform:translate(0);opacity:1}to{transform:translate(100%);opacity:.6}}.data-\\[state\\=closed\\]\\:animate-sheet-out-right[data-state=closed]{animation:sheet-out-right var(--duration-base) var(--ease-out) forwards}.data-\\[state\\=delayed-open\\]\\:animate-scale-in[data-state=delayed-open]{animation:scale-in var(--duration-base) var(--ease-out) forwards}@keyframes dialog-in{0%{opacity:0;transform:translate(-50%,calc(-50% + 12px)) scale(.985)}to{opacity:1;transform:translate(-50%,-50%) scale(1)}}.data-\\[state\\=open\\]\\:animate-dialog-in[data-state=open]{animation:dialog-in var(--duration-base) var(--ease-out) forwards}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.data-\\[state\\=open\\]\\:animate-fade-in[data-state=open]{animation:fade-in var(--duration-base) var(--ease-out) forwards}@keyframes scale-in{0%{opacity:0;transform:scale(.98)}to{opacity:1;transform:scale(1)}}.data-\\[state\\=open\\]\\:animate-scale-in[data-state=open]{animation:scale-in var(--duration-base) var(--ease-out) forwards}@keyframes sheet-in-left{0%{transform:translate(-100%);opacity:.6}to{transform:translate(0);opacity:1}}.data-\\[state\\=open\\]\\:animate-sheet-in-left[data-state=open]{animation:sheet-in-left var(--duration-base) var(--ease-out) forwards}@keyframes sheet-in-right{0%{transform:translate(100%);opacity:.6}to{transform:translate(0)}}.data-\\[state\\=open\\]\\:animate-sheet-in-right[data-state=open]{animation:sheet-in-right var(--duration-base) var(--ease-out) forwards}.data-\\[range-end\\=true\\]\\:rounded-md[data-range-end=true]{border-radius:var(--radius-md)}.data-\\[range-middle\\=true\\]\\:rounded-none[data-range-middle=true]{border-radius:0}.data-\\[range-start\\=true\\]\\:rounded-md[data-range-start=true]{border-radius:var(--radius-md)}.data-\\[state\\=open\\]\\:border-line-focus[data-state=open]{--tw-border-opacity: 1;border-color:hsl(var(--border-focus) / var(--tw-border-opacity, 1))}.data-\\[highlighted\\]\\:bg-surface-2[data-highlighted]{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.data-\\[range-end\\=true\\]\\:bg-brand[data-range-end=true]{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.data-\\[range-middle\\=true\\]\\:bg-transparent[data-range-middle=true]{background-color:transparent}.data-\\[range-start\\=true\\]\\:bg-brand[data-range-start=true],.data-\\[selected-single\\=true\\]\\:bg-brand[data-selected-single=true]{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.data-\\[state\\=selected\\]\\:bg-brand-subtle[data-state=selected]{background-color:var(--brand-subtle)}.data-\\[today\\=true\\]\\:font-semibold[data-today=true]{font-weight:600}.data-\\[highlighted\\]\\:text-text-primary[data-highlighted]{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.data-\\[placeholder\\]\\:text-text-tertiary[data-placeholder]{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.data-\\[range-end\\=true\\]\\:text-brand-fg[data-range-end=true]{color:var(--brand-fg)}.data-\\[range-middle\\=true\\]\\:text-text-primary[data-range-middle=true]{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.data-\\[range-start\\=true\\]\\:text-brand-fg[data-range-start=true],.data-\\[selected-single\\=true\\]\\:text-brand-fg[data-selected-single=true]{color:var(--brand-fg)}.data-\\[state\\=active\\]\\:text-text-primary[data-state=active],.data-\\[state\\=checked\\]\\:text-text-primary[data-state=checked]{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.data-\\[today\\=true\\]\\:text-brand[data-today=true]{--tw-text-opacity: 1;color:hsl(var(--brand-hsl) / var(--tw-text-opacity, 1))}.data-\\[disabled\\]\\:opacity-50[data-disabled]{opacity:.5}.data-\\[state\\=open\\]\\:shadow-focus[data-state=open]{--tw-shadow: var(--shadow-focus);--tw-shadow-colored: var(--shadow-focus);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.data-\\[range-end\\=true\\]\\:hover\\:bg-brand-hover:hover[data-range-end=true],.data-\\[range-start\\=true\\]\\:hover\\:bg-brand-hover:hover[data-range-start=true],.data-\\[selected-single\\=true\\]\\:hover\\:bg-brand-hover:hover[data-selected-single=true]{background-color:var(--brand-hover)}.data-\\[range-end\\=true\\]\\:hover\\:text-brand-fg:hover[data-range-end=true],.data-\\[range-start\\=true\\]\\:hover\\:text-brand-fg:hover[data-range-start=true],.data-\\[selected-single\\=true\\]\\:hover\\:text-brand-fg:hover[data-selected-single=true]{color:var(--brand-fg)}@media(prefers-reduced-motion:reduce){.motion-reduce\\:animate-none{animation:none}}@media(min-width:640px){.sm\\:flex-row{flex-direction:row}.sm\\:items-start{align-items:flex-start}.sm\\:items-center{align-items:center}.sm\\:justify-end{justify-content:flex-end}.sm\\:justify-between{justify-content:space-between}.sm\\:gap-2\\.5{gap:.625rem}.sm\\:p-5{padding:1.25rem}.sm\\:p-6{padding:1.5rem}.sm\\:text-2xl{font-size:26px;line-height:34px}.sm\\:text-\\[2\\.1rem\\]{font-size:2.1rem}}@media(min-width:768px){.md\\:flex{display:flex}.md\\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\\:grid-cols-\\[minmax\\(0\\,1fr\\)_minmax\\(260px\\,340px\\)\\]{grid-template-columns:minmax(0,1fr) minmax(260px,340px)}}.\\[\\&\\>\\*\\:not\\(summary\\)\\]\\:pl-4>*:not(summary){padding-left:1rem}.\\[\\&\\>span\\]\\:line-clamp-1>span{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.\\[\\&\\>tr\\]\\:last\\:border-b-0:last-child>tr{border-bottom-width:0px}.\\[\\&\\[data-state\\=open\\]\\>span\\[data-chevron\\]\\]\\:rotate-180[data-state=open]>span[data-chevron]{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-danger [data-icon]{--tw-text-opacity: 1;color:hsl(var(--danger) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-info [data-icon]{--tw-text-opacity: 1;color:hsl(var(--info) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-success [data-icon]{--tw-text-opacity: 1;color:hsl(var(--success) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-warning [data-icon]{--tw-text-opacity: 1;color:hsl(var(--warning) / var(--tw-text-opacity, 1))}.\\[\\&_tr\\]\\:border-b tr{border-bottom-width:1px}.\\[\\&_tr\\]\\:border-line-subtle tr{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}`;
|
|
38082
|
+
const globalsCSS = `:root,:host{color-scheme:light;--brand-h: 150;--brand-s: 100%;--brand-l: 34%;--brand-hsl: var(--brand-h) var(--brand-s) var(--brand-l);--brand: hsl(var(--brand-hsl));--brand-hover: hsl(var(--brand-h) calc(var(--brand-s) + 3%) calc(var(--brand-l) - 4%));--brand-active: hsl(var(--brand-h) calc(var(--brand-s) + 2%) calc(var(--brand-l) - 8%));--brand-subtle: hsl(var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .14);--brand-border: hsl(var(--brand-h) calc(var(--brand-s) + 8%) calc(var(--brand-l) + 8%) / .34);--brand-fg: hsl(0 0% 100%);--brand-ring: hsl(var(--brand-h) calc(var(--brand-s) + 12%) calc(var(--brand-l) + 10%) / .22);--font-sans: "Pretendard", -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;--font-display: var(--font-sans);--font-mono: var(--font-sans);--surface-0: 0 0% 99%;--surface-1: 0 0% 100%;--surface-2: 144 8% 96%;--surface-3: 144 6% 93%;--surface-inset: 144 6% 95%;--overlay-backdrop: hsl(0 0% 0% / .24);--overlay-backdrop-strong: hsl(0 0% 0% / .48);--text-primary: 150 10% 12%;--text-secondary: 148 6% 36%;--text-tertiary: 145 5% 42%;--text-disabled: 145 4% 70%;--text-inverse: 0 0% 100%;--border-subtle: 144 8% 91%;--border-default: 144 6% 85%;--border-strong: 144 5% 72%;--border-focus: var(--brand-h) var(--brand-s) var(--brand-l);--success: var(--brand-h) var(--brand-s) var(--brand-l);--success-subtle: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .14;--success-surface: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .24;--warning: 34 82% 52%;--warning-subtle: 34 82% 52% / .14;--danger: 3 68% 56%;--danger-subtle: 3 68% 56% / .12;--info: 202 52% 44%;--info-subtle: 202 52% 44% / .12;--accent-terra: 13 52% 47%;--accent-terra-subtle: 13 52% 47% / .1;--accent-terra-deep: 13 48% 44%;--accent-blue: 213 86% 56%;--accent-blue-subtle: 213 92% 56% / .12;--accent-blue-deep: 216 78% 40%;--accent-blue-border: 213 86% 62% / .36;--accent-cream: 38 52% 88%;--accent-cream-warm: 40 56% 95%;--accent-cream-deep: 38 48% 82%;--accent-highlight: 55 96% 70%;--accent-ink: 32 13% 11%;--radius-xs: 4px;--radius-sm: 8px;--radius-md: 12px;--radius-lg: 16px;--radius-xl: 20px;--radius-2xl: 24px;--radius-pill: 9999px;--shadow-xs: 0 1px 2px 0 hsl(0 0% 0% / .04);--shadow-sm: 0 1px 3px 0 hsl(0 0% 0% / .06), 0 1px 2px -1px hsl(0 0% 0% / .06);--shadow-md: 0 4px 6px -1px hsl(0 0% 0% / .06), 0 2px 4px -2px hsl(0 0% 0% / .04);--shadow-lg: 0 10px 15px -3px hsl(0 0% 0% / .06), 0 4px 6px -4px hsl(0 0% 0% / .04);--shadow-xl: 0 20px 25px -5px hsl(0 0% 0% / .06), 0 8px 10px -6px hsl(0 0% 0% / .04);--shadow-focus: 0 0 0 3px var(--brand-ring);--shadow-inset: inset 0 1px 2px 0 hsl(0 0% 0% / .04);--shadow-brand: 0 2px 8px hsl(var(--brand-h) calc(var(--brand-s) - 60%) calc(var(--brand-l) - 14%) / .24), 0 6px 20px hsl(var(--brand-h) calc(var(--brand-s) - 70%) calc(var(--brand-l) - 19%) / .16);--duration-instant: 90ms;--duration-fast: .16s;--duration-base: .26s;--duration-out: .18s;--duration-slow: .36s;--ease-out: cubic-bezier(.23, 1, .32, 1);--ease-in-out: cubic-bezier(.45, 0, .15, 1);--ease-spring: cubic-bezier(.18, .94, .32, 1.08);--grid-line: 0 0% 92%}.dark,:host(.dark){color-scheme:dark;--brand-l: 34%;--brand-fg: hsl(0 0% 100%);--surface-0: 150 8% 7%;--surface-1: 150 6% 10%;--surface-2: 150 5% 14%;--surface-3: 150 4% 18%;--surface-inset: 150 6% 6%;--overlay-backdrop: hsl(0 0% 0% / .56);--overlay-backdrop-strong: hsl(0 0% 0% / .8);--text-primary: 40 16% 93%;--text-secondary: 36 8% 68%;--text-tertiary: 34 6% 50%;--text-disabled: 30 5% 34%;--text-inverse: 150 8% 10%;--border-subtle: 150 6% 16%;--border-default: 150 5% 22%;--border-strong: 150 4% 34%;--success: var(--brand-h) var(--brand-s) var(--brand-l);--success-subtle: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .14;--success-surface: var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 14%) / .24;--warning: 34 82% 62%;--danger: 2 70% 64%;--info: 202 54% 62%;--accent-terra: 13 56% 62%;--accent-terra-subtle: 13 56% 62% / .14;--accent-terra-deep: 13 52% 56%;--accent-blue: 210 92% 68%;--accent-blue-subtle: 210 92% 68% / .18;--accent-blue-deep: 209 100% 78%;--accent-blue-border: 210 92% 72% / .44;--accent-cream: 38 30% 26%;--accent-cream-warm: 38 22% 18%;--accent-cream-deep: 38 26% 32%;--accent-highlight: 55 96% 70%;--accent-ink: 32 13% 8%;--shadow-xs: 0 1px 2px 0 hsl(0 0% 0% / .2);--shadow-sm: 0 1px 3px 0 hsl(0 0% 0% / .3), 0 1px 2px -1px hsl(0 0% 0% / .24);--shadow-md: 0 4px 6px -1px hsl(0 0% 0% / .34), 0 2px 4px -2px hsl(0 0% 0% / .2);--shadow-lg: 0 10px 15px -3px hsl(0 0% 0% / .38), 0 4px 6px -4px hsl(0 0% 0% / .24);--shadow-xl: 0 20px 25px -5px hsl(0 0% 0% / .44), 0 8px 10px -6px hsl(0 0% 0% / .28);--shadow-inset: inset 0 1px 2px 0 hsl(0 0% 0% / .16);--shadow-brand: 0 2px 8px hsl(var(--brand-h) calc(var(--brand-s) - 60%) calc(var(--brand-l) - 24%) / .44), 0 6px 20px hsl(0 0% 0% / .32);--grid-line: 150 6% 14%}*{border-color:hsl(var(--border-default))}html{font-family:var(--font-sans),ui-sans-serif,system-ui,-apple-system,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;font-feature-settings:"cv11","ss01","ss03";background-color:hsl(var(--surface-0))}body{margin:0;min-height:100vh;color:hsl(var(--text-primary));background-color:hsl(var(--surface-0))}::-moz-selection{background-color:hsl(var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 16%) / .22);color:hsl(var(--text-primary))}::selection{background-color:hsl(var(--brand-h) calc(var(--brand-s) + 6%) calc(var(--brand-l) + 16%) / .22);color:hsl(var(--text-primary))}code,kbd,samp,pre{font-family:var(--font-mono),ui-monospace,SFMono-Regular,Menlo,monospace;font-feature-settings:"ss01","ss02","cv11"}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:hsl(var(--border-strong) / .52);border-radius:var(--radius-pill);border:2px solid transparent;background-clip:padding-box}::-webkit-scrollbar-thumb:hover{background:hsl(var(--border-strong) / .9);background-clip:padding-box;border:2px solid transparent}.app-canvas,.grid-canvas{background-color:hsl(var(--surface-0))}.onboarding-canvas{--surface-0: var(--brand-h) var(--brand-s) var(--brand-l);--surface-1: 0 0% 100%;--surface-2: var(--brand-h) 62% 28%;--surface-3: var(--brand-h) 60% 25%;--surface-inset: var(--brand-h) 62% 28%;--text-primary: 0 0% 100%;--text-secondary: var(--brand-h) 46% 90%;--text-tertiary: var(--brand-h) 34% 84%;--text-disabled: var(--brand-h) 20% 72%;--border-subtle: var(--brand-h) 44% 52%;--border-default: var(--brand-h) 40% 58%;--border-strong: var(--brand-h) 36% 70%;--border-focus: 0 0% 100%;--brand-hsl: 0 0% 100%;--brand: hsl(var(--brand-hsl));--brand-hover: hsl(var(--brand-h) 24% 94%);--brand-active: hsl(var(--brand-h) 20% 88%);--brand-fg: hsl(var(--brand-h) var(--brand-s) 24%);--brand-ring: hsl(0 0% 100% / .4);--danger: 6 96% 86%;--danger-subtle: 6 96% 86% / .18;--warning: 42 96% 82%;--warning-subtle: 42 96% 82% / .18}.onboarding-canvas .bg-surface-1,.onboarding-canvas input,.onboarding-canvas textarea,.onboarding-canvas [role=combobox]{--text-primary: 150 10% 12%;--text-secondary: 148 6% 36%;--text-tertiary: 145 5% 42%;--surface-2: 144 8% 96%;--surface-inset: 144 6% 95%;--border-subtle: 144 8% 91%;--border-default: 144 6% 85%;--brand-hsl: var(--brand-h) var(--brand-s) var(--brand-l);--brand: hsl(var(--brand-hsl));--brand-hover: hsl(var(--brand-h) calc(var(--brand-s) + 3%) calc(var(--brand-l) - 4%));--brand-active: hsl(var(--brand-h) calc(var(--brand-s) + 2%) calc(var(--brand-l) - 8%));--brand-fg: hsl(0 0% 100%);--brand-ring: hsl(var(--brand-h) calc(var(--brand-s) + 12%) calc(var(--brand-l) + 10%) / .22)}@keyframes onboarding-step-in{0%{opacity:0;transform:translate(96px)}to{opacity:1;transform:translate(0)}}.onboarding-step-in{animation:onboarding-step-in var(--duration-slow) var(--ease-out) forwards}@keyframes onboarding-enter-up{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.onboarding-enter{position:fixed;top:0;right:0;bottom:0;left:0;overflow-x:hidden;overflow-y:auto;animation:onboarding-enter-up var(--duration-base) var(--ease-out) forwards}@keyframes onboarding-confetti-x{0%{transform:translate(0)}to{transform:translate(var(--confetti-x))}}@keyframes onboarding-confetti-y{0%{transform:translateY(0);animation-timing-function:cubic-bezier(.12,.66,.32,1)}42%{transform:translateY(var(--confetti-lift));animation-timing-function:cubic-bezier(.58,0,.86,.32)}to{transform:translateY(var(--confetti-drop))}}@keyframes onboarding-confetti-piece{0%{opacity:0;transform:scale(.7) rotate(0)}6%{opacity:1}72%{opacity:1}to{opacity:0;transform:scale(1) rotate(var(--confetti-spin))}}.onboarding-confetti-x,.onboarding-confetti-y,.onboarding-confetti-piece{--confetti-duration: 1.9s;animation-duration:var(--confetti-duration);animation-delay:var(--confetti-delay, 0ms);animation-fill-mode:both}.onboarding-confetti-x{animation-name:onboarding-confetti-x;animation-timing-function:cubic-bezier(.08,.62,.3,1)}.onboarding-confetti-y{animation-name:onboarding-confetti-y;animation-timing-function:linear}.onboarding-confetti-piece{width:var(--confetti-size);height:var(--confetti-size);border-radius:var(--radius-pill) var(--radius-xs) var(--radius-pill) var(--radius-pill);animation-name:onboarding-confetti-piece;animation-timing-function:linear}@media(prefers-reduced-motion:reduce){.onboarding-confetti-x,.onboarding-confetti-y,.onboarding-confetti-piece{animation:none;opacity:0}}body:has(.onboarding-canvas){background-color:hsl(var(--brand-h) var(--brand-s) var(--brand-l))}.panel-shell,.surface-shell{border:1px solid hsl(var(--border-subtle));border-radius:var(--radius-xl);background:hsl(var(--surface-1));box-shadow:var(--shadow-sm)}.panel-shell-muted,.surface-shell-muted{background:hsl(var(--surface-2));box-shadow:var(--shadow-xs)}.panel-shell-subtle{border:1px solid hsl(var(--border-subtle));border-radius:var(--radius-lg);background:hsl(var(--surface-1));box-shadow:var(--shadow-xs)}.panel-shell-elevated{border:1px solid hsl(var(--border-default));border-radius:var(--radius-xl);background:hsl(var(--surface-1));box-shadow:var(--shadow-md)}.utility-chip,.floating-chip{display:inline-flex;align-items:center;gap:.5rem;border:1px solid hsl(var(--border-default));border-radius:var(--radius-pill);background:hsl(var(--surface-1));box-shadow:var(--shadow-xs)}.hairline{border-bottom:1px solid hsl(var(--border-subtle))}.mono-label{font-family:var(--font-mono),ui-monospace,monospace;font-size:11px;text-transform:uppercase;color:hsl(var(--text-tertiary))}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--font-sans),ui-sans-serif,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--font-mono),ui-monospace,SFMono-Regular,Menlo,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root,:host{--font-sans: "Pretendard", -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;--font-mono: var(--font-sans);--issue-marker-expand-duration: .52s;--surface-0: 0 0% 99%;--surface-1: 0 0% 100%;--surface-2: 144 8% 96%;--surface-3: 144 6% 93%;--surface-inset: 144 6% 95%;--overlay-backdrop: hsl(0 0% 0% / .24);--overlay-backdrop-strong: hsl(0 0% 0% / .48);--text-primary: 150 10% 12%;--text-secondary: 148 6% 36%;--text-tertiary: 145 5% 52%;--text-disabled: 145 4% 70%;--border-subtle: 144 8% 91%;--border-default: 144 6% 85%;--border-strong: 144 5% 72%;--grid-line: 0 0% 92%;--shadow-xs: 0 1px 2px 0 hsl(0 0% 0% / .04);--shadow-sm: 0 1px 3px 0 hsl(0 0% 0% / .06), 0 1px 2px -1px hsl(0 0% 0% / .06);--shadow-md: 0 4px 6px -1px hsl(0 0% 0% / .06), 0 2px 4px -2px hsl(0 0% 0% / .04);--shadow-lg: 0 10px 15px -3px hsl(0 0% 0% / .06), 0 4px 6px -4px hsl(0 0% 0% / .04);--shadow-xl: 0 20px 25px -5px hsl(0 0% 0% / .06), 0 8px 10px -6px hsl(0 0% 0% / .04);--shadow-focus: 0 0 0 4px var(--brand-ring);--shadow-inset: inset 0 1px 2px 0 hsl(0 0% 0% / .04)}*{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}#issue-sticker-shadow-root{background-color:transparent;--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.\\!container{width:100%!important}.container{width:100%}@media(min-width:640px){.\\!container{max-width:640px!important}.container{max-width:640px}}@media(min-width:768px){.\\!container{max-width:768px!important}.container{max-width:768px}}@media(min-width:1024px){.\\!container{max-width:1024px!important}.container{max-width:1024px}}@media(min-width:1280px){.\\!container{max-width:1280px!important}.container{max-width:1280px}}@media(min-width:1536px){.\\!container{max-width:1536px!important}.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.\\!visible{visibility:visible!important}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-x-0{left:0;right:0}.inset-x-1{left:.25rem;right:.25rem}.inset-y-0{top:0;bottom:0}.-bottom-px{bottom:-1px}.bottom-0{bottom:0}.bottom-4{bottom:1rem}.bottom-6{bottom:1.5rem}.left-0{left:0}.left-1\\/2{left:50%}.left-2{left:.5rem}.left-4{left:1rem}.left-\\[50\\%\\]{left:50%}.right-0{right:0}.right-2{right:.5rem}.right-3{right:.75rem}.right-4{right:1rem}.right-5{right:1.25rem}.right-6{right:1.5rem}.top-0{top:0}.top-1{top:.25rem}.top-1\\/2{top:50%}.top-2{top:.5rem}.top-3{top:.75rem}.top-4{top:1rem}.top-5{top:1.25rem}.top-\\[50\\%\\]{top:50%}.top-\\[calc\\(\\(3\\.5rem-1\\.75rem\\)\\/2\\)\\]{top:.875rem}.top-full{top:100%}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.z-\\[1000000\\]{z-index:1000000}.z-\\[1000003\\]{z-index:1000003}.z-\\[1000004\\]{z-index:1000004}.z-\\[1000005\\]{z-index:1000005}.z-\\[1000006\\]{z-index:1000006}.z-\\[1000007\\]{z-index:1000007}.z-\\[1000008\\]{z-index:1000008}.z-\\[1000010\\]{z-index:1000010}.z-\\[1000011\\]{z-index:1000011}.z-\\[10001\\]{z-index:10001}.z-\\[999999\\]{z-index:999999}.z-\\[9999\\]{z-index:9999}.m-0{margin:0}.-mx-2{margin-left:-.5rem;margin-right:-.5rem}.mx-3{margin-left:.75rem;margin-right:.75rem}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-2\\.5{margin-top:.625rem;margin-bottom:.625rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.mb-0\\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-5{margin-bottom:1.25rem}.ml-0\\.5{margin-left:.125rem}.ml-4{margin-left:1rem}.mr-1\\.5{margin-right:.375rem}.mt-0{margin-top:0}.mt-0\\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.aspect-square{aspect-ratio:1 / 1}.\\!h-auto{height:auto!important}.h-1\\.5{height:.375rem}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-2{height:.5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-3\\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\\[1\\.4rem\\]{height:1.4rem}.h-\\[100vh\\]{height:100vh}.h-\\[18px\\]{height:18px}.h-\\[220px\\]{height:220px}.h-\\[22px\\]{height:22px}.h-\\[30px\\]{height:30px}.h-\\[min\\(36vh\\,320px\\)\\]{height:min(36vh,320px)}.h-\\[min\\(480px\\,calc\\(100vh-64px\\)\\)\\]{height:min(480px,calc(100vh - 64px))}.h-\\[min\\(54vh\\,520px\\)\\]{height:min(54vh,520px)}.h-\\[min\\(560px\\,calc\\(100vh-32px\\)\\)\\]{height:min(560px,calc(100vh - 32px))}.h-\\[var\\(--radix-select-trigger-height\\)\\]{height:var(--radix-select-trigger-height)}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.max-h-24{max-height:6rem}.max-h-40{max-height:10rem}.max-h-56{max-height:14rem}.max-h-96{max-height:24rem}.max-h-\\[150px\\]{max-height:150px}.max-h-\\[220px\\]{max-height:220px}.max-h-\\[320px\\]{max-height:320px}.max-h-\\[420px\\]{max-height:420px}.max-h-\\[90vh\\]{max-height:90vh}.max-h-\\[calc\\(100vh-3rem\\)\\]{max-height:calc(100vh - 3rem)}.max-h-\\[min\\(80vh\\,640px\\)\\]{max-height:min(80vh,640px)}.min-h-0{min-height:0px}.min-h-11{min-height:2.75rem}.min-h-\\[108px\\]{min-height:108px}.min-h-\\[120px\\]{min-height:120px}.min-h-\\[140px\\]{min-height:140px}.min-h-\\[220px\\]{min-height:220px}.w-0\\.5{width:.125rem}.w-1{width:.25rem}.w-1\\.5{width:.375rem}.w-1\\/2{width:50%}.w-10{width:2.5rem}.w-14{width:3.5rem}.w-2{width:.5rem}.w-3{width:.75rem}.w-3\\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-80{width:20rem}.w-9{width:2.25rem}.w-\\[1\\.4rem\\]{width:1.4rem}.w-\\[18px\\]{width:18px}.w-\\[21rem\\]{width:21rem}.w-\\[22rem\\]{width:22rem}.w-\\[30px\\]{width:30px}.w-\\[38px\\]{width:38px}.w-\\[calc\\(100vw-32px\\)\\]{width:calc(100vw - 32px)}.w-\\[min\\(560px\\,calc\\(100vw-32px\\)\\)\\]{width:min(560px,calc(100vw - 32px))}.w-\\[var\\(--radix-popover-trigger-width\\)\\]{width:var(--radix-popover-trigger-width)}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.min-w-0{min-width:0px}.min-w-9{min-width:2.25rem}.min-w-\\[12rem\\]{min-width:12rem}.min-w-\\[200px\\]{min-width:200px}.min-w-\\[var\\(--radix-popover-trigger-width\\)\\]{min-width:var(--radix-popover-trigger-width)}.min-w-\\[var\\(--radix-select-trigger-width\\)\\]{min-width:var(--radix-select-trigger-width)}.max-w-8{max-width:2rem}.max-w-\\[120px\\]{max-width:120px}.max-w-\\[160px\\]{max-width:160px}.max-w-\\[280px\\]{max-width:280px}.max-w-\\[28rem\\]{max-width:28rem}.max-w-\\[300px\\]{max-width:300px}.max-w-\\[360px\\]{max-width:360px}.max-w-\\[36rem\\]{max-width:36rem}.max-w-\\[400px\\]{max-width:400px}.max-w-\\[420px\\]{max-width:420px}.max-w-\\[428px\\]{max-width:428px}.max-w-\\[480px\\]{max-width:480px}.max-w-\\[62ch\\]{max-width:62ch}.max-w-\\[640px\\]{max-width:640px}.max-w-\\[70ch\\]{max-width:70ch}.max-w-\\[90vw\\]{max-width:90vw}.max-w-\\[960px\\]{max-width:960px}.max-w-\\[calc\\(100vw-24px\\)\\]{max-width:calc(100vw - 24px)}.max-w-full{max-width:100%}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.grow{flex-grow:1}.caption-bottom{caption-side:bottom}.border-collapse{border-collapse:collapse}.-translate-x-1{--tw-translate-x: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-1\\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-1{--tw-translate-x: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\\[-50\\%\\]{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\\[18px\\]{--tw-translate-x: 18px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\\[2px\\]{--tw-translate-x: 2px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\\[-50\\%\\]{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes pulse-ring{0%,to{box-shadow:0 0 0 0 var(--brand-ring)}50%{box-shadow:0 0 0 8px transparent}}.animate-pulse-ring{animation:pulse-ring 1.8s var(--ease-in-out) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-col-resize{cursor:col-resize}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize-y{resize:vertical}.resize{resize:both}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.content-center{align-content:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0px}.gap-0\\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-3\\.5{gap:.875rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-x-5{-moz-column-gap:1.25rem;column-gap:1.25rem}.gap-y-2{row-gap:.5rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-line-subtle>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-divide-opacity, 1))}.self-start{align-self:flex-start}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.break-all{word-break:break-all}.\\!rounded-none{border-radius:0!important}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\\[18px\\]{border-radius:18px}.rounded-\\[20px\\]{border-radius:20px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-none{border-radius:0}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-xs{border-radius:var(--radius-xs)}.rounded-b-md{border-bottom-right-radius:var(--radius-md);border-bottom-left-radius:var(--radius-md)}.rounded-t-md{border-top-left-radius:var(--radius-md);border-top-right-radius:var(--radius-md)}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-y{border-top-width:1px;border-bottom-width:1px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-l-2{border-left-width:2px}.border-l-4{border-left-width:4px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-t-0{border-top-width:0px}.border-dashed{border-style:dashed}.border-\\[hsl\\(144_8\\%_91\\%\\)\\]{--tw-border-opacity: 1;border-color:hsl(144 8% 91% / var(--tw-border-opacity, 1))}.border-brand{--tw-border-opacity: 1;border-color:hsl(var(--brand-hsl) / var(--tw-border-opacity, 1))}.border-brand-border{border-color:var(--brand-border)}.border-brand\\/30{border-color:hsl(var(--brand-hsl) / .3)}.border-brand\\/40{border-color:hsl(var(--brand-hsl) / .4)}.border-danger\\/20{border-color:hsl(var(--danger) / .2)}.border-danger\\/30{border-color:hsl(var(--danger) / .3)}.border-info\\/20{border-color:hsl(var(--info) / .2)}.border-info\\/30{border-color:hsl(var(--info) / .3)}.border-line{--tw-border-opacity: 1;border-color:hsl(var(--border-default) / var(--tw-border-opacity, 1))}.border-line-focus{--tw-border-opacity: 1;border-color:hsl(var(--border-focus) / var(--tw-border-opacity, 1))}.border-line-strong{--tw-border-opacity: 1;border-color:hsl(var(--border-strong) / var(--tw-border-opacity, 1))}.border-line-subtle{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}.border-line-subtle\\/50{border-color:hsl(var(--border-subtle) / .5)}.border-line-subtle\\/90{border-color:hsl(var(--border-subtle) / .9)}.border-slate-100{--tw-border-opacity: 1;border-color:rgb(241 245 249 / var(--tw-border-opacity, 1))}.border-slate-200{--tw-border-opacity: 1;border-color:rgb(226 232 240 / var(--tw-border-opacity, 1))}.border-success{--tw-border-opacity: 1;border-color:hsl(var(--success) / var(--tw-border-opacity, 1))}.border-success\\/20{border-color:hsl(var(--success) / .2)}.border-success\\/30{border-color:hsl(var(--success) / .3)}.border-text-primary{--tw-border-opacity: 1;border-color:hsl(var(--text-primary) / var(--tw-border-opacity, 1))}.border-transparent{border-color:transparent}.border-warning\\/20{border-color:hsl(var(--warning) / .2)}.border-warning\\/30{border-color:hsl(var(--warning) / .3)}.border-white\\/70{border-color:#ffffffb3}.border-white\\/80{border-color:#fffc}.border-white\\/90{border-color:#ffffffe6}.border-l-brand{--tw-border-opacity: 1;border-left-color:hsl(var(--brand-hsl) / var(--tw-border-opacity, 1))}.\\!bg-success-surface{background-color:hsl(var(--success-surface))!important}.bg-\\[var\\(--overlay-backdrop-strong\\)\\]{background-color:var(--overlay-backdrop-strong)}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-black\\/10{background-color:#0000001a}.bg-black\\/40{background-color:#0006}.bg-black\\/80{background-color:#000c}.bg-brand{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.bg-brand-subtle{background-color:var(--brand-subtle)}.bg-brand\\/10{background-color:hsl(var(--brand-hsl) / .1)}.bg-brand\\/5{background-color:hsl(var(--brand-hsl) / .05)}.bg-danger{--tw-bg-opacity: 1;background-color:hsl(var(--danger) / var(--tw-bg-opacity, 1))}.bg-danger-subtle{background-color:hsl(var(--danger-subtle))}.bg-danger\\/10{background-color:hsl(var(--danger) / .1)}.bg-info-subtle{background-color:hsl(var(--info-subtle))}.bg-line{--tw-bg-opacity: 1;background-color:hsl(var(--border-default) / var(--tw-bg-opacity, 1))}.bg-line-subtle{--tw-bg-opacity: 1;background-color:hsl(var(--border-subtle) / var(--tw-bg-opacity, 1))}.bg-success{--tw-bg-opacity: 1;background-color:hsl(var(--success) / var(--tw-bg-opacity, 1))}.bg-success-subtle{background-color:hsl(var(--success-subtle))}.bg-success-surface{background-color:hsl(var(--success-surface))}.bg-surface-0{--tw-bg-opacity: 1;background-color:hsl(var(--surface-0) / var(--tw-bg-opacity, 1))}.bg-surface-1{--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.bg-surface-2{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.bg-surface-3{--tw-bg-opacity: 1;background-color:hsl(var(--surface-3) / var(--tw-bg-opacity, 1))}.bg-surface-inset{--tw-bg-opacity: 1;background-color:hsl(var(--surface-inset) / var(--tw-bg-opacity, 1))}.bg-text-primary{--tw-bg-opacity: 1;background-color:hsl(var(--text-primary) / var(--tw-bg-opacity, 1))}.bg-text-tertiary{--tw-bg-opacity: 1;background-color:hsl(var(--text-tertiary) / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.bg-warning{--tw-bg-opacity: 1;background-color:hsl(var(--warning) / var(--tw-bg-opacity, 1))}.bg-warning-subtle{background-color:hsl(var(--warning-subtle))}.bg-warning\\/10{background-color:hsl(var(--warning) / .1)}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\\/10{background-color:#ffffff1a}.bg-white\\/25{background-color:#ffffff40}.fill-text-primary{fill:hsl(var(--text-primary) / 1)}.stroke-\\[3\\]{stroke-width:3}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.\\!p-0{padding:0!important}.p-0{padding:0}.p-0\\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-3\\.5{padding:.875rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-7{padding:1.75rem}.p-8{padding:2rem}.p-\\[18px\\]{padding:18px}.px-0{padding-left:0;padding-right:0}.px-1\\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-9{padding-left:2.25rem;padding-right:2.25rem}.py-0\\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\\.5{padding-top:.375rem;padding-bottom:.375rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-1{padding-bottom:.25rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pl-3{padding-left:.75rem}.pl-4{padding-left:1rem}.pl-5{padding-left:1.25rem}.pl-8{padding-left:2rem}.pr-10{padding-right:2.5rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-2\\.5{padding-top:.625rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.align-middle{vertical-align:middle}.font-display{font-family:var(--font-display),ui-sans-serif,system-ui,sans-serif}.font-mono{font-family:var(--font-mono),ui-monospace,SFMono-Regular,Menlo,monospace}.font-sans{font-family:var(--font-sans),ui-sans-serif,system-ui,sans-serif}.text-2xs{font-size:clamp(10.5px,10.19px + .082vw,11.5px);line-height:1.333}.text-\\[0\\.72rem\\]{font-size:.72rem}.text-\\[1\\.45rem\\]{font-size:1.45rem}.text-\\[1\\.75rem\\]{font-size:1.75rem}.text-\\[10px\\]{font-size:10px}.text-base{font-size:clamp(14px,13.39px + .163vw,16px);line-height:1.5}.text-lg{font-size:clamp(17px,16.39px + .163vw,19px);line-height:1.471}.text-sm{font-size:clamp(13px,12.54px + .122vw,14.5px);line-height:1.462}.text-xl{font-size:clamp(20px,19.08px + .245vw,23px);line-height:1.45}.text-xs{font-size:clamp(12px,11.69px + .082vw,13px);line-height:1.333}.font-black{font-weight:900}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-4{line-height:1rem}.leading-5{line-height:1.25rem}.leading-8{line-height:2rem}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.text-\\[hsl\\(145_5\\%_42\\%\\)\\]{--tw-text-opacity: 1;color:hsl(145 5% 42% / var(--tw-text-opacity, 1))}.text-brand{--tw-text-opacity: 1;color:hsl(var(--brand-hsl) / var(--tw-text-opacity, 1))}.text-brand-fg{color:var(--brand-fg)}.text-brand\\/50{color:hsl(var(--brand-hsl) / .5)}.text-danger{--tw-text-opacity: 1;color:hsl(var(--danger) / var(--tw-text-opacity, 1))}.text-danger\\/80{color:hsl(var(--danger) / .8)}.text-info{--tw-text-opacity: 1;color:hsl(var(--info) / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-slate-400{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1))}.text-slate-500{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity, 1))}.text-slate-700{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity, 1))}.text-slate-900{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity, 1))}.text-success{--tw-text-opacity: 1;color:hsl(var(--success) / var(--tw-text-opacity, 1))}.text-text-disabled{--tw-text-opacity: 1;color:hsl(var(--text-disabled) / var(--tw-text-opacity, 1))}.text-text-inverse{--tw-text-opacity: 1;color:hsl(var(--text-inverse) / var(--tw-text-opacity, 1))}.text-text-primary{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.text-text-secondary{--tw-text-opacity: 1;color:hsl(var(--text-secondary) / var(--tw-text-opacity, 1))}.text-text-tertiary{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.text-transparent{color:transparent}.text-warning{--tw-text-opacity: 1;color:hsl(var(--warning) / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-white\\/90{color:#ffffffe6}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.underline-offset-2{text-underline-offset:2px}.underline-offset-4{text-underline-offset:4px}.accent-brand{accent-color:hsl(var(--brand-hsl) / 1)}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.\\!shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1) !important;--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color) !important;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)!important}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\\[0_24px_70px_-28px_rgba\\(16\\,24\\,18\\,0\\.45\\)\\]{--tw-shadow: 0 24px 70px -28px rgba(16,24,18,.45);--tw-shadow-colored: 0 24px 70px -28px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: var(--shadow-lg);--tw-shadow-colored: var(--shadow-lg);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: var(--shadow-md);--tw-shadow-colored: var(--shadow-md);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: var(--shadow-sm);--tw-shadow-colored: var(--shadow-sm);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: var(--shadow-xl);--tw-shadow-colored: var(--shadow-xl);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xs{--tw-shadow: var(--shadow-xs);--tw-shadow-colored: var(--shadow-xs);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.outline-2{outline-width:2px}.outline-offset-0{outline-offset:0px}.outline-transparent{outline-color:transparent}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-4{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-brand{--tw-ring-opacity: 1;--tw-ring-color: hsl(var(--brand-hsl) / var(--tw-ring-opacity, 1))}.ring-brand-subtle{--tw-ring-color: var(--brand-subtle)}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-\\[2px\\]{--tw-backdrop-blur: blur(2px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,border-color\\,color\\,box-shadow\\]{transition-property:background-color,border-color,color,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\,border-color\\,box-shadow\\,opacity\\]{transition-property:background-color,color,border-color,box-shadow,opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\,border-color\\,box-shadow\\]{transition-property:background-color,color,border-color,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\,box-shadow\\]{transition-property:background-color,color,box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[background-color\\,color\\]{transition-property:background-color,color;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[border-color\\,box-shadow\\,background-color\\]{transition-property:border-color,box-shadow,background-color;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[border-color\\,outline-color\\,box-shadow\\,background-color\\,transform\\]{transition-property:border-color,outline-color,box-shadow,background-color,transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[max-width\\,box-shadow\\,background-color\\,border-color\\,transform\\,opacity\\]{transition-property:max-width,box-shadow,background-color,border-color,transform,opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[max-width\\]{transition-property:max-width;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\\[opacity\\,transform\\]{transition-property:opacity,transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.duration-\\[var\\(--issue-marker-expand-duration\\)\\]{transition-duration:var(--issue-marker-expand-duration)}.duration-fast{transition-duration:var(--duration-fast)}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:var(--ease-in-out)}.ease-out{transition-timing-function:var(--ease-out)}@keyframes float-gentle{0%,to{transform:translateY(0)}50%{transform:translateY(-2px)}}@keyframes toast-slide{0%{opacity:0;transform:translateY(-14px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes gradient-shift{0%,to{background-position:0% 50%}50%{background-position:100% 50%}}.issue-overlay-shell{border:1px solid hsl(var(--border-subtle));border-radius:var(--radius-lg);background:hsl(var(--surface-1));box-shadow:var(--shadow-md)}.issue-marker-breathe{animation:float-gentle 4.8s var(--ease-in-out) infinite}.issue-marker-breathe:hover,.issue-marker-breathe:focus-visible,.issue-marker-breathe:focus-within{animation-play-state:paused}.marker\\:text-text-tertiary *::marker{color:hsl(var(--text-tertiary))}.marker\\:text-text-tertiary::marker{color:hsl(var(--text-tertiary))}.file\\:border-0::file-selector-button{border-width:0px}.file\\:bg-transparent::file-selector-button{background-color:transparent}.file\\:text-sm::file-selector-button{font-size:clamp(13px,12.54px + .122vw,14.5px);line-height:1.462}.file\\:font-medium::file-selector-button{font-weight:500}.file\\:text-text-primary::file-selector-button{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.placeholder\\:text-text-tertiary::-moz-placeholder{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.placeholder\\:text-text-tertiary::placeholder{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.focus-within\\:z-\\[10001\\]:focus-within{z-index:10001}.focus-within\\:border-line-focus:focus-within{--tw-border-opacity: 1;border-color:hsl(var(--border-focus) / var(--tw-border-opacity, 1))}.hover\\:z-\\[10001\\]:hover{z-index:10001}.hover\\:max-w-\\[160px\\]:hover{max-width:160px}.hover\\:max-w-\\[480px\\]:hover{max-width:480px}.hover\\:border-line:hover{--tw-border-opacity: 1;border-color:hsl(var(--border-default) / var(--tw-border-opacity, 1))}.hover\\:border-line-strong:hover{--tw-border-opacity: 1;border-color:hsl(var(--border-strong) / var(--tw-border-opacity, 1))}.hover\\:border-line-subtle:hover{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}.hover\\:bg-\\[hsl\\(144_8\\%_96\\%\\)\\]:hover{--tw-bg-opacity: 1;background-color:hsl(144 8% 96% / var(--tw-bg-opacity, 1))}.hover\\:bg-blue-500:hover{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.hover\\:bg-brand-hover:hover{background-color:var(--brand-hover)}.hover\\:bg-brand\\/40:hover{background-color:hsl(var(--brand-hsl) / .4)}.hover\\:bg-danger-subtle:hover{background-color:hsl(var(--danger-subtle))}.hover\\:bg-danger\\/10:hover{background-color:hsl(var(--danger) / .1)}.hover\\:bg-slate-100:hover{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity, 1))}.hover\\:bg-slate-50:hover{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity, 1))}.hover\\:bg-surface-2:hover{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.hover\\:bg-surface-2\\/60:hover{background-color:hsl(var(--surface-2) / .6)}.hover\\:bg-surface-3:hover{--tw-bg-opacity: 1;background-color:hsl(var(--surface-3) / var(--tw-bg-opacity, 1))}.hover\\:bg-surface-inset:hover{--tw-bg-opacity: 1;background-color:hsl(var(--surface-inset) / var(--tw-bg-opacity, 1))}.hover\\:bg-transparent:hover{background-color:transparent}.hover\\:bg-white\\/20:hover{background-color:#fff3}.hover\\:text-\\[hsl\\(150_10\\%_12\\%\\)\\]:hover{--tw-text-opacity: 1;color:hsl(150 10% 12% / var(--tw-text-opacity, 1))}.hover\\:text-brand-hover:hover{color:var(--brand-hover)}.hover\\:text-danger:hover{--tw-text-opacity: 1;color:hsl(var(--danger) / var(--tw-text-opacity, 1))}.hover\\:text-slate-900:hover{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity, 1))}.hover\\:text-text-primary:hover{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.hover\\:text-text-secondary:hover{--tw-text-opacity: 1;color:hsl(var(--text-secondary) / var(--tw-text-opacity, 1))}.hover\\:underline:hover{text-decoration-line:underline}.hover\\:opacity-90:hover{opacity:.9}.hover\\:shadow-xl:hover{--tw-shadow: var(--shadow-xl);--tw-shadow-colored: var(--shadow-xl);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus\\:border-brand:focus{--tw-border-opacity: 1;border-color:hsl(var(--brand-hsl) / var(--tw-border-opacity, 1))}.focus\\:bg-surface-2:focus{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.focus\\:text-text-primary:focus{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.focus\\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus-visible\\:max-w-\\[160px\\]:focus-visible{max-width:160px}.focus-visible\\:max-w-\\[480px\\]:focus-visible{max-width:480px}.focus-visible\\:border-line-focus:focus-visible{--tw-border-opacity: 1;border-color:hsl(var(--border-focus) / var(--tw-border-opacity, 1))}.focus-visible\\:border-transparent:focus-visible{border-color:transparent}.focus-visible\\:bg-slate-50:focus-visible{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity, 1))}.focus-visible\\:bg-surface-1:focus-visible{--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.focus-visible\\:bg-surface-2:focus-visible{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.focus-visible\\:text-text-primary:focus-visible{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.focus-visible\\:shadow-focus:focus-visible{--tw-shadow: var(--shadow-focus);--tw-shadow-colored: var(--shadow-focus);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus-visible\\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\\:outline-line-focus:focus-visible{outline-color:hsl(var(--border-focus) / 1)}.focus-visible\\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\\:ring-4:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\\:ring-brand-subtle:focus-visible{--tw-ring-color: var(--brand-subtle)}.focus-visible\\:ring-white\\/40:focus-visible{--tw-ring-color: rgb(255 255 255 / .4)}.active\\:bg-brand-active:active{background-color:var(--brand-active)}.active\\:bg-brand\\/60:active{background-color:hsl(var(--brand-hsl) / .6)}.disabled\\:pointer-events-none:disabled{pointer-events:none}.disabled\\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\\:translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\\:opacity-100{opacity:1}.group:focus-visible .group-focus-visible\\:translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:focus-visible .group-focus-visible\\:opacity-100{opacity:1}.group.toaster .group-\\[\\.toaster\\]\\:isolate{isolation:isolate}.group.toast .group-\\[\\.toast\\]\\:rounded-md,.group.toaster .group-\\[\\.toaster\\]\\:rounded-md{border-radius:var(--radius-md)}.group.toaster .group-\\[\\.toaster\\]\\:border{border-width:1px}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-danger\\/30{border-color:hsl(var(--danger) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-info\\/30{border-color:hsl(var(--info) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-success\\/30{border-color:hsl(var(--success) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!border-warning\\/30{border-color:hsl(var(--warning) / .3)!important}.group.toaster .group-\\[\\.toaster\\]\\:border-line-subtle{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}.group.toast .group-\\[\\.toast\\]\\:bg-brand{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.group.toast .group-\\[\\.toast\\]\\:bg-surface-2{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-danger-subtle{background-color:hsl(var(--danger-subtle))!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-info-subtle{background-color:hsl(var(--info-subtle))!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-success-surface{background-color:hsl(var(--success-surface))!important}.group.toaster .group-\\[\\.toaster\\]\\:\\!bg-warning-subtle{background-color:hsl(var(--warning-subtle))!important}.group.toaster .group-\\[\\.toaster\\]\\:bg-surface-1{--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:px-4{padding-left:1rem;padding-right:1rem}.group.toaster .group-\\[\\.toaster\\]\\:py-3{padding-top:.75rem;padding-bottom:.75rem}.group.toast .group-\\[\\.toast\\]\\:text-sm{font-size:clamp(13px,12.54px + .122vw,14.5px);line-height:1.462}.group.toast .group-\\[\\.toast\\]\\:text-xs{font-size:clamp(12px,11.69px + .082vw,13px);line-height:1.333}.group.toast .group-\\[\\.toast\\]\\:font-medium{font-weight:500}.group.toast .group-\\[\\.toast\\]\\:text-brand-fg{color:var(--brand-fg)}.group.toast .group-\\[\\.toast\\]\\:text-text-primary{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.group.toast .group-\\[\\.toast\\]\\:text-text-secondary{--tw-text-opacity: 1;color:hsl(var(--text-secondary) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:text-text-primary{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:shadow-sm{--tw-shadow: var(--shadow-sm);--tw-shadow-colored: var(--shadow-sm);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.group.toaster .group-\\[\\.toaster\\]\\:before\\:absolute:before{content:var(--tw-content);position:absolute}.group.toaster .group-\\[\\.toaster\\]\\:before\\:inset-0:before{content:var(--tw-content);top:0;right:0;bottom:0;left:0}.group.toaster .group-\\[\\.toaster\\]\\:before\\:-z-10:before{content:var(--tw-content);z-index:-10}.group.toaster .group-\\[\\.toaster\\]\\:before\\:rounded-md:before{content:var(--tw-content);border-radius:var(--radius-md)}.group.toaster .group-\\[\\.toaster\\]\\:before\\:bg-surface-1:before{content:var(--tw-content);--tw-bg-opacity: 1;background-color:hsl(var(--surface-1) / var(--tw-bg-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:before\\:content-\\[\\'\\'\\]:before{--tw-content: "";content:var(--tw-content)}.peer:focus-visible~.peer-focus-visible\\:shadow-focus{--tw-shadow: var(--shadow-focus);--tw-shadow-colored: var(--shadow-focus);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.peer:disabled~.peer-disabled\\:cursor-not-allowed{cursor:not-allowed}.peer:disabled~.peer-disabled\\:opacity-60{opacity:.6}.aria-disabled\\:pointer-events-none[aria-disabled=true]{pointer-events:none}.aria-disabled\\:opacity-40[aria-disabled=true]{opacity:.4}.data-\\[disabled\\]\\:pointer-events-none[data-disabled]{pointer-events:none}@keyframes dialog-out{0%{opacity:1;transform:translate(-50%,-50%) scale(1)}to{opacity:0;transform:translate(-50%,calc(-50% + 8px)) scale(.985)}}.data-\\[state\\=closed\\]\\:animate-dialog-out[data-state=closed]{animation:dialog-out var(--duration-out) var(--ease-out) forwards}@keyframes fade-out{0%{opacity:1}to{opacity:0}}.data-\\[state\\=closed\\]\\:animate-fade-out[data-state=closed]{animation:fade-out var(--duration-out) var(--ease-out) forwards}@keyframes scale-out{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.97)}}.data-\\[state\\=closed\\]\\:animate-scale-out[data-state=closed]{animation:scale-out var(--duration-out) var(--ease-out) forwards}@keyframes sheet-out-left{0%{transform:translate(0)}to{transform:translate(-100%);opacity:.6}}.data-\\[state\\=closed\\]\\:animate-sheet-out-left[data-state=closed]{animation:sheet-out-left var(--duration-base) var(--ease-out) forwards}@keyframes sheet-out-right{0%{transform:translate(0);opacity:1}to{transform:translate(100%);opacity:.6}}.data-\\[state\\=closed\\]\\:animate-sheet-out-right[data-state=closed]{animation:sheet-out-right var(--duration-base) var(--ease-out) forwards}.data-\\[state\\=delayed-open\\]\\:animate-scale-in[data-state=delayed-open]{animation:scale-in var(--duration-base) var(--ease-out) forwards}@keyframes dialog-in{0%{opacity:0;transform:translate(-50%,calc(-50% + 12px)) scale(.985)}to{opacity:1;transform:translate(-50%,-50%) scale(1)}}.data-\\[state\\=open\\]\\:animate-dialog-in[data-state=open]{animation:dialog-in var(--duration-base) var(--ease-out) forwards}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.data-\\[state\\=open\\]\\:animate-fade-in[data-state=open]{animation:fade-in var(--duration-base) var(--ease-out) forwards}@keyframes scale-in{0%{opacity:0;transform:scale(.98)}to{opacity:1;transform:scale(1)}}.data-\\[state\\=open\\]\\:animate-scale-in[data-state=open]{animation:scale-in var(--duration-base) var(--ease-out) forwards}@keyframes sheet-in-left{0%{transform:translate(-100%);opacity:.6}to{transform:translate(0);opacity:1}}.data-\\[state\\=open\\]\\:animate-sheet-in-left[data-state=open]{animation:sheet-in-left var(--duration-base) var(--ease-out) forwards}@keyframes sheet-in-right{0%{transform:translate(100%);opacity:.6}to{transform:translate(0)}}.data-\\[state\\=open\\]\\:animate-sheet-in-right[data-state=open]{animation:sheet-in-right var(--duration-base) var(--ease-out) forwards}.data-\\[range-end\\=true\\]\\:rounded-md[data-range-end=true]{border-radius:var(--radius-md)}.data-\\[range-middle\\=true\\]\\:rounded-none[data-range-middle=true]{border-radius:0}.data-\\[range-start\\=true\\]\\:rounded-md[data-range-start=true]{border-radius:var(--radius-md)}.data-\\[state\\=open\\]\\:border-line-focus[data-state=open]{--tw-border-opacity: 1;border-color:hsl(var(--border-focus) / var(--tw-border-opacity, 1))}.data-\\[highlighted\\]\\:bg-surface-2[data-highlighted]{--tw-bg-opacity: 1;background-color:hsl(var(--surface-2) / var(--tw-bg-opacity, 1))}.data-\\[range-end\\=true\\]\\:bg-brand[data-range-end=true]{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.data-\\[range-middle\\=true\\]\\:bg-transparent[data-range-middle=true]{background-color:transparent}.data-\\[range-start\\=true\\]\\:bg-brand[data-range-start=true],.data-\\[selected-single\\=true\\]\\:bg-brand[data-selected-single=true]{--tw-bg-opacity: 1;background-color:hsl(var(--brand-hsl) / var(--tw-bg-opacity, 1))}.data-\\[state\\=selected\\]\\:bg-brand-subtle[data-state=selected]{background-color:var(--brand-subtle)}.data-\\[today\\=true\\]\\:font-semibold[data-today=true]{font-weight:600}.data-\\[highlighted\\]\\:text-text-primary[data-highlighted]{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.data-\\[placeholder\\]\\:text-text-tertiary[data-placeholder]{--tw-text-opacity: 1;color:hsl(var(--text-tertiary) / var(--tw-text-opacity, 1))}.data-\\[range-end\\=true\\]\\:text-brand-fg[data-range-end=true]{color:var(--brand-fg)}.data-\\[range-middle\\=true\\]\\:text-text-primary[data-range-middle=true]{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.data-\\[range-start\\=true\\]\\:text-brand-fg[data-range-start=true],.data-\\[selected-single\\=true\\]\\:text-brand-fg[data-selected-single=true]{color:var(--brand-fg)}.data-\\[state\\=active\\]\\:text-text-primary[data-state=active],.data-\\[state\\=checked\\]\\:text-text-primary[data-state=checked]{--tw-text-opacity: 1;color:hsl(var(--text-primary) / var(--tw-text-opacity, 1))}.data-\\[today\\=true\\]\\:text-brand[data-today=true]{--tw-text-opacity: 1;color:hsl(var(--brand-hsl) / var(--tw-text-opacity, 1))}.data-\\[disabled\\]\\:opacity-50[data-disabled]{opacity:.5}.data-\\[state\\=open\\]\\:shadow-focus[data-state=open]{--tw-shadow: var(--shadow-focus);--tw-shadow-colored: var(--shadow-focus);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.data-\\[range-end\\=true\\]\\:hover\\:bg-brand-hover:hover[data-range-end=true],.data-\\[range-start\\=true\\]\\:hover\\:bg-brand-hover:hover[data-range-start=true],.data-\\[selected-single\\=true\\]\\:hover\\:bg-brand-hover:hover[data-selected-single=true]{background-color:var(--brand-hover)}.data-\\[range-end\\=true\\]\\:hover\\:text-brand-fg:hover[data-range-end=true],.data-\\[range-start\\=true\\]\\:hover\\:text-brand-fg:hover[data-range-start=true],.data-\\[selected-single\\=true\\]\\:hover\\:text-brand-fg:hover[data-selected-single=true]{color:var(--brand-fg)}@media(prefers-reduced-motion:reduce){.motion-reduce\\:animate-none{animation:none}}@media(min-width:640px){.sm\\:flex-row{flex-direction:row}.sm\\:items-start{align-items:flex-start}.sm\\:items-center{align-items:center}.sm\\:justify-end{justify-content:flex-end}.sm\\:justify-between{justify-content:space-between}.sm\\:gap-2\\.5{gap:.625rem}.sm\\:p-5{padding:1.25rem}.sm\\:p-6{padding:1.5rem}.sm\\:text-2xl{font-size:clamp(26px,24.78px + .327vw,30px);line-height:1.308}.sm\\:text-\\[2\\.1rem\\]{font-size:2.1rem}}@media(min-width:768px){.md\\:flex{display:flex}.md\\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\\:grid-cols-\\[minmax\\(0\\,1fr\\)_minmax\\(260px\\,340px\\)\\]{grid-template-columns:minmax(0,1fr) minmax(260px,340px)}}.\\[\\&\\>\\*\\:not\\(summary\\)\\]\\:pl-4>*:not(summary){padding-left:1rem}.\\[\\&\\>span\\]\\:line-clamp-1>span{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.\\[\\&\\>tr\\]\\:last\\:border-b-0:last-child>tr{border-bottom-width:0px}.\\[\\&\\[data-state\\=open\\]\\>span\\[data-chevron\\]\\]\\:rotate-180[data-state=open]>span[data-chevron]{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-danger [data-icon]{--tw-text-opacity: 1;color:hsl(var(--danger) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-info [data-icon]{--tw-text-opacity: 1;color:hsl(var(--info) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-success [data-icon]{--tw-text-opacity: 1;color:hsl(var(--success) / var(--tw-text-opacity, 1))}.group.toaster .group-\\[\\.toaster\\]\\:\\[\\&_\\[data-icon\\]\\]\\:text-warning [data-icon]{--tw-text-opacity: 1;color:hsl(var(--warning) / var(--tw-text-opacity, 1))}.\\[\\&_tr\\]\\:border-b tr{border-bottom-width:1px}.\\[\\&_tr\\]\\:border-line-subtle tr{--tw-border-opacity: 1;border-color:hsl(var(--border-subtle) / var(--tw-border-opacity, 1))}`;
|
|
37260
38083
|
const sdkShadowCSS = ".issue-sticker-marker{pointer-events:auto}@keyframes highlight-pulse{0%,to{transform:scale(1);box-shadow:var(--shadow-md)}50%{transform:scale(1.3);box-shadow:var(--shadow-focus),var(--shadow-lg)}}.issue-sticker-marker.highlight-animation{animation:highlight-pulse .7s ease-in-out 3}";
|
|
37261
|
-
const contentPageCSS = `body.issue-sticker-mode-active,body.issue-sticker-mode-active *{cursor:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cpath d='M3 29 C3 22 3 20 3 15 a12 12 0 0 1 12-12 h2 a12 12 0 0 1 12 12 a12 12 0 0 1-12 12 H12 Z' fill='%
|
|
38084
|
+
const contentPageCSS = `body.issue-sticker-mode-active,body.issue-sticker-mode-active *{cursor:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cpath d='M3 29 C3 22 3 20 3 15 a12 12 0 0 1 12-12 h2 a12 12 0 0 1 12 12 a12 12 0 0 1-12 12 H12 Z' fill='%231C221F' stroke='%23ffffff' stroke-width='2' stroke-linejoin='round'/%3E%3C/svg%3E") 3 29,crosshair!important}body.issue-sticker-mode-active .issue-sticker-marker{cursor:default!important}body.issue-sticker-mode-active button,body.issue-sticker-mode-active a,body.issue-sticker-mode-active input,body.issue-sticker-mode-active textarea,body.issue-sticker-mode-active select{cursor:pointer!important}.issue-sticker-mode-highlight{outline:2px solid hsl(160 64% 34%)!important;outline-offset:2px!important;background-color:#1f8e691f!important;transition:outline .1s ease,background-color .1s ease!important}`;
|
|
37262
38085
|
const PAGE_STYLE_ID = "issue-sticker-page-style";
|
|
37263
38086
|
let root = null;
|
|
37264
38087
|
let mountContainer = null;
|