@designbasekorea/figma-ui 0.6.3 → 0.6.6
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/README.md +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +115 -14
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.css.map +1 -1
- package/dist/index.esm.js +427 -132
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +978 -147
- package/dist/index.js.map +1 -1
- package/package.json +26 -19
package/dist/index.esm.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import React, { useRef, useState, useLayoutEffect, useEffect, createContext, useContext, useCallback } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export
|
|
1
|
+
import React, { useRef, useState, useLayoutEffect, useEffect, createContext, useContext, useCallback, useMemo } from 'react';
|
|
2
|
+
import { Button, Dropdown, Badge, Toggle, Spinner, SegmentControl, Logo, Toast, Input, Modal, Progressbar, RandomGradient } from '@designbasekorea/ui-wc/react';
|
|
3
|
+
export * from '@designbasekorea/ui-wc/react';
|
|
4
|
+
export { Accordion, ActivityHeatmap, AdBanner, AiChat, AiChatList, Alert, AnimationBackground, AnimationText, AppBadge, AudioPlayer, Avatar, Backdrop, Badge, Banner, BottomNavigation, BottomSheet, Breadcrumbs, Button, Calendar, Card, Carousel, ChatComposer, ChatList, ChatMessage, ChatOrb, ChatRoom, ChatSuggestions, ChatTyping, ChatWelcome, ChatWidget, Checkbox, Chip, CodeBlock, ColorPicker, ColorSwatch, Confirm, Container, ContextMenu, CookieBanner, Countdown, CursorFollower, DatePicker, Divider, DownloadProgress, Drawer, Dropdown, Dropzone, EmailVerify, EmptyState, FileUploader, FloatingActionButton, Footer, Form, Gantt, Gradient, Grid, GridBackground, GridItem, Image, ImageList, ImagePlaceholder, Indicator, Input, Kanban, Label, Lightbox, List, Logo, MarkdownEditor, Marquee, Masonry, MenuItem, Modal, ModalBody, ModalFooter, ModalHeader, Navbar, OnboardingModal, OtpInput, PageHeader, Pagination, PhoneVerify, Popover, Progress, ProgressStep, Progressbar, Radio, RandomGradient, RangeSlider, Rating, Reorder, ResizablePanels, ScrollArea, SearchBar, Section, SectionAppDownload, SectionContact, SectionCta, SectionFaq, SectionFeature, SectionFeatureGrid, SectionHero, SectionLogoCloud, SectionPricing, SectionStats, SectionTestimonials, SegmentControl, Select, Share, Sidebar, Signature, Skeleton, Spinner, SplitView, Stack, Stat, Stepper, Table, Tabs, Testimonial, Textarea, TimePicker, Timeline, Toast, Toggle, Toolbar, Tooltip, TopBanner, Tutorial, TwoFactor, VideoPlayer, YouTubePlayer, useContextMenu } from '@designbasekorea/ui-wc/react';
|
|
5
|
+
import { ChevronDownIcon, AppWindowIcon, YoutubeIcon, InstagramIcon, FigmaIcon, MailIcon, ExternalLinkIcon, MoreHorizontalIcon, CloseIcon, CircleCheckFilledIcon, ResizableIcon, GripVerticalIcon, ChevronRightIcon } from '@designbasekorea/icons';
|
|
5
6
|
|
|
6
7
|
function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
|
|
7
8
|
|
|
@@ -11,10 +12,20 @@ function resolveText(t, input, fallback) {
|
|
|
11
12
|
if (typeof input === 'string') {
|
|
12
13
|
return input;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
+
if (t) {
|
|
16
|
+
const translated = t(input.key, input.values);
|
|
17
|
+
if (translated && translated !== input.key) {
|
|
18
|
+
return translated;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return fallback ?? input.key;
|
|
15
22
|
}
|
|
16
23
|
|
|
17
|
-
const
|
|
24
|
+
const DONATION_ICON_NAMES = {
|
|
25
|
+
heart: 'star-filled',
|
|
26
|
+
coffee: 'cart',
|
|
27
|
+
};
|
|
28
|
+
const DonationBadge = ({ donationUrl = 'https://buymeacoffee.com/designbase', text = { key: 'donation.buy_me_a_coffee' }, iconType = 'heart', size = 's', variant = 'tertiary', fullWidth = false, iconOnly = false, disabled = false, showPrompt = false, promptText = { key: 'donation.prompt' }, className, onClick, t }) => {
|
|
18
29
|
const handleClick = () => {
|
|
19
30
|
if (onClick) {
|
|
20
31
|
onClick();
|
|
@@ -23,15 +34,12 @@ const DonationBadge = ({ donationUrl = 'https://buymeacoffee.com/designbase', te
|
|
|
23
34
|
window.open(donationUrl, '_blank', 'noopener,noreferrer');
|
|
24
35
|
}
|
|
25
36
|
};
|
|
26
|
-
const Icon = iconType === 'heart' ? HeartFilledIcon : CoffeeFilledIcon;
|
|
27
37
|
const displayText = resolveText(t, text, 'Buy me a coffee');
|
|
28
38
|
const displayPromptText = resolveText(t, promptText, '도움이 되었다면 커피 한 잔 사주세요!');
|
|
29
39
|
const buttonSize = size;
|
|
30
40
|
return (React.createElement("div", { className: clsx('designbase-figma-donation-badge-container', className) },
|
|
31
|
-
showPrompt && (React.createElement("div", { className: "designbase-figma-donation-badge__prompt" }, displayPromptText)),
|
|
32
|
-
React.createElement(Button, { variant: variant, size: buttonSize, fullWidth: fullWidth, disabled: disabled, onPress: handleClick, startIcon:
|
|
33
|
-
'--designbase-figma-donation-badge-icon-color': 'var(--db-brand-primary)'
|
|
34
|
-
} }, displayText)));
|
|
41
|
+
showPrompt && !iconOnly && (React.createElement("div", { className: "designbase-figma-donation-badge__prompt" }, displayPromptText)),
|
|
42
|
+
React.createElement(Button, { variant: variant, size: buttonSize, fullWidth: fullWidth, disabled: disabled, onPress: handleClick, iconOnly: iconOnly, startIcon: DONATION_ICON_NAMES[iconType], className: clsx('designbase-figma-donation-badge', `designbase-figma-donation-badge--${iconType}`), "aria-label": displayText }, iconOnly ? undefined : displayText)));
|
|
35
43
|
};
|
|
36
44
|
DonationBadge.displayName = 'DonationBadge';
|
|
37
45
|
|
|
@@ -69,10 +77,11 @@ const FigmaHeader = ({ children, actions = [], searchBar, sticky = true, classNa
|
|
|
69
77
|
'designbase-figma-header--with-search': !!searchBar,
|
|
70
78
|
'designbase-figma-header--with-actions': actions.length > 0,
|
|
71
79
|
}, className);
|
|
80
|
+
const hasToolbar = !!children || actions.length > 0;
|
|
72
81
|
return (React.createElement("header", { className: classes },
|
|
73
|
-
React.createElement("div", { className: "designbase-figma-header__container" },
|
|
82
|
+
hasToolbar && (React.createElement("div", { className: "designbase-figma-header__container" },
|
|
74
83
|
children && (React.createElement("div", { className: "designbase-figma-header__center" }, children)),
|
|
75
|
-
actions.length > 0 && (React.createElement("div", { className: "designbase-figma-header__right" }, actions.map((action, index) => (React.createElement(Button, { key: index
|
|
84
|
+
actions.length > 0 && (React.createElement("div", { className: "designbase-figma-header__right" }, actions.map((action, index) => (React.createElement(Button, { key: `${action.startIcon}-${index}`, variant: "tertiary", size: "s", iconOnly: true, startIcon: action.startIcon, "aria-label": action.ariaLabel, onPress: action.onPress }))))))),
|
|
76
85
|
searchBar && (React.createElement("div", { className: "designbase-figma-header__search-container" }, searchBar))));
|
|
77
86
|
};
|
|
78
87
|
FigmaHeader.displayName = 'FigmaHeader';
|
|
@@ -81,22 +90,24 @@ const FigmaPageHead = ({ onBack, title, description, actions = [], moreActions =
|
|
|
81
90
|
const classes = clsx('designbase-figma-page-head', className);
|
|
82
91
|
const displayTitle = resolveText(t, title);
|
|
83
92
|
const displayDescription = description ? resolveText(t, description) : undefined;
|
|
84
|
-
const dropdownItems = moreActions.map(action => ({
|
|
93
|
+
const dropdownItems = moreActions.map((action) => ({
|
|
85
94
|
id: action.id,
|
|
86
95
|
label: resolveText(t, action.label),
|
|
87
|
-
onClick: action.onClick
|
|
88
96
|
}));
|
|
97
|
+
const handleDropdownChange = (event) => {
|
|
98
|
+
const actionId = event.detail?.id ?? event.detail?.value;
|
|
99
|
+
const action = moreActions.find((item) => item.id === actionId);
|
|
100
|
+
action?.onClick();
|
|
101
|
+
};
|
|
89
102
|
return (React.createElement("div", { className: classes },
|
|
90
103
|
React.createElement("div", { className: "designbase-figma-page-head__left" },
|
|
91
|
-
React.createElement(Button, { variant: "tertiary", size: "s", iconOnly: true, onPress: onBack, "aria-label": "\uB4A4\uB85C\uAC00\uAE30" },
|
|
92
|
-
React.createElement(ChevronLeftIcon, { size: 14 })),
|
|
104
|
+
React.createElement(Button, { variant: "tertiary", size: "s", iconOnly: true, startIcon: "chevron-left", onPress: onBack, "aria-label": "\uB4A4\uB85C\uAC00\uAE30" }),
|
|
93
105
|
React.createElement("div", { className: "designbase-figma-page-head__titles" },
|
|
94
106
|
React.createElement("h2", null, displayTitle),
|
|
95
107
|
displayDescription && React.createElement("p", null, displayDescription))),
|
|
96
108
|
React.createElement("div", { className: "designbase-figma-page-head__actions" },
|
|
97
109
|
actions.map((action, index) => (React.createElement(React.Fragment, { key: index }, action))),
|
|
98
|
-
moreActions.length > 0 && (React.createElement(Dropdown, {
|
|
99
|
-
React.createElement(MoreHorizontalIcon, { size: 16 })), items: dropdownItems, placement: "bottom-right", size: "s" })))));
|
|
110
|
+
moreActions.length > 0 && (React.createElement(Dropdown, { items: dropdownItems, triggerIcon: "more-horizontal", iconOnly: true, triggerVariant: "tertiary", placement: "bottom-right", size: "s", onChange: handleDropdownChange })))));
|
|
100
111
|
};
|
|
101
112
|
FigmaPageHead.displayName = 'FigmaPageHead';
|
|
102
113
|
|
|
@@ -413,10 +424,19 @@ const LanguageSelector = ({ currentLanguage, languages = DEFAULT_LANGUAGES, onLa
|
|
|
413
424
|
const segmentOptions = languages.map((language) => ({
|
|
414
425
|
value: language.code,
|
|
415
426
|
label: resolveText(t, language.label),
|
|
416
|
-
disabled: false
|
|
427
|
+
disabled: false,
|
|
417
428
|
}));
|
|
418
429
|
return (React.createElement("div", { className: `designbase-figma-language-selector ${className || ''}` },
|
|
419
|
-
React.createElement(SegmentControl, { options: segmentOptions, value: activeLanguage, onChange:
|
|
430
|
+
React.createElement(SegmentControl, { options: segmentOptions, value: activeLanguage, onChange: (event) => {
|
|
431
|
+
const detail = event.detail;
|
|
432
|
+
const value = typeof detail === 'object' && detail !== null && 'value' in detail &&
|
|
433
|
+
typeof detail.value === 'string'
|
|
434
|
+
? detail.value
|
|
435
|
+
: undefined;
|
|
436
|
+
if (value) {
|
|
437
|
+
handleLanguageChange(value);
|
|
438
|
+
}
|
|
439
|
+
}, size: size, className: "designbase-figma-language-selector__segment" })));
|
|
420
440
|
};
|
|
421
441
|
LanguageSelector.displayName = 'LanguageSelector';
|
|
422
442
|
|
|
@@ -506,22 +526,29 @@ const FigmaFooter = ({ onLicensePageClick, paymentStatus = 'FREE', usageCount =
|
|
|
506
526
|
React.createElement("div", { className: "designbase-figma-footer__left" },
|
|
507
527
|
React.createElement(LogoDropdown, { logoSrc: logoSrc, logoAlt: logoAlt, logoType: logoType, logoSize: logoSize, links: logoLinks, t: t }),
|
|
508
528
|
showLanguageSelector && (React.createElement(LanguageSelector, { currentLanguage: currentLanguage, languages: languages, onLanguageChange: onLanguageChange, size: "s" }))),
|
|
509
|
-
|
|
510
|
-
resolvedShowUsageInfo && (React.createElement("div", { className: "designbase-figma-footer__usage-info" }, isActive ? (React.createElement("span", { className: "designbase-figma-footer__unlimited-usage designbase-figma-footer__unlimited-usage--tooltip", title: t('unlimitedUsageTooltip') }, t('unlimitedUsage'))) : (React.createElement(
|
|
511
|
-
React.createElement("span", { className: "designbase-figma-footer__usage-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
showDonation && (React.createElement("div", { className: "designbase-figma-footer__donation" },
|
|
520
|
-
React.createElement(DonationBadge, { donationUrl: donationUrl, text: donationText, iconType: "heart", size: "s", showPrompt: showDonationText && !isActive, promptText: donationPromptText, t: t })))),
|
|
529
|
+
React.createElement("div", { className: "designbase-figma-footer__right" },
|
|
530
|
+
showPaymentStatus && resolvedShowUsageInfo && (React.createElement("div", { className: "designbase-figma-footer__usage-info" }, isActive ? (React.createElement("span", { className: "designbase-figma-footer__unlimited-usage designbase-figma-footer__unlimited-usage--tooltip", title: t('unlimitedUsageTooltip') }, t('unlimitedUsage'))) : (React.createElement("span", { className: "designbase-figma-footer__usage-info designbase-figma-footer__usage-info--tooltip", title: t('resetsDaily') },
|
|
531
|
+
React.createElement("span", { className: "designbase-figma-footer__usage-count" }, usageCount),
|
|
532
|
+
React.createElement("span", { className: "designbase-figma-footer__max-daily-usage" },
|
|
533
|
+
"/",
|
|
534
|
+
maxDailyUsage,
|
|
535
|
+
" ",
|
|
536
|
+
t('perDay')))))),
|
|
537
|
+
showPaymentStatus && resolvedShowPaymentBadge && (React.createElement(PaymentBadge, { isActive: isActive, onClick: isBeta ? undefined : onLicensePageClick, isLoading: isLoading, text: isBeta ? (t('betaStatus') || 'BETA') : undefined, t: t })),
|
|
538
|
+
showDonation && (React.createElement(DonationBadge, { donationUrl: donationUrl, text: donationText, iconType: "heart", size: "s", iconOnly: true, showPrompt: false, t: t })))),
|
|
521
539
|
children));
|
|
522
540
|
};
|
|
523
541
|
FigmaFooter.displayName = 'FigmaFooter';
|
|
524
542
|
|
|
543
|
+
const FigmaToastStack = ({ toasts, position, maxToasts, onRemoveToast, }) => {
|
|
544
|
+
const visibleToasts = [...toasts]
|
|
545
|
+
.sort((a, b) => b.createdAt - a.createdAt)
|
|
546
|
+
.slice(0, maxToasts);
|
|
547
|
+
if (visibleToasts.length === 0)
|
|
548
|
+
return null;
|
|
549
|
+
return (React.createElement("div", { className: `figma-toast-container figma-toast-container--${position}` }, visibleToasts.map((toast) => (React.createElement("div", { key: toast.id, className: "figma-toast-container__item" },
|
|
550
|
+
React.createElement(Toast, { toastId: toast.id, title: toast.title, description: toast.description, status: toast.status, duration: toast.duration, showProgress: toast.showProgress, showClose: toast.showCloseButton, onClose: () => onRemoveToast(toast.id) }))))));
|
|
551
|
+
};
|
|
525
552
|
const ToastContext = createContext(null);
|
|
526
553
|
const useToast = () => {
|
|
527
554
|
const context = useContext(ToastContext);
|
|
@@ -539,13 +566,13 @@ const FigmaToastProvider = ({ children, position = 'top-right', maxToasts = 5, }
|
|
|
539
566
|
id,
|
|
540
567
|
createdAt: Date.now(),
|
|
541
568
|
};
|
|
542
|
-
setToasts(prev => {
|
|
569
|
+
setToasts((prev) => {
|
|
543
570
|
const updated = [newToast, ...prev];
|
|
544
571
|
return updated.slice(0, maxToasts);
|
|
545
572
|
});
|
|
546
573
|
}, [maxToasts]);
|
|
547
574
|
const removeToast = useCallback((id) => {
|
|
548
|
-
setToasts(prev => prev.filter(toast => toast.id !== id));
|
|
575
|
+
setToasts((prev) => prev.filter((toast) => toast.id !== id));
|
|
549
576
|
}, []);
|
|
550
577
|
const showToast = useCallback((message, options = {}) => {
|
|
551
578
|
addToast({
|
|
@@ -564,17 +591,17 @@ const FigmaToastProvider = ({ children, position = 'top-right', maxToasts = 5, }
|
|
|
564
591
|
};
|
|
565
592
|
return (React.createElement(ToastContext.Provider, { value: contextValue },
|
|
566
593
|
children,
|
|
567
|
-
React.createElement(
|
|
594
|
+
React.createElement(FigmaToastStack, { toasts: toasts, onRemoveToast: removeToast, position: position, maxToasts: maxToasts })));
|
|
568
595
|
};
|
|
569
596
|
const FigmaToast = ({ message, isVisible, onClose, type = 'info', duration = 3000, className, }) => {
|
|
570
597
|
if (!isVisible)
|
|
571
598
|
return null;
|
|
572
599
|
return (React.createElement("div", { className: `figma-toast-fixed-wrap ${className || ''}` },
|
|
573
|
-
React.createElement(Toast, {
|
|
600
|
+
React.createElement(Toast, { toastId: "figma-toast-simple", title: message, status: type, duration: duration, showProgress: false, showClose: true, onClose: onClose })));
|
|
574
601
|
};
|
|
575
602
|
const useFigmaToast = () => {
|
|
576
603
|
const [toast, setToast] = useState({ message: '', isVisible: false });
|
|
577
|
-
const showToast = useCallback((message,
|
|
604
|
+
const showToast = useCallback((message, _type = 'info') => {
|
|
578
605
|
setToast({ message, isVisible: true });
|
|
579
606
|
setTimeout(() => setToast({ message: '', isVisible: false }), 5000);
|
|
580
607
|
}, []);
|
|
@@ -605,7 +632,12 @@ const FormWithSubmit = ({ onLicenseSubmit, disabled = false, isSubmitting = fals
|
|
|
605
632
|
return (React.createElement("form", { className: `designbase-figma-form-with-submit ${className || ''}`, onSubmit: handleSubmit },
|
|
606
633
|
React.createElement("div", { className: "designbase-figma-form-with-submit__field" },
|
|
607
634
|
React.createElement("label", { className: "designbase-figma-form-with-submit__label" }, displayLabel),
|
|
608
|
-
React.createElement(Input, { value: inputValue, onChange:
|
|
635
|
+
React.createElement(Input, { value: inputValue, onChange: (event) => {
|
|
636
|
+
const value = event.detail?.value;
|
|
637
|
+
if (value !== undefined) {
|
|
638
|
+
handleChange(value);
|
|
639
|
+
}
|
|
640
|
+
}, placeholder: displayPlaceholder, helperText: displayHelperText, disabled: disabled || isSubmitting, size: "m" })),
|
|
609
641
|
React.createElement(Button, { type: "submit", variant: "primary", size: "m", loading: isSubmitting, disabled: !inputValue.trim() || isSubmitting || disabled, fullWidth: true }, isSubmitting ? displaySubmittingText : displaySubmitText)));
|
|
610
642
|
};
|
|
611
643
|
FormWithSubmit.displayName = 'FormWithSubmit';
|
|
@@ -626,6 +658,88 @@ const InteractionFeedback = ({ status = 'default', message, statusMessage, leftC
|
|
|
626
658
|
};
|
|
627
659
|
InteractionFeedback.displayName = 'InteractionFeedback';
|
|
628
660
|
|
|
661
|
+
function postPluginMessage(message) {
|
|
662
|
+
if (typeof parent === 'undefined') {
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
parent.postMessage({ pluginMessage: message }, '*');
|
|
666
|
+
}
|
|
667
|
+
function openExternalUrl(url) {
|
|
668
|
+
if (!url)
|
|
669
|
+
return;
|
|
670
|
+
postPluginMessage({ type: 'open-external-url', url });
|
|
671
|
+
if (typeof window !== 'undefined') {
|
|
672
|
+
window.open(url, '_blank', 'noopener,noreferrer');
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
const LicenseOffer = ({ membershipUrl, t, className }) => (React.createElement("section", { className: `designbase-figma-license-offer ${className || ''}`, "aria-labelledby": "designbase-license-offer-title" },
|
|
677
|
+
React.createElement("div", { className: "designbase-figma-license-offer__eyebrow" }, "YouTube Membership"),
|
|
678
|
+
React.createElement("h3", { id: "designbase-license-offer-title" }, resolveText(t, { key: 'license.youtube_membership_title' }, 'YouTube 멤버십으로 전체 플러그인 이용')),
|
|
679
|
+
React.createElement("p", null, resolveText(t, { key: 'license.youtube_membership_description' }, 'YouTube 멤버십에 가입하면 Designbase 플러그인을 무제한으로 사용할 수 있습니다.')),
|
|
680
|
+
React.createElement("ol", null,
|
|
681
|
+
React.createElement("li", null, "Designbase YouTube \uCC44\uB110\uC758 \uBA64\uBC84\uC2ED\uC5D0 \uAC00\uC785\uD569\uB2C8\uB2E4."),
|
|
682
|
+
React.createElement("li", null, "\uBA64\uBC84 \uC804\uC6A9 \uCEE4\uBBA4\uB2C8\uD2F0 \uAC8C\uC2DC\uAE00\uC5D0\uC11C \uC774\uBC88 \uB2EC \uB77C\uC774\uC120\uC2A4 \uD0A4\uB97C \uD655\uC778\uD569\uB2C8\uB2E4."),
|
|
683
|
+
React.createElement("li", null, "\uC544\uB798 \uC785\uB825\uCC3D\uC5D0 \uD0A4\uB97C \uBD99\uC5EC \uB123\uACE0 \uD65C\uC131\uD654\uD569\uB2C8\uB2E4.")),
|
|
684
|
+
membershipUrl && (React.createElement(Button, { onPress: () => openExternalUrl(membershipUrl), variant: "secondary", size: "m", fullWidth: true },
|
|
685
|
+
React.createElement("span", null, resolveText(t, { key: 'license.youtube_membership_cta' }, '멤버십 안내 보기')),
|
|
686
|
+
React.createElement(ExternalLinkIcon, { size: 16 })))));
|
|
687
|
+
LicenseOffer.displayName = 'LicenseOffer';
|
|
688
|
+
|
|
689
|
+
function maskLicenseKey(value) {
|
|
690
|
+
if (value.length <= 8)
|
|
691
|
+
return '••••••••';
|
|
692
|
+
return `${value.slice(0, 4)}••••${value.slice(-4)}`;
|
|
693
|
+
}
|
|
694
|
+
function formatDate(value) {
|
|
695
|
+
if (!value)
|
|
696
|
+
return undefined;
|
|
697
|
+
const date = new Date(value);
|
|
698
|
+
if (Number.isNaN(date.getTime()))
|
|
699
|
+
return value;
|
|
700
|
+
return new Intl.DateTimeFormat(undefined, { dateStyle: 'medium' }).format(date);
|
|
701
|
+
}
|
|
702
|
+
function formatScope(value) {
|
|
703
|
+
if (!value)
|
|
704
|
+
return undefined;
|
|
705
|
+
if (value === 'all-products' || value === 'all_products')
|
|
706
|
+
return '전체 제품';
|
|
707
|
+
return value;
|
|
708
|
+
}
|
|
709
|
+
const LicenseStatusCard = ({ status, licenseKey = '', licenseStatus, licenseSource, accessScope, expiresAt, lastVerifiedAt, validationMessage, allowRevealKey = true, t, className, }) => {
|
|
710
|
+
const [isKeyRevealed, setIsKeyRevealed] = useState(false);
|
|
711
|
+
const isActive = status === 'PAID';
|
|
712
|
+
const statusText = isActive
|
|
713
|
+
? resolveText(t, { key: 'license.status_active' }, 'Active')
|
|
714
|
+
: resolveText(t, { key: 'license.status_inactive' }, 'License check failed');
|
|
715
|
+
const statusClass = isActive ? 'active' : 'inactive';
|
|
716
|
+
return (React.createElement("section", { className: `designbase-figma-license-status-card designbase-figma-license-status-card--${statusClass} ${className || ''}`, "aria-label": statusText },
|
|
717
|
+
React.createElement("div", { className: "designbase-figma-license-status-card__header" },
|
|
718
|
+
React.createElement("div", null,
|
|
719
|
+
React.createElement("div", { className: "designbase-figma-license-status-card__eyebrow" }, isActive ? 'License Activated' : 'License Status'),
|
|
720
|
+
React.createElement("h3", null, statusText)),
|
|
721
|
+
React.createElement("span", { className: "designbase-figma-license-status-card__badge" }, licenseStatus || (isActive ? 'active' : 'inactive'))),
|
|
722
|
+
validationMessage && !isActive && (React.createElement("p", { className: "designbase-figma-license-status-card__message" }, validationMessage)),
|
|
723
|
+
licenseKey && (React.createElement("div", { className: "designbase-figma-license-status-card__key-row" },
|
|
724
|
+
React.createElement("span", null, resolveText(t, { key: 'license.key_label' }, '라이선스 키')),
|
|
725
|
+
React.createElement("code", null, allowRevealKey && isKeyRevealed ? licenseKey : maskLicenseKey(licenseKey)),
|
|
726
|
+
allowRevealKey && (React.createElement(Button, { type: "button", onPress: () => setIsKeyRevealed((value) => !value), variant: "tertiary", size: "s" }, isKeyRevealed ? '숨기기' : '보기')))),
|
|
727
|
+
(licenseSource || accessScope || expiresAt || lastVerifiedAt) && (React.createElement("dl", { className: "designbase-figma-license-status-card__meta" },
|
|
728
|
+
licenseSource && React.createElement(React.Fragment, null,
|
|
729
|
+
React.createElement("dt", null, "Source"),
|
|
730
|
+
React.createElement("dd", null, licenseSource)),
|
|
731
|
+
formatScope(accessScope) && React.createElement(React.Fragment, null,
|
|
732
|
+
React.createElement("dt", null, "Access"),
|
|
733
|
+
React.createElement("dd", null, formatScope(accessScope))),
|
|
734
|
+
expiresAt && React.createElement(React.Fragment, null,
|
|
735
|
+
React.createElement("dt", null, "Expires"),
|
|
736
|
+
React.createElement("dd", null, formatDate(expiresAt) || expiresAt)),
|
|
737
|
+
lastVerifiedAt && React.createElement(React.Fragment, null,
|
|
738
|
+
React.createElement("dt", null, "Last checked"),
|
|
739
|
+
React.createElement("dd", null, formatDate(lastVerifiedAt) || lastVerifiedAt))))));
|
|
740
|
+
};
|
|
741
|
+
LicenseStatusCard.displayName = 'LicenseStatusCard';
|
|
742
|
+
|
|
629
743
|
const defaultFeatures = [
|
|
630
744
|
{ name: '사용 제한', free: '일일 제한', pro: '무제한' },
|
|
631
745
|
{ name: '모든 주제 사용', free: false, pro: true },
|
|
@@ -658,18 +772,21 @@ const PricingComparison = ({ features = defaultFeatures, pricing = defaultPricin
|
|
|
658
772
|
};
|
|
659
773
|
return (React.createElement("div", { className: `designbase-figma-pricing-comparison ${className || ''}` },
|
|
660
774
|
paymentType === 'subscription' && (React.createElement("div", { className: "designbase-figma-pricing-comparison__billing-toggle" },
|
|
661
|
-
React.createElement(SegmentControl, { value: isYearly ? 'yearly' : 'monthly', onChange: (
|
|
775
|
+
React.createElement(SegmentControl, { value: isYearly ? 'yearly' : 'monthly', onChange: (event) => {
|
|
776
|
+
const detail = event.detail;
|
|
777
|
+
const value = typeof detail === 'object' && detail !== null && 'value' in detail &&
|
|
778
|
+
typeof detail.value === 'string'
|
|
779
|
+
? detail.value
|
|
780
|
+
: undefined;
|
|
781
|
+
setIsYearly(value === 'yearly');
|
|
782
|
+
}, options: [
|
|
662
783
|
{
|
|
663
784
|
value: 'monthly',
|
|
664
785
|
label: t('monthlyBilling') || '월간 결제',
|
|
665
786
|
},
|
|
666
787
|
{
|
|
667
788
|
value: 'yearly',
|
|
668
|
-
label: (
|
|
669
|
-
t('yearlyBilling') || '연간 결제',
|
|
670
|
-
React.createElement("span", { className: "designbase-figma-pricing-comparison__discount-badge" },
|
|
671
|
-
getDiscountPercentage(),
|
|
672
|
-
"% \uC808\uC57D"))),
|
|
789
|
+
label: `${t('yearlyBilling') || '연간 결제'} (${getDiscountPercentage()}% 절약)`,
|
|
673
790
|
},
|
|
674
791
|
], size: "s" }))),
|
|
675
792
|
paymentType === 'lifetime' && (React.createElement("div", { className: "designbase-figma-pricing-comparison__lifetime-info" },
|
|
@@ -697,123 +814,301 @@ const PricingComparison = ({ features = defaultFeatures, pricing = defaultPricin
|
|
|
697
814
|
};
|
|
698
815
|
PricingComparison.displayName = 'PricingComparison';
|
|
699
816
|
|
|
700
|
-
const
|
|
701
|
-
|
|
817
|
+
const DEFAULT_LICENSE_MESSAGE_TYPES = {
|
|
818
|
+
initialize: 'initialize',
|
|
819
|
+
verifyLicense: 'verify-license',
|
|
820
|
+
deactivateLicense: 'deactivate-license',
|
|
821
|
+
updateStatus: 'update-plugin-status',
|
|
822
|
+
verifyResult: 'license-verification-result',
|
|
823
|
+
deactivateResult: 'license-deactivation-result',
|
|
824
|
+
};
|
|
825
|
+
const START_DESIGNBASE_AUTH_MESSAGE = 'start-designbase-auth';
|
|
826
|
+
const INITIAL_LICENSE_PAGE_STATE = {
|
|
827
|
+
paymentStatus: 'FREE',
|
|
828
|
+
licenseKey: '',
|
|
829
|
+
planTier: 'FREE',
|
|
830
|
+
hasLicenseKey: false,
|
|
831
|
+
isLicenseRegistered: false,
|
|
832
|
+
activationLimit: 0,
|
|
833
|
+
activationUsage: 0,
|
|
834
|
+
usageCount: 0,
|
|
835
|
+
remainingUsage: 0,
|
|
836
|
+
usageUsed: 0,
|
|
837
|
+
usageLimit: 0,
|
|
838
|
+
usageReset: 'none',
|
|
839
|
+
canUseFeature: true,
|
|
840
|
+
};
|
|
841
|
+
|
|
842
|
+
function readString(data, keys) {
|
|
843
|
+
for (const key of keys) {
|
|
844
|
+
const value = data[key];
|
|
845
|
+
if (typeof value === 'string') {
|
|
846
|
+
return value;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
return '';
|
|
850
|
+
}
|
|
851
|
+
function readNumber(data, keys) {
|
|
852
|
+
for (const key of keys) {
|
|
853
|
+
const value = data[key];
|
|
854
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
855
|
+
return value;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
return undefined;
|
|
859
|
+
}
|
|
860
|
+
function readBoolean(data, keys) {
|
|
861
|
+
for (const key of keys) {
|
|
862
|
+
const value = data[key];
|
|
863
|
+
if (typeof value === 'boolean') {
|
|
864
|
+
return value;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
return undefined;
|
|
868
|
+
}
|
|
869
|
+
function parseLicenseMessage(data) {
|
|
870
|
+
const paymentStatus = readString(data, ['paymentStatus', 'status']);
|
|
871
|
+
const usageLimitRaw = data.usageLimit;
|
|
872
|
+
return {
|
|
873
|
+
...(paymentStatus ? { paymentStatus } : {}),
|
|
874
|
+
licenseKey: readString(data, ['licenseKey']) || undefined,
|
|
875
|
+
planTier: readString(data, ['planTier']) || undefined,
|
|
876
|
+
hasLicenseKey: readBoolean(data, ['hasLicenseKey']),
|
|
877
|
+
isLicenseRegistered: readBoolean(data, ['isLicenseRegistered']),
|
|
878
|
+
activationLimit: readNumber(data, ['activationLimit']),
|
|
879
|
+
activationUsage: readNumber(data, ['activationUsage']),
|
|
880
|
+
usageCount: readNumber(data, ['usageCount']),
|
|
881
|
+
remainingUsage: readNumber(data, ['remainingUsage']),
|
|
882
|
+
usageUsed: readNumber(data, ['usageUsed']),
|
|
883
|
+
usageLimit: usageLimitRaw === 'unlimited' ? 'unlimited' : readNumber(data, ['usageLimit']),
|
|
884
|
+
usageReset: readString(data, ['usageReset']) || undefined,
|
|
885
|
+
canUseFeature: readBoolean(data, ['canUseFeature']),
|
|
886
|
+
usageReason: readString(data, ['usageReason']) || undefined,
|
|
887
|
+
lastMessage: readString(data, ['message']) || undefined,
|
|
888
|
+
lastErrorCode: readString(data, ['errorCode']) || undefined,
|
|
889
|
+
licenseStatus: readString(data, ['licenseStatus', 'license_status']) || undefined,
|
|
890
|
+
licenseSource: readString(data, ['licenseSource', 'license_source', 'source']) || undefined,
|
|
891
|
+
accessScope: readString(data, ['accessScope', 'access_scope', 'scope']) || undefined,
|
|
892
|
+
expiresAt: readString(data, ['expiresAt', 'expires_at']) || undefined,
|
|
893
|
+
lastVerifiedAt: readString(data, ['lastVerifiedAt', 'last_verified_at']) || undefined,
|
|
894
|
+
validationMessage: readString(data, ['validationMessage', 'validation_message']) || undefined,
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
function useFigmaLicenseBridge(options = {}) {
|
|
898
|
+
const messageTypes = useMemo(() => ({ ...DEFAULT_LICENSE_MESSAGE_TYPES, ...options.messageTypes }), [options.messageTypes]);
|
|
899
|
+
const [state, setState] = useState({
|
|
900
|
+
...INITIAL_LICENSE_PAGE_STATE,
|
|
901
|
+
...options.initialState,
|
|
902
|
+
});
|
|
903
|
+
const [isVerifying, setIsVerifying] = useState(false);
|
|
702
904
|
const [isDeactivating, setIsDeactivating] = useState(false);
|
|
703
|
-
const [
|
|
704
|
-
const
|
|
705
|
-
|
|
706
|
-
const
|
|
707
|
-
|
|
708
|
-
|
|
905
|
+
const [isStartingAuth, setIsStartingAuth] = useState(false);
|
|
906
|
+
const optionsRef = useRef(options);
|
|
907
|
+
optionsRef.current = options;
|
|
908
|
+
const applyPatch = useCallback((patch) => {
|
|
909
|
+
setState((prev) => {
|
|
910
|
+
const next = {
|
|
911
|
+
...prev,
|
|
912
|
+
...Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== undefined)),
|
|
913
|
+
};
|
|
914
|
+
optionsRef.current.onStateChange?.(next);
|
|
915
|
+
if (patch.paymentStatus) {
|
|
916
|
+
optionsRef.current.onPaymentStatusChange?.(patch.paymentStatus);
|
|
917
|
+
}
|
|
918
|
+
if (patch.usageCount !== undefined) {
|
|
919
|
+
optionsRef.current.onUsageCountChange?.(patch.usageCount);
|
|
920
|
+
}
|
|
921
|
+
return next;
|
|
922
|
+
});
|
|
923
|
+
}, []);
|
|
709
924
|
useEffect(() => {
|
|
710
925
|
const handleMessage = (event) => {
|
|
711
|
-
const
|
|
712
|
-
if (
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
setActivationLimit(activationLimit);
|
|
719
|
-
if (activationUsage !== undefined)
|
|
720
|
-
setActivationUsage(activationUsage);
|
|
721
|
-
if (paymentStatus)
|
|
722
|
-
setPaymentStatus(paymentStatus);
|
|
723
|
-
if (usageCount !== undefined) {
|
|
724
|
-
setLocalUsageCount(usageCount);
|
|
725
|
-
setUsageCount(usageCount);
|
|
726
|
-
}
|
|
926
|
+
const data = event.data?.pluginMessage;
|
|
927
|
+
if (!data || typeof data !== 'object')
|
|
928
|
+
return;
|
|
929
|
+
const payload = data;
|
|
930
|
+
const type = typeof payload.type === 'string' ? payload.type : '';
|
|
931
|
+
if (type === messageTypes.updateStatus) {
|
|
932
|
+
applyPatch(parseLicenseMessage(payload));
|
|
727
933
|
}
|
|
728
|
-
if (type ===
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
if (success) {
|
|
733
|
-
|
|
734
|
-
setPaymentStatus('PAID');
|
|
934
|
+
if (type === messageTypes.verifyResult) {
|
|
935
|
+
setIsVerifying(false);
|
|
936
|
+
setIsStartingAuth(false);
|
|
937
|
+
applyPatch(parseLicenseMessage(payload));
|
|
938
|
+
if (payload.success === true) {
|
|
939
|
+
applyPatch({ paymentStatus: 'PAID', isLicenseRegistered: true });
|
|
735
940
|
}
|
|
736
941
|
}
|
|
737
|
-
if (type ===
|
|
942
|
+
if (type === messageTypes.deactivateResult) {
|
|
738
943
|
setIsDeactivating(false);
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
944
|
+
applyPatch(parseLicenseMessage(payload));
|
|
945
|
+
if (payload.success === true) {
|
|
946
|
+
applyPatch({
|
|
947
|
+
paymentStatus: 'UNPAID',
|
|
948
|
+
licenseKey: '',
|
|
949
|
+
hasLicenseKey: false,
|
|
950
|
+
isLicenseRegistered: false,
|
|
951
|
+
activationLimit: 0,
|
|
952
|
+
activationUsage: 0,
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
if (type === 'designbase-auth-result') {
|
|
957
|
+
setIsStartingAuth(false);
|
|
958
|
+
if (payload.success === true) {
|
|
959
|
+
applyPatch(parseLicenseMessage(payload));
|
|
960
|
+
}
|
|
961
|
+
else if (typeof payload.message === 'string') {
|
|
962
|
+
applyPatch({ lastMessage: payload.message });
|
|
748
963
|
}
|
|
749
964
|
}
|
|
750
965
|
};
|
|
751
966
|
window.addEventListener('message', handleMessage);
|
|
752
|
-
|
|
753
|
-
parent.postMessage({ pluginMessage: { type: 'initialize' } }, '*');
|
|
754
|
-
}
|
|
967
|
+
postPluginMessage({ type: messageTypes.initialize });
|
|
755
968
|
return () => window.removeEventListener('message', handleMessage);
|
|
756
|
-
}, [
|
|
969
|
+
}, [applyPatch, messageTypes]);
|
|
970
|
+
const verifyLicense = useCallback((licenseKey) => {
|
|
971
|
+
setIsVerifying(true);
|
|
972
|
+
postPluginMessage({
|
|
973
|
+
type: messageTypes.verifyLicense,
|
|
974
|
+
licenseKey,
|
|
975
|
+
});
|
|
976
|
+
}, [messageTypes.verifyLicense]);
|
|
977
|
+
const deactivateLicense = useCallback(() => {
|
|
978
|
+
setIsDeactivating(true);
|
|
979
|
+
postPluginMessage({ type: messageTypes.deactivateLicense });
|
|
980
|
+
}, [messageTypes.deactivateLicense]);
|
|
981
|
+
const startDesignbaseAuth = useCallback(() => {
|
|
982
|
+
setIsStartingAuth(true);
|
|
983
|
+
postPluginMessage({ type: START_DESIGNBASE_AUTH_MESSAGE });
|
|
984
|
+
}, []);
|
|
985
|
+
return {
|
|
986
|
+
state,
|
|
987
|
+
isVerifying,
|
|
988
|
+
isDeactivating,
|
|
989
|
+
isStartingAuth,
|
|
990
|
+
verifyLicense,
|
|
991
|
+
deactivateLicense,
|
|
992
|
+
startDesignbaseAuth,
|
|
993
|
+
setLicenseKeyInput: (licenseKey) => applyPatch({ licenseKey }),
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
function formatUsageLabel(state, t) {
|
|
998
|
+
const { remainingUsage, usageUsed, usageLimit, usageReset } = state;
|
|
999
|
+
if (usageLimit === 'unlimited') {
|
|
1000
|
+
return resolveText(t, { key: 'license.usage_unlimited' }, '사용 횟수 제한 없음') ?? '사용 횟수 제한 없음';
|
|
1001
|
+
}
|
|
1002
|
+
const limit = typeof usageLimit === 'number' ? usageLimit : remainingUsage + usageUsed;
|
|
1003
|
+
const remaining = remainingUsage ?? Math.max(0, limit - usageUsed);
|
|
1004
|
+
if (usageReset === 'daily') {
|
|
1005
|
+
const fallback = `오늘 남은 횟수 ${remaining}/${limit}`;
|
|
1006
|
+
const translated = resolveText(t, { key: 'license.usage_daily' }, fallback) ?? fallback;
|
|
1007
|
+
return translated.includes(String(remaining)) ? translated : fallback;
|
|
1008
|
+
}
|
|
1009
|
+
if (usageReset === 'monthly') {
|
|
1010
|
+
const fallback = `이번 달 남은 횟수 ${remaining}/${limit}`;
|
|
1011
|
+
const translated = resolveText(t, { key: 'license.usage_monthly' }, fallback) ?? fallback;
|
|
1012
|
+
return translated.includes(String(remaining)) ? translated : fallback;
|
|
1013
|
+
}
|
|
1014
|
+
return `남은 횟수 ${remaining}/${limit}`;
|
|
1015
|
+
}
|
|
1016
|
+
const PageLicense = ({ status: initialStatus, onClose, licenseKey: initialLicenseKey = '', wordpressLinks, paymentPageUrl, mode = 'pricing', membershipUrl, enableAccountAuth = true, showLicenseKeyInput = true, pricingFeatures, pricing, paymentType = 'subscription', messageTypes, onStateChange, setPaymentStatus, setUsageCount, onLicenseSubmit, usageCount: initialUsageCount = 0, t, className, }) => {
|
|
1017
|
+
const links = useMemo(() => ({
|
|
1018
|
+
purchaseUrl: wordpressLinks?.purchaseUrl ?? paymentPageUrl,
|
|
1019
|
+
membershipUrl: membershipUrl ?? wordpressLinks?.membershipUrl,
|
|
1020
|
+
accountUrl: wordpressLinks?.accountUrl,
|
|
1021
|
+
helpUrl: wordpressLinks?.helpUrl,
|
|
1022
|
+
}), [wordpressLinks, paymentPageUrl, membershipUrl]);
|
|
1023
|
+
const { state, isVerifying, isDeactivating, isStartingAuth, verifyLicense, deactivateLicense, startDesignbaseAuth, setLicenseKeyInput, } = useFigmaLicenseBridge({
|
|
1024
|
+
messageTypes,
|
|
1025
|
+
initialState: {
|
|
1026
|
+
paymentStatus: initialStatus,
|
|
1027
|
+
licenseKey: initialLicenseKey,
|
|
1028
|
+
usageCount: initialUsageCount,
|
|
1029
|
+
},
|
|
1030
|
+
onStateChange,
|
|
1031
|
+
onPaymentStatusChange: setPaymentStatus,
|
|
1032
|
+
onUsageCountChange: setUsageCount,
|
|
1033
|
+
});
|
|
1034
|
+
const [showDetails, setShowDetails] = useState(false);
|
|
1035
|
+
const [licenseKeyDraft, setLicenseKeyDraft] = useState(initialLicenseKey);
|
|
1036
|
+
const isPaid = state.isLicenseRegistered && state.paymentStatus === 'PAID';
|
|
1037
|
+
const isMembershipMode = mode === 'youtube-membership';
|
|
1038
|
+
const usageLabel = formatUsageLabel(state, t);
|
|
757
1039
|
const handleLicenseSubmit = async (submittedLicenseKey) => {
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
pluginMessage: {
|
|
762
|
-
type: 'verify-license',
|
|
763
|
-
licenseKey: submittedLicenseKey
|
|
764
|
-
}
|
|
765
|
-
}, '*');
|
|
1040
|
+
if (onLicenseSubmit) {
|
|
1041
|
+
await onLicenseSubmit(submittedLicenseKey);
|
|
1042
|
+
return;
|
|
766
1043
|
}
|
|
1044
|
+
verifyLicense(submittedLicenseKey);
|
|
767
1045
|
};
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
parent.postMessage({
|
|
772
|
-
pluginMessage: { type: 'deactivate-license' }
|
|
773
|
-
}, '*');
|
|
774
|
-
}
|
|
1046
|
+
const handleLicenseKeyChange = (value) => {
|
|
1047
|
+
setLicenseKeyDraft(value);
|
|
1048
|
+
setLicenseKeyInput(value);
|
|
775
1049
|
};
|
|
776
|
-
const isPaid = status === 'PAID';
|
|
777
1050
|
return (React.createElement("div", { className: `designbase-figma-page-license ${className || ''}` },
|
|
778
1051
|
React.createElement("div", { className: "designbase-figma-page-license__content" },
|
|
779
1052
|
React.createElement("div", { className: "designbase-figma-page-license__header" },
|
|
780
1053
|
React.createElement("div", { className: "designbase-figma-page-license__title" },
|
|
781
|
-
React.createElement("h2", null,
|
|
1054
|
+
React.createElement("h2", null, isMembershipMode
|
|
1055
|
+
? resolveText(t, { key: 'license.youtube_membership' }, 'YouTube 멤버십')
|
|
1056
|
+
: isPaid
|
|
1057
|
+
? resolveText(t, { key: 'license.pro_account' }, '프로 계정')
|
|
1058
|
+
: resolveText(t, { key: 'license.upgrade_to_pro' }, '프로로 업그레이드')),
|
|
1059
|
+
state.planTier && state.planTier !== 'FREE' && (React.createElement("span", { className: "designbase-figma-page-license__tier" }, state.planTier))),
|
|
782
1060
|
React.createElement("p", { className: "designbase-figma-page-license__description" }, isPaid
|
|
783
1061
|
? resolveText(t, { key: 'license.all_features_available' }, '모든 기능을 사용할 수 있습니다.')
|
|
784
|
-
:
|
|
785
|
-
|
|
1062
|
+
: isMembershipMode
|
|
1063
|
+
? resolveText(t, { key: 'license.youtube_membership_description' }, 'YouTube 멤버십에 가입하면 Designbase 플러그인을 무제한으로 사용할 수 있습니다.')
|
|
1064
|
+
: resolveText(t, { key: 'license.purchase_for_unlimited' }, '디자인베이스 멤버십 또는 라이선스로 무제한 이용이 가능합니다.')),
|
|
1065
|
+
!isPaid && (React.createElement("p", { className: "designbase-figma-page-license__usage" }, usageLabel))),
|
|
1066
|
+
!isMembershipMode && (React.createElement(PricingComparison, { features: pricingFeatures, pricing: pricing, paymentType: paymentType, t: t })),
|
|
1067
|
+
state.lastMessage && (React.createElement("p", { className: `designbase-figma-page-license__feedback ${state.lastErrorCode ? 'designbase-figma-page-license__feedback--error' : ''}` }, state.lastMessage)),
|
|
786
1068
|
isPaid && (React.createElement("div", { className: "designbase-figma-page-license__section" },
|
|
787
1069
|
React.createElement("div", { className: "designbase-figma-page-license__section-header" },
|
|
788
1070
|
React.createElement("h3", null, resolveText(t, { key: 'license.activated' }, '라이선스 활성화됨')),
|
|
789
|
-
React.createElement(Button, {
|
|
1071
|
+
React.createElement(Button, { onPress: () => setShowDetails(!showDetails), variant: "tertiary", size: "s", iconOnly: true },
|
|
790
1072
|
React.createElement(MoreHorizontalIcon, { size: 16 }))),
|
|
791
|
-
React.createElement(
|
|
792
|
-
|
|
793
|
-
": ",
|
|
794
|
-
React.createElement("span", null, licenseKey)),
|
|
1073
|
+
React.createElement(LicenseStatusCard, { status: state.paymentStatus, licenseKey: state.licenseKey, licenseStatus: state.licenseStatus, licenseSource: state.licenseSource, accessScope: state.accessScope, expiresAt: state.expiresAt, lastVerifiedAt: state.lastVerifiedAt, validationMessage: state.validationMessage, t: t }),
|
|
1074
|
+
React.createElement("p", { className: "designbase-figma-page-license__usage" }, usageLabel),
|
|
795
1075
|
showDetails && (React.createElement("div", { className: "designbase-figma-page-license__details" },
|
|
796
1076
|
React.createElement("div", { className: "designbase-figma-page-license__activation-info" },
|
|
797
1077
|
React.createElement("div", { className: "designbase-figma-page-license__remaining" },
|
|
798
|
-
activationLimit - activationUsage,
|
|
799
|
-
|
|
1078
|
+
Math.max(0, state.activationLimit - state.activationUsage),
|
|
1079
|
+
' ',
|
|
800
1080
|
resolveText(t, { key: 'license.activations_remaining' }, '활성'),
|
|
801
|
-
|
|
1081
|
+
' ',
|
|
802
1082
|
resolveText(t, { key: 'license.spots_remaining' }, '자리 남음')),
|
|
803
|
-
React.createElement("div", { className: "designbase-figma-page-license__usage" },
|
|
804
|
-
activationUsage,
|
|
1083
|
+
React.createElement("div", { className: "designbase-figma-page-license__usage-count" },
|
|
1084
|
+
state.activationUsage,
|
|
805
1085
|
"/",
|
|
806
|
-
activationLimit)),
|
|
807
|
-
React.createElement(Button, {
|
|
808
|
-
? resolveText(t, { key: 'license.deactivating' }, '
|
|
1086
|
+
state.activationLimit)),
|
|
1087
|
+
React.createElement(Button, { onPress: deactivateLicense, variant: "tertiary", size: "s", disabled: isDeactivating }, isDeactivating
|
|
1088
|
+
? resolveText(t, { key: 'license.deactivating' }, '비활성화 중...')
|
|
809
1089
|
: resolveText(t, { key: 'license.deactivate' }, '라이선스 비활성화')))))),
|
|
810
|
-
!isPaid && (React.createElement(
|
|
811
|
-
React.createElement(
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
React.createElement("
|
|
815
|
-
|
|
816
|
-
|
|
1090
|
+
!isPaid && (React.createElement(React.Fragment, null,
|
|
1091
|
+
isMembershipMode && (React.createElement(LicenseOffer, { membershipUrl: links.membershipUrl || links.purchaseUrl, t: t })),
|
|
1092
|
+
!isMembershipMode && (enableAccountAuth || links.purchaseUrl || links.accountUrl) && (React.createElement("div", { className: "designbase-figma-page-license__section" },
|
|
1093
|
+
React.createElement("div", { className: "designbase-figma-page-license__section-header" },
|
|
1094
|
+
React.createElement("h3", null, resolveText(t, { key: 'license.designbase_account' }, '디자인베이스 계정'))),
|
|
1095
|
+
React.createElement("p", { className: "designbase-figma-page-license__hint" }, resolveText(t, { key: 'license.designbase_account_hint' }, 'WordPress 계정으로 로그인하거나 멤버십을 구매하면 플러그인이 자동으로 활성화됩니다.')),
|
|
1096
|
+
React.createElement("div", { className: "designbase-figma-page-license__actions" },
|
|
1097
|
+
enableAccountAuth && (React.createElement(Button, { onPress: startDesignbaseAuth, variant: "primary", size: "m", disabled: isStartingAuth || isVerifying, fullWidth: true }, isStartingAuth
|
|
1098
|
+
? resolveText(t, { key: 'license.authenticating' }, '인증 중...')
|
|
1099
|
+
: resolveText(t, { key: 'license.login_with_designbase' }, '디자인베이스로 로그인'))),
|
|
1100
|
+
links.purchaseUrl && (React.createElement(Button, { onPress: () => openExternalUrl(links.purchaseUrl), variant: "secondary", size: "m", fullWidth: true },
|
|
1101
|
+
React.createElement("span", null, resolveText(t, { key: 'license.purchase_membership' }, '멤버십 안내')),
|
|
1102
|
+
React.createElement(ExternalLinkIcon, { size: 16 }))),
|
|
1103
|
+
links.accountUrl && (React.createElement(Button, { onPress: () => openExternalUrl(links.accountUrl), variant: "tertiary", size: "s", fullWidth: true },
|
|
1104
|
+
React.createElement("span", null, resolveText(t, { key: 'license.manage_account' }, '계정·멤버십 관리')),
|
|
1105
|
+
React.createElement(ExternalLinkIcon, { size: 16 })))))),
|
|
1106
|
+
showLicenseKeyInput && (React.createElement("div", { className: "designbase-figma-page-license__section" },
|
|
1107
|
+
React.createElement("div", { className: "designbase-figma-page-license__section-header" },
|
|
1108
|
+
React.createElement("h3", null, resolveText(t, { key: 'license.enter_key' }, '라이선스 키 입력'))),
|
|
1109
|
+
React.createElement(FormWithSubmit, { onLicenseSubmit: handleLicenseSubmit, disabled: false, isSubmitting: isVerifying, value: licenseKeyDraft, onValueChange: handleLicenseKeyChange, label: { key: 'license.key' }, submitText: { key: 'license.submit' }, submittingText: { key: 'license.verifying' }, helperText: { key: 'license.enter_from_email' }, t: t }))))),
|
|
1110
|
+
links.helpUrl && (React.createElement("p", { className: "designbase-figma-page-license__disclaimer" },
|
|
1111
|
+
React.createElement("button", { type: "button", className: "designbase-figma-page-license__link", onClick: () => openExternalUrl(links.helpUrl) }, resolveText(t, { key: 'license.help_link' }, '라이선스·결제 도움말'))))),
|
|
817
1112
|
React.createElement(Button, { className: "designbase-figma-page-license__close", onPress: onClose, variant: "tertiary", size: "s", "aria-label": "Close" },
|
|
818
1113
|
React.createElement(CloseIcon, { size: 20 }))));
|
|
819
1114
|
};
|
|
@@ -838,7 +1133,7 @@ const PaymentStatusSection = ({ status, usageCount, activationLimit, activationU
|
|
|
838
1133
|
activationUsage,
|
|
839
1134
|
"/",
|
|
840
1135
|
activationLimit)),
|
|
841
|
-
React.createElement(Button, {
|
|
1136
|
+
React.createElement(Button, { onPress: onDeactivate, variant: "tertiary", size: "s", disabled: isDeactivating }, isDeactivating
|
|
842
1137
|
? resolveText(t, { key: 'payment.deactivating' }, '비활성화중...')
|
|
843
1138
|
: resolveText(t, { key: 'payment.deactivate_license' }, '라이선스 비활성화'))))));
|
|
844
1139
|
};
|
|
@@ -1087,11 +1382,11 @@ const UpgradeBanner = ({ onClick, variant = 'button', isLoading = false, title =
|
|
|
1087
1382
|
React.createElement("div", { className: "designbase-figma-upgrade-banner__text-wrap" },
|
|
1088
1383
|
React.createElement("h3", { className: "designbase-figma-upgrade-banner__title" }, displayTitle),
|
|
1089
1384
|
React.createElement("p", { className: "designbase-figma-upgrade-banner__text" }, displayDescription)),
|
|
1090
|
-
variant === 'button' ? (React.createElement(Button, {
|
|
1385
|
+
variant === 'button' ? (React.createElement(Button, { onPress: onClick, variant: "primary", size: "m", disabled: isLoading }, displayButtonText)) : (React.createElement("div", { className: "designbase-figma-upgrade-banner__icon" },
|
|
1091
1386
|
React.createElement(ChevronRightIcon, { size: 20 })))));
|
|
1092
1387
|
return (React.createElement("div", { className: `designbase-figma-upgrade-banner designbase-figma-upgrade-banner--${variant} ${className || ''}` }, useGradient ? (React.createElement(RandomGradient, { scheme: gradientScheme, tone: gradientTone, animated: gradientAnimated, height: "100%", width: "100%", className: "designbase-figma-upgrade-banner__gradient-bg" }, bannerContent)) : (bannerContent)));
|
|
1093
1388
|
};
|
|
1094
1389
|
UpgradeBanner.displayName = 'UpgradeBanner';
|
|
1095
1390
|
|
|
1096
|
-
export { DonationBadge, FigmaContainer, FigmaFooter, FigmaHeader, FigmaPageHead, FigmaSection, FigmaSidebar, FigmaToast, FigmaToastProvider, FormWithSubmit, InteractionFeedback, LanguageSelector, LogoDropdown, PageLicense, PaymentBadge, PaymentStatusSection, PricingComparison, ProgressModal, ResizablePlugin, SettingsModal, TitleDescription, UpgradeBanner, getActiveSection, resolveText, scrollToSection, useFigmaToast, useToast };
|
|
1391
|
+
export { DEFAULT_LICENSE_MESSAGE_TYPES, DonationBadge, FigmaContainer, FigmaFooter, FigmaHeader, FigmaPageHead, FigmaSection, FigmaSidebar, FigmaToast, FigmaToastProvider, FormWithSubmit, InteractionFeedback, LanguageSelector, LicenseOffer, LicenseStatusCard, LogoDropdown, PageLicense, PaymentBadge, PaymentStatusSection, PricingComparison, ProgressModal, ResizablePlugin, START_DESIGNBASE_AUTH_MESSAGE, SettingsModal, TitleDescription, UpgradeBanner, getActiveSection, resolveText, scrollToSection, useFigmaLicenseBridge, useFigmaToast, useToast };
|
|
1097
1392
|
//# sourceMappingURL=index.esm.js.map
|