@burdenoff/microfe-devportal 2026.609.4 → 2026.611.2

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.
Files changed (58) hide show
  1. package/dist/devportal/DevportalRoot.js +6 -1
  2. package/dist/devportal/DevportalRoot.js.map +1 -1
  3. package/dist/devportal/DevportalRoutes.js +169 -158
  4. package/dist/devportal/DevportalRoutes.js.map +1 -1
  5. package/dist/devportal/hooks/usePackageUpload.js +120 -0
  6. package/dist/devportal/hooks/usePackageUpload.js.map +1 -0
  7. package/dist/devportal/pages/AnalyticsDashboardPage.js +73 -62
  8. package/dist/devportal/pages/AnalyticsDashboardPage.js.map +1 -1
  9. package/dist/devportal/pages/AppLogsPage.js +89 -82
  10. package/dist/devportal/pages/AppLogsPage.js.map +1 -1
  11. package/dist/devportal/pages/ApplicationDetailPage.js +948 -367
  12. package/dist/devportal/pages/ApplicationDetailPage.js.map +1 -1
  13. package/dist/devportal/pages/ApplicationVersionsPage.js +56 -45
  14. package/dist/devportal/pages/ApplicationVersionsPage.js.map +1 -1
  15. package/dist/devportal/pages/CreateApiKeyPage.js +30 -32
  16. package/dist/devportal/pages/CreateApiKeyPage.js.map +1 -1
  17. package/dist/devportal/pages/CreateApplicationPage.js +8 -3
  18. package/dist/devportal/pages/CreateApplicationPage.js.map +1 -1
  19. package/dist/devportal/pages/CreateOAuthClientPage.js +4 -4
  20. package/dist/devportal/pages/CreateOAuthClientPage.js.map +1 -1
  21. package/dist/devportal/pages/CreateOrganizationPage.js +238 -229
  22. package/dist/devportal/pages/CreateOrganizationPage.js.map +1 -1
  23. package/dist/devportal/pages/CreateWebhookPage.js +159 -148
  24. package/dist/devportal/pages/CreateWebhookPage.js.map +1 -1
  25. package/dist/devportal/pages/DelegationsPage.js +1 -1
  26. package/dist/devportal/pages/DelegationsPage.js.map +1 -1
  27. package/dist/devportal/pages/EditApplicationPage.js +25 -17
  28. package/dist/devportal/pages/EditApplicationPage.js.map +1 -1
  29. package/dist/devportal/pages/ListingPreviewPage.js +159 -153
  30. package/dist/devportal/pages/ListingPreviewPage.js.map +1 -1
  31. package/dist/devportal/pages/OAuthClientDetailPage.js.map +1 -1
  32. package/dist/devportal/pages/OAuthClientsPage.js +2 -2
  33. package/dist/devportal/pages/OAuthClientsPage.js.map +1 -1
  34. package/dist/devportal/pages/OrganizationDetailPage.js +158 -153
  35. package/dist/devportal/pages/OrganizationDetailPage.js.map +1 -1
  36. package/dist/devportal/pages/OrganizationMembersPage.js +223 -212
  37. package/dist/devportal/pages/OrganizationMembersPage.js.map +1 -1
  38. package/dist/devportal/pages/PublishPage.js +172 -165
  39. package/dist/devportal/pages/PublishPage.js.map +1 -1
  40. package/dist/devportal/pages/ResourcesPage.js.map +1 -1
  41. package/dist/devportal/pages/RevenueDashboardPage.js +461 -0
  42. package/dist/devportal/pages/RevenueDashboardPage.js.map +1 -0
  43. package/dist/devportal/pages/SetupPage.js +186 -181
  44. package/dist/devportal/pages/SetupPage.js.map +1 -1
  45. package/dist/devportal/pages/StoreSubmissionPage.js +76 -97
  46. package/dist/devportal/pages/StoreSubmissionPage.js.map +1 -1
  47. package/dist/devportal/pages/WebhookDetailPage.js +172 -154
  48. package/dist/devportal/pages/WebhookDetailPage.js.map +1 -1
  49. package/dist/devportal/pages/WebhooksPage.js +218 -200
  50. package/dist/devportal/pages/WebhooksPage.js.map +1 -1
  51. package/dist/devportal/providers/DevportalProvider.js +16 -13
  52. package/dist/devportal/providers/DevportalProvider.js.map +1 -1
  53. package/dist/devportal/types/index.js.map +1 -1
  54. package/dist/generated/global-operations.js +334 -223
  55. package/dist/generated/global-operations.js.map +1 -1
  56. package/package.json +1 -1
  57. package/dist/devportal/pages/RevenueRedirectPage.js +0 -14
  58. package/dist/devportal/pages/RevenueRedirectPage.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PublishPage.js","names":[],"sources":["../../../src/devportal/pages/PublishPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState, useMemo } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n CheckCircle,\n XCircle,\n AlertTriangle,\n Send,\n FileText,\n Shield,\n Image,\n Globe,\n Loader2,\n Eye,\n} from \"lucide-react\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { Alert } from \"../components/ConfirmDialog\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport {\n useGetApplicationQuery,\n useSubmitApplicationMutation,\n} from \"../../generated/global-operations\";\nimport { useDevportalPermission } from \"../hooks\";\n\ninterface ChecklistItem {\n id: string;\n label: string;\n description: string;\n status: \"passed\" | \"failed\" | \"warning\" | \"pending\";\n icon: React.ReactNode;\n}\n\nconst ALREADY_SUBMITTED_STATUSES = [\n \"SUBMITTED\",\n \"IN_REVIEW\",\n \"APPROVED\",\n \"PUBLISHED\",\n];\n\nexport const PublishPage: FC = () => {\n const { appId } = useParams<{ appId: string }>();\n const { navigate, basePath } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const [submitting, setSubmitting] = useState(false);\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [notes, setNotes] = useState(\"\");\n const submitPerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_SUBMIT);\n\n const {\n data,\n loading,\n error: queryError,\n } = useGetApplicationQuery({\n variables: { id: appId! },\n skip: !appId,\n fetchPolicy: \"network-only\",\n });\n\n const [submitApplication] = useSubmitApplicationMutation();\n\n const app = data?.application;\n const isAlreadySubmitted = ALREADY_SUBMITTED_STATUSES.includes(\n app?.status ?? \"\",\n );\n\n const checklist = useMemo((): ChecklistItem[] => {\n if (!app) return [];\n\n const screenshotCount = app.screenshots?.length ?? 0;\n\n return [\n {\n id: \"name\",\n label: tr(\"devportal.checklistNameLabel\", \"App Name & Description\"),\n description: tr(\n \"devportal.checklistNameDesc\",\n \"Name and short description are required\",\n ),\n status: app.name && app.shortDescription ? \"passed\" : \"failed\",\n icon: <FileText size={20} />,\n },\n {\n id: \"category\",\n label: tr(\"devportal.checklistCategoryLabel\", \"Category\"),\n description: tr(\n \"devportal.checklistCategoryDesc\",\n \"A category must be selected\",\n ),\n status: app.category ? \"passed\" : \"failed\",\n icon: <Globe size={20} />,\n },\n {\n id: \"privacy\",\n label: tr(\"devportal.checklistPrivacyLabel\", \"Privacy Policy\"),\n description: tr(\n \"devportal.checklistPrivacyDesc\",\n \"Privacy policy URL is required\",\n ),\n status: app.privacyPolicyUrl ? \"passed\" : \"failed\",\n icon: <Shield size={20} />,\n },\n {\n id: \"terms\",\n label: tr(\"devportal.checklistTermsLabel\", \"Terms of Service\"),\n description: tr(\n \"devportal.checklistTermsDesc\",\n \"Terms of service URL is required\",\n ),\n status: app.termsOfServiceUrl ? \"passed\" : \"failed\",\n icon: <FileText size={20} />,\n },\n {\n id: \"icon\",\n label: tr(\"devportal.checklistIconLabel\", \"App Icon\"),\n description: tr(\n \"devportal.checklistIconDesc\",\n \"An icon URL is recommended\",\n ),\n status: app.iconUrl ? \"passed\" : \"warning\",\n icon: <Image size={20} />,\n },\n {\n id: \"screenshots\",\n label: tr(\"devportal.checklistScreenshotsLabel\", \"Screenshots\"),\n description: tr(\n \"devportal.checklistScreenshotsDesc\",\n \"At least 3 screenshots are recommended\",\n ),\n status:\n screenshotCount >= 3\n ? \"passed\"\n : screenshotCount > 0\n ? \"warning\"\n : \"warning\",\n icon: <Image size={20} />,\n },\n {\n id: \"status\",\n label: tr(\"devportal.checklistStatusLabel\", \"App Status\"),\n description: tr(\n \"devportal.checklistStatusDesc\",\n \"App must be in DRAFT or REJECTED state to submit\",\n ),\n status: [\"DRAFT\", \"REJECTED\"].includes(app.status ?? \"\")\n ? \"passed\"\n : \"warning\",\n icon: <CheckCircle size={20} />,\n },\n ];\n }, [app]);\n\n const passedCount = checklist.filter((i) => i.status === \"passed\").length;\n const failedCount = checklist.filter((i) => i.status === \"failed\").length;\n const warningCount = checklist.filter((i) => i.status === \"warning\").length;\n const isSubmittableStatus = [\"DRAFT\", \"REJECTED\"].includes(app?.status ?? \"\");\n const canSubmit =\n !loading &&\n !queryError &&\n failedCount === 0 &&\n !!app &&\n !isAlreadySubmitted &&\n isSubmittableStatus;\n\n const getStatusIcon = (status: ChecklistItem[\"status\"]) => {\n switch (status) {\n case \"passed\":\n return <CheckCircle size={20} className=\"text-status-success-text\" />;\n case \"failed\":\n return <XCircle size={20} className=\"text-status-error-text\" />;\n case \"warning\":\n return <AlertTriangle size={20} className=\"text-status-warning-text\" />;\n default:\n return (\n <div className=\"h-5 w-5 rounded-full border-2 border-border-default\" />\n );\n }\n };\n\n const getStatusBg = (status: ChecklistItem[\"status\"]) => {\n switch (status) {\n case \"passed\":\n return \"bg-status-success-bg-subtle border-border-subtle\";\n case \"failed\":\n return \"bg-status-error-bg-subtle border-border-subtle\";\n case \"warning\":\n return \"bg-status-warning-bg-subtle border-border-subtle\";\n default:\n return \"bg-bg-canvas border-border-subtle\";\n }\n };\n\n const handleSubmit = async () => {\n if (!appId) return;\n setSubmitting(true);\n setSubmitError(null);\n try {\n const result = await submitApplication({\n variables: { id: appId, notes: notes.trim() || undefined },\n });\n if (result.error) {\n throw result.error;\n }\n navigate?.(`${basePath}/apps/${appId}`);\n } catch (err) {\n setSubmitError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.submitFailedDefault\", \"Failed to submit for review\"),\n );\n setSubmitting(false);\n }\n };\n\n if (loading) {\n return (\n <PageLayout\n title={tr(\"devportal.publishToStoreTitle\", \"Publish to Store\")}\n description={tr(\n \"devportal.loadingApplicationDetails\",\n \"Loading application details...\",\n )}\n backLink={`/apps/${appId}`}\n backLabel={tr(\"devportal.backToApplication\", \"Back to Application\")}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"animate-spin h-8 w-8 text-muted-foreground\" />\n </div>\n </PageLayout>\n );\n }\n\n if (queryError || !app) {\n return (\n <PageLayout\n title={tr(\"devportal.publishToStoreTitle\", \"Publish to Store\")}\n description={tr(\n \"devportal.couldNotLoadApplication\",\n \"Could not load application\",\n )}\n backLink={`/apps/${appId}`}\n backLabel={tr(\"devportal.backToApplication\", \"Back to Application\")}\n >\n <Alert\n variant=\"error\"\n title={tr(\n \"devportal.failedToLoadApplication\",\n \"Failed to load application\",\n )}\n >\n {queryError?.message ??\n tr(\"devportal.applicationNotFound\", \"Application not found\")}\n </Alert>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.APP_SUBMIT}>\n <PageLayout\n title={tr(\"devportal.publishToStoreTitle\", \"Publish to Store\")}\n description={`${tr(\"devportal.submitAppForReview\", \"Submit\")} \"${app.name}\" ${tr(\"devportal.forReviewAndPublication\", \"for review and publication\")}`}\n backLink={`/apps/${appId}`}\n backLabel={tr(\"devportal.backToApplication\", \"Back to Application\")}\n actions={\n <button\n onClick={() => navigate?.(`${basePath}/apps/${appId}/listing`)}\n className=\"inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium hover:bg-muted\"\n >\n <Eye size={16} />\n {tr(\"devportal.previewListing\", \"Preview Listing\")}\n </button>\n }\n >\n {isAlreadySubmitted && (\n <Alert\n variant=\"warning\"\n title={tr(\"devportal.alreadySubmittedTitle\", \"Already Submitted\")}\n >\n {tr(\"devportal.alreadySubmittedMsg1\", \"This app is currently in\")}{\" \"}\n <strong>{app.status}</strong>{\" \"}\n {tr(\n \"devportal.alreadySubmittedMsg2\",\n \"state and cannot be re-submitted until the review process is complete or the app is rejected.\",\n )}\n </Alert>\n )}\n\n {/* Progress Summary */}\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-lg font-semibold\">\n {tr(\"devportal.preSubmissionChecklist\", \"Pre-submission Checklist\")}\n </h2>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {tr(\n \"devportal.completeAllRequiredItems\",\n \"Complete all required items before submitting for review\",\n )}\n </p>\n <div className=\"mt-4 flex gap-6\">\n <div className=\"flex items-center gap-2\">\n <CheckCircle size={20} className=\"text-status-success-text\" />\n <span>\n {passedCount} {tr(\"devportal.passed\", \"Passed\")}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <XCircle size={20} className=\"text-status-error-text\" />\n <span>\n {failedCount} {tr(\"devportal.failed\", \"Failed\")}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <AlertTriangle size={20} className=\"text-status-warning-text\" />\n <span>\n {warningCount} {tr(\"devportal.warnings\", \"Warnings\")}\n </span>\n </div>\n </div>\n </div>\n\n {/* Checklist Items */}\n <PageSection>\n <div className=\"space-y-3\">\n {checklist.map((item) => (\n <div\n key={item.id}\n className={`flex items-center gap-4 rounded-lg border p-4 ${getStatusBg(item.status)}`}\n >\n <div className=\"rounded-lg bg-background p-2\">{item.icon}</div>\n <div className=\"flex-1\">\n <p className=\"font-medium\">{item.label}</p>\n <p className=\"text-sm text-muted-foreground\">\n {item.description}\n </p>\n </div>\n {getStatusIcon(item.status)}\n </div>\n ))}\n </div>\n </PageSection>\n\n {/* Submission Notes */}\n {!isAlreadySubmitted && (\n <PageSection\n title={tr(\"devportal.notesForReviewerTitle\", \"Notes for Reviewer\")}\n description={tr(\n \"devportal.notesForReviewerDesc\",\n \"Optional message to the review team\",\n )}\n >\n <textarea\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n placeholder={tr(\n \"devportal.notesForReviewerPlaceholder\",\n \"Describe what your app does, any special review considerations, or testing instructions...\",\n )}\n rows={4}\n maxLength={1000}\n className=\"w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring resize-none\"\n />\n <p className=\"mt-1 text-xs text-muted-foreground text-right\">\n {notes.length}/1000\n </p>\n </PageSection>\n )}\n\n {/* Alerts */}\n {submitError && (\n <Alert\n variant=\"error\"\n title={tr(\"devportal.submissionFailedTitle\", \"Submission Failed\")}\n >\n {submitError}\n </Alert>\n )}\n\n {failedCount > 0 && !isAlreadySubmitted && (\n <Alert\n variant=\"error\"\n title={tr(\"devportal.cannotSubmitTitle\", \"Cannot Submit\")}\n >\n {tr(\"devportal.pleaseFixItems1\", \"Please fix\")} {failedCount}{\" \"}\n {tr(\n \"devportal.pleaseFixItems2\",\n \"failed item(s) before submitting for review.\",\n )}\n <button\n onClick={() => navigate?.(`${basePath}/apps/${appId}/edit`)}\n className=\"mt-2 block text-sm underline hover:no-underline\"\n >\n {tr(\n \"devportal.editApplicationToFix\",\n \"Edit application to fix issues →\",\n )}\n </button>\n </Alert>\n )}\n\n {warningCount > 0 && failedCount === 0 && !isAlreadySubmitted && (\n <Alert\n variant=\"warning\"\n title={tr(\"devportal.warningsTitle\", \"Warnings\")}\n >\n {tr(\"devportal.warningsMsg1\", \"You have\")} {warningCount}{\" \"}\n {tr(\n \"devportal.warningsMsg2\",\n \"warning(s). While you can submit, addressing these may improve your app's chances of approval.\",\n )}\n </Alert>\n )}\n\n {/* Review Process Info */}\n <PageSection\n title={tr(\"devportal.reviewProcessTitle\", \"Review Process\")}\n >\n <div className=\"rounded-lg border bg-muted/50 p-4\">\n <ul className=\"space-y-2 text-sm\">\n <li className=\"flex items-start gap-2\">\n <CheckCircle size={16} className=\"mt-0.5 text-primary\" />\n <span>\n {tr(\n \"devportal.reviewProcessInfo1\",\n \"Review typically takes 3-5 business days\",\n )}\n </span>\n </li>\n <li className=\"flex items-start gap-2\">\n <CheckCircle size={16} className=\"mt-0.5 text-primary\" />\n <span>\n {tr(\n \"devportal.reviewProcessInfo2\",\n \"You'll receive notifications about review status changes\",\n )}\n </span>\n </li>\n <li className=\"flex items-start gap-2\">\n <CheckCircle size={16} className=\"mt-0.5 text-primary\" />\n <span>\n {tr(\n \"devportal.reviewProcessInfo3\",\n \"If changes are requested, you can resubmit without losing your place in the queue\",\n )}\n </span>\n </li>\n <li className=\"flex items-start gap-2\">\n <CheckCircle size={16} className=\"mt-0.5 text-primary\" />\n <span>\n {tr(\n \"devportal.reviewProcessInfo4\",\n \"Once approved and published, your app will be visible in the marketplace\",\n )}\n </span>\n </li>\n </ul>\n </div>\n </PageSection>\n\n {/* Actions */}\n <div className=\"flex gap-3\">\n <button\n onClick={() => navigate?.(`${basePath}/apps/${appId}`)}\n className=\"rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted\"\n >\n {tr(\"devportal.cancelButton\", \"Cancel\")}\n </button>\n <button\n onClick={handleSubmit}\n disabled={!canSubmit || submitting || !submitPerm.allowed}\n aria-disabled={!canSubmit || submitting || !submitPerm.allowed}\n title={\n !submitPerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n {submitting ? (\n <>\n <Loader2 size={16} className=\"animate-spin\" />\n {tr(\"devportal.submittingButton\", \"Submitting...\")}\n </>\n ) : (\n <>\n <Send size={16} />\n {tr(\"devportal.submitForReviewButton\", \"Submit for Review\")}\n </>\n )}\n </button>\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"PublishPage.js","names":[],"sources":["../../../src/devportal/pages/PublishPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useEffect, useState, useMemo } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n CheckCircle,\n XCircle,\n AlertTriangle,\n Send,\n FileText,\n Shield,\n Image,\n Globe,\n Loader2,\n Eye,\n} from \"lucide-react\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { Alert } from \"../components/ConfirmDialog\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PermissionGuard } from \"../components\";\nimport { DEVPORTAL_PERMISSIONS } from \"../constants/permissions\";\nimport {\n useGetApplicationQuery,\n useSubmitApplicationMutation,\n} from \"../../generated/global-operations\";\nimport { useDevportalPermission } from \"../hooks\";\n\ninterface ChecklistItem {\n id: string;\n label: string;\n description: string;\n status: \"passed\" | \"failed\" | \"warning\" | \"pending\";\n icon: React.ReactNode;\n}\n\nconst ALREADY_SUBMITTED_STATUSES = [\n \"SUBMITTED\",\n \"IN_REVIEW\",\n \"APPROVED\",\n \"PUBLISHED\",\n];\n\nexport const PublishPage: FC = () => {\n const { appId } = useParams<{ appId: string }>();\n const { navigate, basePath } = useDevportal();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const [submitting, setSubmitting] = useState(false);\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [notes, setNotes] = useState(\"\");\n const submitPerm = useDevportalPermission(DEVPORTAL_PERMISSIONS.APP_SUBMIT);\n\n const {\n data,\n loading,\n error: queryError,\n } = useGetApplicationQuery({\n variables: { id: appId! },\n skip: !appId,\n fetchPolicy: \"network-only\",\n });\n\n const [submitApplication] = useSubmitApplicationMutation();\n\n const app = data?.application;\n\n useEffect(() => {\n const name = app?.name;\n if (!appId || !name) return;\n const reg = (\n window as unknown as {\n __breadcrumbRegistry?: {\n register: (id: string, name: string) => void;\n unregister: (id: string) => void;\n };\n }\n ).__breadcrumbRegistry;\n reg?.register(appId, name);\n return () => reg?.unregister(appId);\n }, [appId, app?.name]);\n\n const isAlreadySubmitted = ALREADY_SUBMITTED_STATUSES.includes(\n app?.status ?? \"\",\n );\n\n const checklist = useMemo((): ChecklistItem[] => {\n if (!app) return [];\n\n const screenshotCount = app.screenshots?.length ?? 0;\n\n return [\n {\n id: \"name\",\n label: tr(\"devportal.checklistNameLabel\", \"App Name & Description\"),\n description: tr(\n \"devportal.checklistNameDesc\",\n \"Name and short description are required\",\n ),\n status: app.name && app.shortDescription ? \"passed\" : \"failed\",\n icon: <FileText size={20} />,\n },\n {\n id: \"category\",\n label: tr(\"devportal.checklistCategoryLabel\", \"Category\"),\n description: tr(\n \"devportal.checklistCategoryDesc\",\n \"A category must be selected\",\n ),\n status: app.category ? \"passed\" : \"failed\",\n icon: <Globe size={20} />,\n },\n {\n id: \"privacy\",\n label: tr(\"devportal.checklistPrivacyLabel\", \"Privacy Policy\"),\n description: tr(\n \"devportal.checklistPrivacyDesc\",\n \"Privacy policy URL is required\",\n ),\n status: app.privacyPolicyUrl ? \"passed\" : \"failed\",\n icon: <Shield size={20} />,\n },\n {\n id: \"terms\",\n label: tr(\"devportal.checklistTermsLabel\", \"Terms of Service\"),\n description: tr(\n \"devportal.checklistTermsDesc\",\n \"Terms of service URL is required\",\n ),\n status: app.termsOfServiceUrl ? \"passed\" : \"failed\",\n icon: <FileText size={20} />,\n },\n {\n id: \"icon\",\n label: tr(\"devportal.checklistIconLabel\", \"App Icon\"),\n description: tr(\n \"devportal.checklistIconDesc\",\n \"An icon URL is recommended\",\n ),\n status: app.iconUrl ? \"passed\" : \"warning\",\n icon: <Image size={20} />,\n },\n {\n id: \"screenshots\",\n label: tr(\"devportal.checklistScreenshotsLabel\", \"Screenshots\"),\n description: tr(\n \"devportal.checklistScreenshotsDesc\",\n \"At least 3 screenshots are recommended\",\n ),\n status:\n screenshotCount >= 3\n ? \"passed\"\n : screenshotCount > 0\n ? \"warning\"\n : \"warning\",\n icon: <Image size={20} />,\n },\n {\n id: \"status\",\n label: tr(\"devportal.checklistStatusLabel\", \"App Status\"),\n description: tr(\n \"devportal.checklistStatusDesc\",\n \"App must be in DRAFT or REJECTED state to submit\",\n ),\n status: [\"DRAFT\", \"REJECTED\"].includes(app.status ?? \"\")\n ? \"passed\"\n : \"warning\",\n icon: <CheckCircle size={20} />,\n },\n ];\n }, [app]);\n\n const passedCount = checklist.filter((i) => i.status === \"passed\").length;\n const failedCount = checklist.filter((i) => i.status === \"failed\").length;\n const warningCount = checklist.filter((i) => i.status === \"warning\").length;\n const isSubmittableStatus = [\"DRAFT\", \"REJECTED\"].includes(app?.status ?? \"\");\n const canSubmit =\n !loading &&\n !queryError &&\n failedCount === 0 &&\n !!app &&\n !isAlreadySubmitted &&\n isSubmittableStatus;\n\n const getStatusIcon = (status: ChecklistItem[\"status\"]) => {\n switch (status) {\n case \"passed\":\n return <CheckCircle size={20} className=\"text-status-success-text\" />;\n case \"failed\":\n return <XCircle size={20} className=\"text-status-error-text\" />;\n case \"warning\":\n return <AlertTriangle size={20} className=\"text-status-warning-text\" />;\n default:\n return (\n <div className=\"h-5 w-5 rounded-full border-2 border-border-default\" />\n );\n }\n };\n\n const getStatusBg = (status: ChecklistItem[\"status\"]) => {\n switch (status) {\n case \"passed\":\n return \"bg-status-success-bg-subtle border-border-subtle\";\n case \"failed\":\n return \"bg-status-error-bg-subtle border-border-subtle\";\n case \"warning\":\n return \"bg-status-warning-bg-subtle border-border-subtle\";\n default:\n return \"bg-bg-canvas border-border-subtle\";\n }\n };\n\n const handleSubmit = async () => {\n if (!appId) return;\n setSubmitting(true);\n setSubmitError(null);\n try {\n const result = await submitApplication({\n variables: { id: appId, notes: notes.trim() || undefined },\n });\n if (result.error) {\n throw result.error;\n }\n navigate?.(`${basePath}/apps/${appId}`);\n } catch (err) {\n setSubmitError(\n err instanceof Error\n ? err.message\n : tr(\"devportal.submitFailedDefault\", \"Failed to submit for review\"),\n );\n setSubmitting(false);\n }\n };\n\n if (loading) {\n return (\n <PageLayout\n title={tr(\"devportal.publishToStoreTitle\", \"Publish to Store\")}\n description={tr(\n \"devportal.loadingApplicationDetails\",\n \"Loading application details...\",\n )}\n backLink={`/apps/${appId}`}\n backLabel={tr(\"devportal.backToApplication\", \"Back to Application\")}\n >\n <div className=\"flex items-center justify-center py-12\">\n <Loader2 className=\"animate-spin h-8 w-8 text-muted-foreground\" />\n </div>\n </PageLayout>\n );\n }\n\n if (queryError || !app) {\n return (\n <PageLayout\n title={tr(\"devportal.publishToStoreTitle\", \"Publish to Store\")}\n description={tr(\n \"devportal.couldNotLoadApplication\",\n \"Could not load application\",\n )}\n backLink={`/apps/${appId}`}\n backLabel={tr(\"devportal.backToApplication\", \"Back to Application\")}\n >\n <Alert\n variant=\"error\"\n title={tr(\n \"devportal.failedToLoadApplication\",\n \"Failed to load application\",\n )}\n >\n {queryError?.message ??\n tr(\"devportal.applicationNotFound\", \"Application not found\")}\n </Alert>\n </PageLayout>\n );\n }\n\n return (\n <PermissionGuard permission={DEVPORTAL_PERMISSIONS.APP_SUBMIT}>\n <PageLayout\n title={tr(\"devportal.publishToStoreTitle\", \"Publish to Store\")}\n description={`${tr(\"devportal.submitAppForReview\", \"Submit\")} \"${app.name}\" ${tr(\"devportal.forReviewAndPublication\", \"for review and publication\")}`}\n backLink={`/apps/${appId}`}\n backLabel={tr(\"devportal.backToApplication\", \"Back to Application\")}\n actions={\n <button\n onClick={() => navigate?.(`${basePath}/apps/${appId}/listing`)}\n className=\"inline-flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium hover:bg-muted\"\n >\n <Eye size={16} />\n {tr(\"devportal.previewListing\", \"Preview Listing\")}\n </button>\n }\n >\n {isAlreadySubmitted && (\n <Alert\n variant=\"warning\"\n title={tr(\"devportal.alreadySubmittedTitle\", \"Already Submitted\")}\n >\n {tr(\"devportal.alreadySubmittedMsg1\", \"This app is currently in\")}{\" \"}\n <strong>{app.status}</strong>{\" \"}\n {tr(\n \"devportal.alreadySubmittedMsg2\",\n \"state and cannot be re-submitted until the review process is complete or the app is rejected.\",\n )}\n </Alert>\n )}\n\n {/* Progress Summary */}\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-lg font-semibold\">\n {tr(\"devportal.preSubmissionChecklist\", \"Pre-submission Checklist\")}\n </h2>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {tr(\n \"devportal.completeAllRequiredItems\",\n \"Complete all required items before submitting for review\",\n )}\n </p>\n <div className=\"mt-4 flex gap-6\">\n <div className=\"flex items-center gap-2\">\n <CheckCircle size={20} className=\"text-status-success-text\" />\n <span>\n {passedCount} {tr(\"devportal.passed\", \"Passed\")}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <XCircle size={20} className=\"text-status-error-text\" />\n <span>\n {failedCount} {tr(\"devportal.failed\", \"Failed\")}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <AlertTriangle size={20} className=\"text-status-warning-text\" />\n <span>\n {warningCount} {tr(\"devportal.warnings\", \"Warnings\")}\n </span>\n </div>\n </div>\n </div>\n\n {/* Checklist Items */}\n <PageSection>\n <div className=\"space-y-3\">\n {checklist.map((item) => (\n <div\n key={item.id}\n className={`flex items-center gap-4 rounded-lg border p-4 ${getStatusBg(item.status)}`}\n >\n <div className=\"rounded-lg bg-background p-2\">{item.icon}</div>\n <div className=\"flex-1\">\n <p className=\"font-medium\">{item.label}</p>\n <p className=\"text-sm text-muted-foreground\">\n {item.description}\n </p>\n </div>\n {getStatusIcon(item.status)}\n </div>\n ))}\n </div>\n </PageSection>\n\n {/* Submission Notes */}\n {!isAlreadySubmitted && (\n <PageSection\n title={tr(\"devportal.notesForReviewerTitle\", \"Notes for Reviewer\")}\n description={tr(\n \"devportal.notesForReviewerDesc\",\n \"Optional message to the review team\",\n )}\n >\n <textarea\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n placeholder={tr(\n \"devportal.notesForReviewerPlaceholder\",\n \"Describe what your app does, any special review considerations, or testing instructions...\",\n )}\n rows={4}\n maxLength={1000}\n className=\"w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring resize-none\"\n />\n <p className=\"mt-1 text-xs text-muted-foreground text-right\">\n {notes.length}/1000\n </p>\n </PageSection>\n )}\n\n {/* Alerts */}\n {submitError && (\n <Alert\n variant=\"error\"\n title={tr(\"devportal.submissionFailedTitle\", \"Submission Failed\")}\n >\n {submitError}\n </Alert>\n )}\n\n {failedCount > 0 && !isAlreadySubmitted && (\n <Alert\n variant=\"error\"\n title={tr(\"devportal.cannotSubmitTitle\", \"Cannot Submit\")}\n >\n {tr(\"devportal.pleaseFixItems1\", \"Please fix\")} {failedCount}{\" \"}\n {tr(\n \"devportal.pleaseFixItems2\",\n \"failed item(s) before submitting for review.\",\n )}\n <button\n onClick={() => navigate?.(`${basePath}/apps/${appId}/edit`)}\n className=\"mt-2 block text-sm underline hover:no-underline\"\n >\n {tr(\n \"devportal.editApplicationToFix\",\n \"Edit application to fix issues →\",\n )}\n </button>\n </Alert>\n )}\n\n {warningCount > 0 && failedCount === 0 && !isAlreadySubmitted && (\n <Alert\n variant=\"warning\"\n title={tr(\"devportal.warningsTitle\", \"Warnings\")}\n >\n {tr(\"devportal.warningsMsg1\", \"You have\")} {warningCount}{\" \"}\n {tr(\n \"devportal.warningsMsg2\",\n \"warning(s). While you can submit, addressing these may improve your app's chances of approval.\",\n )}\n </Alert>\n )}\n\n {/* Review Process Info */}\n <PageSection\n title={tr(\"devportal.reviewProcessTitle\", \"Review Process\")}\n >\n <div className=\"rounded-lg border bg-muted/50 p-4\">\n <ul className=\"space-y-2 text-sm\">\n <li className=\"flex items-start gap-2\">\n <CheckCircle size={16} className=\"mt-0.5 text-primary\" />\n <span>\n {tr(\n \"devportal.reviewProcessInfo1\",\n \"Review typically takes 3-5 business days\",\n )}\n </span>\n </li>\n <li className=\"flex items-start gap-2\">\n <CheckCircle size={16} className=\"mt-0.5 text-primary\" />\n <span>\n {tr(\n \"devportal.reviewProcessInfo2\",\n \"You'll receive notifications about review status changes\",\n )}\n </span>\n </li>\n <li className=\"flex items-start gap-2\">\n <CheckCircle size={16} className=\"mt-0.5 text-primary\" />\n <span>\n {tr(\n \"devportal.reviewProcessInfo3\",\n \"If changes are requested, you can resubmit without losing your place in the queue\",\n )}\n </span>\n </li>\n <li className=\"flex items-start gap-2\">\n <CheckCircle size={16} className=\"mt-0.5 text-primary\" />\n <span>\n {tr(\n \"devportal.reviewProcessInfo4\",\n \"Once approved and published, your app will be visible in the marketplace\",\n )}\n </span>\n </li>\n </ul>\n </div>\n </PageSection>\n\n {/* Actions */}\n <div className=\"flex gap-3\">\n <button\n onClick={() => navigate?.(`${basePath}/apps/${appId}`)}\n className=\"rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted\"\n >\n {tr(\"devportal.cancelButton\", \"Cancel\")}\n </button>\n <button\n onClick={handleSubmit}\n disabled={!canSubmit || submitting || !submitPerm.allowed}\n aria-disabled={!canSubmit || submitting || !submitPerm.allowed}\n title={\n !submitPerm.allowed\n ? tr(\n \"devportal.common.noPermission\",\n \"You do not have permission to perform this action\",\n )\n : undefined\n }\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n {submitting ? (\n <>\n <Loader2 size={16} className=\"animate-spin\" />\n {tr(\"devportal.submittingButton\", \"Submitting...\")}\n </>\n ) : (\n <>\n <Send size={16} />\n {tr(\"devportal.submitForReviewButton\", \"Submit for Review\")}\n </>\n )}\n </button>\n </div>\n </PageLayout>\n </PermissionGuard>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ResourcesPage.js","names":[],"sources":["../../../src/devportal/pages/ResourcesPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState } from \"react\";\nimport {\n Package,\n Terminal,\n FileCode,\n Download,\n ExternalLink,\n Github,\n Code2,\n BookOpen,\n Wrench,\n Cpu,\n Boxes,\n Globe,\n Smartphone,\n Monitor,\n Layers,\n Palette,\n Search,\n Star,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { cn } from \"../utils/cn\";\nimport {\n nativeCopyText,\n nativeImpact,\n nativeNotify,\n} from \"../../utils/nativeBridge\";\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\ninterface SDK {\n id: string;\n name: string;\n language: string;\n description: string;\n version: string;\n downloads: string;\n icon: React.ReactNode;\n packageManager: string;\n installCommand: string;\n docsUrl: string;\n githubUrl: string;\n isOfficial: boolean;\n}\n\ninterface Tool {\n id: string;\n name: string;\n description: string;\n icon: React.ReactNode;\n type: \"cli\" | \"extension\" | \"library\" | \"utility\";\n url: string;\n isNew?: boolean;\n}\n\ninterface Starter {\n id: string;\n name: string;\n description: string;\n framework: string;\n icon: React.ReactNode;\n githubUrl: string;\n demoUrl?: string;\n stars: number;\n}\n\ninterface Guide {\n id: string;\n title: string;\n description: string;\n difficulty: \"beginner\" | \"intermediate\" | \"advanced\";\n duration: string;\n url: string;\n}\n\ntype ResourceCategory = \"all\" | \"sdks\" | \"tools\" | \"starters\" | \"guides\";\n\n// =============================================================================\n// DATA\n// =============================================================================\n\nconst sdks: SDK[] = [\n {\n id: \"sdk-node\",\n name: \"Node.js SDK\",\n language: \"TypeScript/JavaScript\",\n description:\n \"Official SDK for Node.js applications with TypeScript support\",\n version: \"2.4.1\",\n downloads: \"125k\",\n icon: <Code2 size={24} />,\n packageManager: \"npm\",\n installCommand: \"npm install @burdenoff/sdk-node\",\n docsUrl: \"https://docs.burdenoff.com/sdks/node\",\n githubUrl: \"https://github.com/burdenoff/sdk-node\",\n isOfficial: true,\n },\n {\n id: \"sdk-python\",\n name: \"Python SDK\",\n language: \"Python\",\n description: \"Official SDK for Python applications with async support\",\n version: \"1.8.0\",\n downloads: \"89k\",\n icon: <FileCode size={24} />,\n packageManager: \"pip\",\n installCommand: \"pip install burdenoff-sdk\",\n docsUrl: \"https://docs.burdenoff.com/sdks/python\",\n githubUrl: \"https://github.com/burdenoff/sdk-python\",\n isOfficial: true,\n },\n {\n id: \"sdk-go\",\n name: \"Go SDK\",\n language: \"Go\",\n description: \"Official SDK for Go applications\",\n version: \"1.5.2\",\n downloads: \"45k\",\n icon: <Cpu size={24} />,\n packageManager: \"go\",\n installCommand: \"go get github.com/burdenoff/sdk-go\",\n docsUrl: \"https://docs.burdenoff.com/sdks/go\",\n githubUrl: \"https://github.com/burdenoff/sdk-go\",\n isOfficial: true,\n },\n {\n id: \"sdk-react\",\n name: \"React SDK\",\n language: \"TypeScript/React\",\n description: \"Hooks and components for React applications\",\n version: \"3.1.0\",\n downloads: \"78k\",\n icon: <Boxes size={24} />,\n packageManager: \"npm\",\n installCommand: \"npm install @burdenoff/react\",\n docsUrl: \"https://docs.burdenoff.com/sdks/react\",\n githubUrl: \"https://github.com/burdenoff/sdk-react\",\n isOfficial: true,\n },\n {\n id: \"sdk-ruby\",\n name: \"Ruby SDK\",\n language: \"Ruby\",\n description: \"Community SDK for Ruby on Rails applications\",\n version: \"1.2.0\",\n downloads: \"12k\",\n icon: <FileCode size={24} />,\n packageManager: \"gem\",\n installCommand: \"gem install burdenoff\",\n docsUrl: \"https://docs.burdenoff.com/sdks/ruby\",\n githubUrl: \"https://github.com/burdenoff/sdk-ruby\",\n isOfficial: false,\n },\n];\n\nconst tools: Tool[] = [\n {\n id: \"cli\",\n name: \"Burdenoff CLI\",\n description:\n \"Command-line tool for managing apps, deployments, and testing\",\n icon: <Terminal size={24} />,\n type: \"cli\",\n url: \"https://docs.burdenoff.com/cli\",\n },\n {\n id: \"vscode\",\n name: \"VS Code Extension\",\n description:\n \"IntelliSense, snippets, and debugging for Burdenoff development\",\n icon: <Monitor size={24} />,\n type: \"extension\",\n url: \"https://marketplace.visualstudio.com/items?itemName=burdenoff.burdenoff-vscode\",\n isNew: true,\n },\n {\n id: \"graphql-playground\",\n name: \"GraphQL Playground\",\n description: \"Interactive GraphQL IDE for exploring and testing the API\",\n icon: <Globe size={24} />,\n type: \"utility\",\n url: \"https://api.burdenoff.com/graphql\",\n },\n {\n id: \"postman\",\n name: \"Postman Collection\",\n description: \"Pre-built Postman collection for REST API testing\",\n icon: <Layers size={24} />,\n type: \"utility\",\n url: \"https://www.postman.com/burdenoff/workspace/burdenoff-api\",\n },\n {\n id: \"webhook-tester\",\n name: \"Webhook Tester\",\n description: \"Tool for testing and debugging webhook integrations\",\n icon: <Wrench size={24} />,\n type: \"utility\",\n url: \"https://developers.burdenoff.com/tools/webhook-tester\",\n },\n {\n id: \"oauth-debugger\",\n name: \"OAuth Debugger\",\n description: \"Debug OAuth flows and inspect tokens\",\n icon: <Wrench size={24} />,\n type: \"utility\",\n url: \"https://developers.burdenoff.com/tools/oauth-debugger\",\n isNew: true,\n },\n {\n id: \"ui-kit\",\n name: \"UI Component Kit\",\n description: \"Figma design kit matching Burdenoff platform UI\",\n icon: <Palette size={24} />,\n type: \"library\",\n url: \"https://www.figma.com/community/file/burdenoff-ui-kit\",\n },\n];\n\nconst starters: Starter[] = [\n {\n id: \"nextjs-starter\",\n name: \"Next.js Starter\",\n description:\n \"Full-featured Next.js app with OAuth, webhooks, and API integration\",\n framework: \"Next.js 14\",\n icon: <Boxes size={24} />,\n githubUrl: \"https://github.com/burdenoff/starter-nextjs\",\n demoUrl: \"https://starter-nextjs.burdenoff.dev\",\n stars: 1240,\n },\n {\n id: \"express-starter\",\n name: \"Express.js Starter\",\n description:\n \"Backend starter with Express, TypeScript, and webhook handling\",\n framework: \"Express.js\",\n icon: <Code2 size={24} />,\n githubUrl: \"https://github.com/burdenoff/starter-express\",\n stars: 890,\n },\n {\n id: \"react-starter\",\n name: \"React Dashboard\",\n description: \"React dashboard template with Burdenoff SDK integration\",\n framework: \"React + Vite\",\n icon: <Monitor size={24} />,\n githubUrl: \"https://github.com/burdenoff/starter-react\",\n demoUrl: \"https://starter-react.burdenoff.dev\",\n stars: 756,\n },\n {\n id: \"python-starter\",\n name: \"FastAPI Starter\",\n description: \"Python FastAPI backend with async Burdenoff SDK\",\n framework: \"FastAPI\",\n icon: <FileCode size={24} />,\n githubUrl: \"https://github.com/burdenoff/starter-fastapi\",\n stars: 534,\n },\n {\n id: \"mobile-starter\",\n name: \"React Native Starter\",\n description: \"Mobile app template with Burdenoff authentication\",\n framework: \"React Native\",\n icon: <Smartphone size={24} />,\n githubUrl: \"https://github.com/burdenoff/starter-react-native\",\n stars: 423,\n },\n];\n\nconst guides: Guide[] = [\n {\n id: \"first-app\",\n title: \"Build Your First App\",\n description:\n \"Step-by-step guide to creating and publishing your first application\",\n difficulty: \"beginner\",\n duration: \"30 min\",\n url: \"https://docs.burdenoff.com/guides/first-app\",\n },\n {\n id: \"oauth-setup\",\n title: \"Setting Up OAuth 2.0\",\n description: \"Complete guide to implementing OAuth authentication\",\n difficulty: \"intermediate\",\n duration: \"45 min\",\n url: \"https://docs.burdenoff.com/guides/oauth-setup\",\n },\n {\n id: \"webhooks-guide\",\n title: \"Webhook Integration Guide\",\n description: \"Handle real-time events with webhooks\",\n difficulty: \"intermediate\",\n duration: \"40 min\",\n url: \"https://docs.burdenoff.com/guides/webhooks\",\n },\n {\n id: \"multi-tenant\",\n title: \"Building Multi-Tenant Apps\",\n description: \"Architecture patterns for multi-tenant applications\",\n difficulty: \"advanced\",\n duration: \"60 min\",\n url: \"https://docs.burdenoff.com/guides/multi-tenant\",\n },\n {\n id: \"graphql-subscriptions\",\n title: \"Real-time with GraphQL Subscriptions\",\n description: \"Implement real-time features using GraphQL subscriptions\",\n difficulty: \"advanced\",\n duration: \"50 min\",\n url: \"https://docs.burdenoff.com/guides/subscriptions\",\n },\n {\n id: \"app-security\",\n title: \"Security Best Practices\",\n description: \"Secure your application with industry best practices\",\n difficulty: \"intermediate\",\n duration: \"35 min\",\n url: \"https://docs.burdenoff.com/guides/security\",\n },\n];\n\n// =============================================================================\n// COMPONENTS\n// =============================================================================\n\nconst SDKCard: FC<{ sdk: SDK }> = ({ sdk }) => {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = async () => {\n void nativeImpact(\"light\");\n const ok = await nativeCopyText(sdk.installCommand);\n if (ok) {\n setCopied(true);\n void nativeNotify(\"success\");\n setTimeout(() => setCopied(false), 2000);\n } else {\n void nativeNotify(\"error\");\n }\n };\n\n return (\n <div className=\"flex flex-col rounded-lg border bg-card p-5\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-primary/10 p-2.5 text-primary\">\n {sdk.icon}\n </div>\n <div>\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-semibold\">{sdk.name}</h3>\n {sdk.isOfficial && (\n <span className=\"rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs font-medium text-status-info-text\">\n Official\n </span>\n )}\n </div>\n <p className=\"text-sm text-muted-foreground\">{sdk.language}</p>\n </div>\n </div>\n <span className=\"text-sm text-muted-foreground\">v{sdk.version}</span>\n </div>\n\n <p className=\"mt-3 text-sm text-muted-foreground\">{sdk.description}</p>\n\n <div className=\"mt-4 flex items-center gap-2 rounded-md bg-muted/50 p-2\">\n <code className=\"flex-1 text-xs\">{sdk.installCommand}</code>\n <button\n onClick={handleCopy}\n className=\"rounded px-2 py-1 text-xs hover:bg-muted transition-colors\"\n >\n {copied ? \"Copied!\" : \"Copy\"}\n </button>\n </div>\n\n <div className=\"mt-4 flex items-center justify-between text-sm\">\n <span className=\"flex items-center gap-1 text-muted-foreground\">\n <Download size={14} />\n {sdk.downloads} downloads\n </span>\n <div className=\"flex gap-2\">\n <a\n href={sdk.docsUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center gap-1 text-primary hover:underline\"\n >\n Docs <ExternalLink size={12} />\n </a>\n <a\n href={sdk.githubUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={`${sdk.name} on GitHub`}\n className=\"flex items-center gap-1 text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Github size={14} aria-hidden=\"true\" />\n </a>\n </div>\n </div>\n </div>\n );\n};\n\nconst ToolCard: FC<{ tool: Tool }> = ({ tool }) => (\n <a\n href={tool.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"group flex items-start gap-4 rounded-lg border bg-card p-4 transition-all hover:border-primary/50 hover:shadow-md\"\n >\n <div className=\"rounded-lg bg-primary/10 p-2.5 text-primary\">\n {tool.icon}\n </div>\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-semibold group-hover:text-primary\">{tool.name}</h3>\n {tool.isNew && (\n <span className=\"rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-xs font-medium text-status-success-text\">\n New\n </span>\n )}\n </div>\n <p className=\"mt-1 text-sm text-muted-foreground\">{tool.description}</p>\n </div>\n <ExternalLink\n size={16}\n className=\"text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100\"\n />\n </a>\n);\n\nconst StarterCard: FC<{ starter: Starter }> = ({ starter }) => (\n <div className=\"flex flex-col rounded-lg border bg-card p-5\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-primary/10 p-2.5 text-primary\">\n {starter.icon}\n </div>\n <div>\n <h3 className=\"font-semibold\">{starter.name}</h3>\n <p className=\"text-sm text-muted-foreground\">{starter.framework}</p>\n </div>\n </div>\n <span className=\"flex items-center gap-1 text-sm text-muted-foreground\">\n <Star size={14} className=\"text-status-warning-text\" />\n {starter.stars.toLocaleString()}\n </span>\n </div>\n\n <p className=\"mt-3 text-sm text-muted-foreground\">{starter.description}</p>\n\n <div className=\"mt-4 flex gap-2\">\n <a\n href={starter.githubUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex flex-1 items-center justify-center gap-2 rounded-md border bg-background px-3 py-2 text-sm font-medium hover:bg-accent transition-colors\"\n >\n <Github size={16} />\n View on GitHub\n </a>\n {starter.demoUrl && (\n <a\n href={starter.demoUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center justify-center gap-2 rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors\"\n >\n <Globe size={16} />\n Demo\n </a>\n )}\n </div>\n </div>\n);\n\nconst GuideCard: FC<{ guide: Guide }> = ({ guide }) => {\n const difficultyColors = {\n beginner: \"bg-status-success-bg-subtle text-status-success-text\",\n intermediate: \"bg-status-warning-bg-subtle text-status-warning-text\",\n advanced: \"bg-status-error-bg-subtle text-status-error-text\",\n };\n\n return (\n <a\n href={guide.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"group flex items-center gap-4 rounded-lg border bg-card p-4 transition-all hover:border-primary/50 hover:shadow-md\"\n >\n <div className=\"rounded-lg bg-primary/10 p-2.5 text-primary\">\n <BookOpen size={20} />\n </div>\n <div className=\"flex-1\">\n <h3 className=\"font-semibold group-hover:text-primary\">\n {guide.title}\n </h3>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {guide.description}\n </p>\n <div className=\"mt-2 flex items-center gap-3\">\n <span\n className={cn(\n \"rounded-full px-2 py-0.5 text-xs font-medium capitalize\",\n difficultyColors[guide.difficulty],\n )}\n >\n {guide.difficulty}\n </span>\n <span className=\"text-xs text-muted-foreground\">\n {guide.duration}\n </span>\n </div>\n </div>\n <ExternalLink\n size={16}\n className=\"text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100\"\n />\n </a>\n );\n};\n\n// =============================================================================\n// PAGE COMPONENT\n// =============================================================================\n\nexport const ResourcesPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [category, setCategory] = useState<ResourceCategory>(\"all\");\n\n return (\n <PageLayout\n title={tr(\"devportal.developerResources\", \"Developer Resources\")}\n description={tr(\n \"devportal.resourcesDescription\",\n \"SDKs, tools, starter templates, and guides to accelerate your development\",\n )}\n >\n {/* Coming-soon banner — Resources is a deferred surface (see\n devportal stability tracker). The cards below are curated external\n links until the in-product CMS lands. */}\n <div\n role=\"status\"\n className=\"mb-6 rounded-lg border border-status-warning-border bg-status-warning-bg p-4 text-sm text-status-warning-text\"\n >\n <strong className=\"font-semibold\">\n {tr(\"devportal.resources.comingSoon.title\", \"Coming soon\")}\n </strong>\n <span className=\"ml-2\">\n {tr(\n \"devportal.resources.comingSoon.description\",\n \"An in-product resources hub is on the way. For now we're surfacing the most useful external SDKs, tools, and templates here.\",\n )}\n </span>\n </div>\n\n {/* Search and Filter */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"relative flex-1 max-w-md\">\n <Search\n size={16}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground\"\n />\n <input\n type=\"text\"\n placeholder={tr(\"devportal.searchResources\", \"Search resources...\")}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full rounded-md border bg-background pl-9 pr-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n />\n </div>\n <div className=\"flex items-center gap-1 rounded-md border p-1\">\n {[\n { id: \"all\", label: tr(\"devportal.filterAll\", \"All\") },\n { id: \"sdks\", label: tr(\"devportal.filterSdks\", \"SDKs\") },\n { id: \"tools\", label: tr(\"devportal.filterTools\", \"Tools\") },\n {\n id: \"starters\",\n label: tr(\"devportal.filterStarters\", \"Starters\"),\n },\n { id: \"guides\", label: tr(\"devportal.filterGuides\", \"Guides\") },\n ].map((cat) => (\n <button\n key={cat.id}\n onClick={() => setCategory(cat.id as ResourceCategory)}\n className={cn(\n \"rounded px-3 py-1.5 text-sm font-medium transition-colors\",\n category === cat.id\n ? \"bg-primary text-primary-foreground\"\n : \"hover:bg-muted\",\n )}\n >\n {cat.label}\n </button>\n ))}\n </div>\n </div>\n\n {/* SDKs */}\n {(category === \"all\" || category === \"sdks\") && (\n <PageSection\n title={tr(\"devportal.officialSdks\", \"Official SDKs\")}\n description={tr(\n \"devportal.officialSdksDescription\",\n \"Client libraries for popular languages\",\n )}\n >\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {sdks.map((sdk) => (\n <SDKCard key={sdk.id} sdk={sdk} />\n ))}\n </div>\n </PageSection>\n )}\n\n {/* Developer Tools */}\n {(category === \"all\" || category === \"tools\") && (\n <PageSection\n title={tr(\"devportal.developerTools\", \"Developer Tools\")}\n description={tr(\n \"devportal.developerToolsDescription\",\n \"Tools to streamline your development workflow\",\n )}\n >\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {tools.map((tool) => (\n <ToolCard key={tool.id} tool={tool} />\n ))}\n </div>\n </PageSection>\n )}\n\n {/* Starter Templates */}\n {(category === \"all\" || category === \"starters\") && (\n <PageSection\n title={tr(\"devportal.starterTemplates\", \"Starter Templates\")}\n description={tr(\n \"devportal.starterTemplatesDescription\",\n \"Production-ready templates to kickstart your project\",\n )}\n >\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {starters.map((starter) => (\n <StarterCard key={starter.id} starter={starter} />\n ))}\n </div>\n </PageSection>\n )}\n\n {/* Guides */}\n {(category === \"all\" || category === \"guides\") && (\n <PageSection\n title={tr(\"devportal.stepByStepGuides\", \"Step-by-Step Guides\")}\n description={tr(\n \"devportal.stepByStepGuidesDescription\",\n \"Learn with hands-on tutorials\",\n )}\n >\n <div className=\"grid gap-4 lg:grid-cols-2\">\n {guides.map((guide) => (\n <GuideCard key={guide.id} guide={guide} />\n ))}\n </div>\n </PageSection>\n )}\n </PageLayout>\n );\n};\n"],"mappings":";;;;;;;;AAsFA,IAAM,IAAc;CAClB;EACE,IAAI;EACJ,MAAM;EACN,UAAU;EACV,aACE;EACF,SAAS;EACT,WAAW;EACX,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;EACzB,gBAAgB;EAChB,gBAAgB;EAChB,SAAS;EACT,WAAW;EACX,YAAY;EACb;CACD;EACE,IAAI;EACJ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,WAAW;EACX,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;EAC5B,gBAAgB;EAChB,gBAAgB;EAChB,SAAS;EACT,WAAW;EACX,YAAY;EACb;CACD;EACE,IAAI;EACJ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,WAAW;EACX,MAAM,kBAAC,GAAD,EAAK,MAAM,IAAM,CAAA;EACvB,gBAAgB;EAChB,gBAAgB;EAChB,SAAS;EACT,WAAW;EACX,YAAY;EACb;CACD;EACE,IAAI;EACJ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,WAAW;EACX,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;EACzB,gBAAgB;EAChB,gBAAgB;EAChB,SAAS;EACT,WAAW;EACX,YAAY;EACb;CACD;EACE,IAAI;EACJ,MAAM;EACN,UAAU;EACV,aAAa;EACb,SAAS;EACT,WAAW;EACX,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;EAC5B,gBAAgB;EAChB,gBAAgB;EAChB,SAAS;EACT,WAAW;EACX,YAAY;EACb;CACF,EAEK,IAAgB;CACpB;EACE,IAAI;EACJ,MAAM;EACN,aACE;EACF,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;EAC5B,MAAM;EACN,KAAK;EACN;CACD;EACE,IAAI;EACJ,MAAM;EACN,aACE;EACF,MAAM,kBAAC,GAAD,EAAS,MAAM,IAAM,CAAA;EAC3B,MAAM;EACN,KAAK;EACL,OAAO;EACR;CACD;EACE,IAAI;EACJ,MAAM;EACN,aAAa;EACb,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;EACzB,MAAM;EACN,KAAK;EACN;CACD;EACE,IAAI;EACJ,MAAM;EACN,aAAa;EACb,MAAM,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;EAC1B,MAAM;EACN,KAAK;EACN;CACD;EACE,IAAI;EACJ,MAAM;EACN,aAAa;EACb,MAAM,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;EAC1B,MAAM;EACN,KAAK;EACN;CACD;EACE,IAAI;EACJ,MAAM;EACN,aAAa;EACb,MAAM,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;EAC1B,MAAM;EACN,KAAK;EACL,OAAO;EACR;CACD;EACE,IAAI;EACJ,MAAM;EACN,aAAa;EACb,MAAM,kBAAC,GAAD,EAAS,MAAM,IAAM,CAAA;EAC3B,MAAM;EACN,KAAK;EACN;CACF,EAEK,IAAsB;CAC1B;EACE,IAAI;EACJ,MAAM;EACN,aACE;EACF,WAAW;EACX,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;EACzB,WAAW;EACX,SAAS;EACT,OAAO;EACR;CACD;EACE,IAAI;EACJ,MAAM;EACN,aACE;EACF,WAAW;EACX,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;EACzB,WAAW;EACX,OAAO;EACR;CACD;EACE,IAAI;EACJ,MAAM;EACN,aAAa;EACb,WAAW;EACX,MAAM,kBAAC,GAAD,EAAS,MAAM,IAAM,CAAA;EAC3B,WAAW;EACX,SAAS;EACT,OAAO;EACR;CACD;EACE,IAAI;EACJ,MAAM;EACN,aAAa;EACb,WAAW;EACX,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;EAC5B,WAAW;EACX,OAAO;EACR;CACD;EACE,IAAI;EACJ,MAAM;EACN,aAAa;EACb,WAAW;EACX,MAAM,kBAAC,GAAD,EAAY,MAAM,IAAM,CAAA;EAC9B,WAAW;EACX,OAAO;EACR;CACF,EAEK,IAAkB;CACtB;EACE,IAAI;EACJ,OAAO;EACP,aACE;EACF,YAAY;EACZ,UAAU;EACV,KAAK;EACN;CACD;EACE,IAAI;EACJ,OAAO;EACP,aAAa;EACb,YAAY;EACZ,UAAU;EACV,KAAK;EACN;CACD;EACE,IAAI;EACJ,OAAO;EACP,aAAa;EACb,YAAY;EACZ,UAAU;EACV,KAAK;EACN;CACD;EACE,IAAI;EACJ,OAAO;EACP,aAAa;EACb,YAAY;EACZ,UAAU;EACV,KAAK;EACN;CACD;EACE,IAAI;EACJ,OAAO;EACP,aAAa;EACb,YAAY;EACZ,UAAU;EACV,KAAK;EACN;CACD;EACE,IAAI;EACJ,OAAO;EACP,aAAa;EACb,YAAY;EACZ,UAAU;EACV,KAAK;EACN;CACF,EAMK,KAA6B,EAAE,aAAU;CAC7C,IAAM,CAAC,GAAQ,KAAa,EAAS,GAAM;AAc3C,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAI;MACD,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBAAiB,EAAI;OAAU,CAAA,EAC5C,EAAI,cACH,kBAAC,QAAD;OAAM,WAAU;iBAA8F;OAEvG,CAAA,CAEL;SACN,kBAAC,KAAD;MAAG,WAAU;gBAAiC,EAAI;MAAa,CAAA,CAC3D,EAAA,CAAA,CACF;QACN,kBAAC,QAAD;KAAM,WAAU;eAAhB,CAAgD,KAAE,EAAI,QAAe;OACjE;;GAEN,kBAAC,KAAD;IAAG,WAAU;cAAsC,EAAI;IAAgB,CAAA;GAEvE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,QAAD;KAAM,WAAU;eAAkB,EAAI;KAAsB,CAAA,EAC5D,kBAAC,UAAD;KACE,SAvCW,YAAY;AAG7B,MAFK,EAAa,QAAQ,EACf,MAAM,EAAe,EAAI,eAAe,IAEjD,EAAU,GAAK,EACV,EAAa,UAAU,EAC5B,iBAAiB,EAAU,GAAM,EAAE,IAAK,IAEnC,EAAa,QAAQ;;KAgCtB,WAAU;eAET,IAAS,YAAY;KACf,CAAA,CACL;;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,QAAD;KAAM,WAAU;eAAhB;MACE,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;MACrB,EAAI;MAAU;MACV;QACP,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MACE,MAAM,EAAI;MACV,QAAO;MACP,KAAI;MACJ,WAAU;gBAJZ,CAKC,SACM,kBAAC,GAAD,EAAc,MAAM,IAAM,CAAA,CAC7B;SACJ,kBAAC,KAAD;MACE,MAAM,EAAI;MACV,QAAO;MACP,KAAI;MACJ,cAAY,GAAG,EAAI,KAAK;MACxB,WAAU;gBAEV,kBAAC,GAAD;OAAQ,MAAM;OAAI,eAAY;OAAS,CAAA;MACrC,CAAA,CACA;OACF;;GACF;;GAIJ,KAAgC,EAAE,cACtC,kBAAC,KAAD;CACE,MAAM,EAAK;CACX,QAAO;CACP,KAAI;CACJ,WAAU;WAJZ;EAME,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAK;GACF,CAAA;EACN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,MAAD;KAAI,WAAU;eAA0C,EAAK;KAAU,CAAA,EACtE,EAAK,SACJ,kBAAC,QAAD;KAAM,WAAU;eAAoG;KAE7G,CAAA,CAEL;OACN,kBAAC,KAAD;IAAG,WAAU;cAAsC,EAAK;IAAgB,CAAA,CACpE;;EACN,kBAAC,GAAD;GACE,MAAM;GACN,WAAU;GACV,CAAA;EACA;IAGA,KAAyC,EAAE,iBAC/C,kBAAC,OAAD;CAAK,WAAU;WAAf;EACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAQ;KACL,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eAAiB,EAAQ;KAAU,CAAA,EACjD,kBAAC,KAAD;KAAG,WAAU;eAAiC,EAAQ;KAAc,CAAA,CAChE,EAAA,CAAA,CACF;OACN,kBAAC,QAAD;IAAM,WAAU;cAAhB,CACE,kBAAC,GAAD;KAAM,MAAM;KAAI,WAAU;KAA6B,CAAA,EACtD,EAAQ,MAAM,gBAAgB,CAC1B;MACH;;EAEN,kBAAC,KAAD;GAAG,WAAU;aAAsC,EAAQ;GAAgB,CAAA;EAE3E,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,KAAD;IACE,MAAM,EAAQ;IACd,QAAO;IACP,KAAI;IACJ,WAAU;cAJZ,CAME,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA,EAAA,iBAElB;OACH,EAAQ,WACP,kBAAC,KAAD;IACE,MAAM,EAAQ;IACd,QAAO;IACP,KAAI;IACJ,WAAU;cAJZ,CAME,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA,EAAA,OAEjB;MAEF;;EACF;IAGF,KAAmC,EAAE,eAQvC,kBAAC,KAAD;CACE,MAAM,EAAM;CACZ,QAAO;CACP,KAAI;CACJ,WAAU;WAJZ;EAME,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;GAClB,CAAA;EACN,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAM;KACJ,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eACV,EAAM;KACL,CAAA;IACJ,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,QAAD;MACE,WAAW,EACT,2DA1Ba;OACvB,UAAU;OACV,cAAc;OACd,UAAU;OACX,CAuB4B,EAAM,YACxB;gBAEA,EAAM;MACF,CAAA,EACP,kBAAC,QAAD;MAAM,WAAU;gBACb,EAAM;MACF,CAAA,CACH;;IACF;;EACN,kBAAC,GAAD;GACE,MAAM;GACN,WAAU;GACV,CAAA;EACA;IAQK,UAA0B;CACrC,IAAM,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAQ,EAAE,EAAI;AACpB,SAAO,MAAU,IAAM,IAAW;IAE9B,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAU,KAAe,EAA2B,MAAM;AAEjE,QACE,kBAAC,GAAD;EACE,OAAO,EAAG,gCAAgC,sBAAsB;EAChE,aAAa,EACX,kCACA,4EACD;YALH;GAUE,kBAAC,OAAD;IACE,MAAK;IACL,WAAU;cAFZ,CAIE,kBAAC,UAAD;KAAQ,WAAU;eACf,EAAG,wCAAwC,cAAc;KACnD,CAAA,EACT,kBAAC,QAAD;KAAM,WAAU;eACb,EACC,8CACA,+HACD;KACI,CAAA,CACH;;GAGN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MACE,MAAM;MACN,WAAU;MACV,CAAA,EACF,kBAAC,SAAD;MACE,MAAK;MACL,aAAa,EAAG,6BAA6B,sBAAsB;MACnE,OAAO;MACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;MAC/C,WAAU;MACV,CAAA,CACE;QACN,kBAAC,OAAD;KAAK,WAAU;eACZ;MACC;OAAE,IAAI;OAAO,OAAO,EAAG,uBAAuB,MAAM;OAAE;MACtD;OAAE,IAAI;OAAQ,OAAO,EAAG,wBAAwB,OAAO;OAAE;MACzD;OAAE,IAAI;OAAS,OAAO,EAAG,yBAAyB,QAAQ;OAAE;MAC5D;OACE,IAAI;OACJ,OAAO,EAAG,4BAA4B,WAAW;OAClD;MACD;OAAE,IAAI;OAAU,OAAO,EAAG,0BAA0B,SAAS;OAAE;MAChE,CAAC,KAAK,MACL,kBAAC,UAAD;MAEE,eAAe,EAAY,EAAI,GAAuB;MACtD,WAAW,EACT,6DACA,MAAa,EAAI,KACb,uCACA,iBACL;gBAEA,EAAI;MACE,EAVF,EAAI,GAUF,CACT;KACE,CAAA,CACF;;IAGJ,MAAa,SAAS,MAAa,WACnC,kBAAC,GAAD;IACE,OAAO,EAAG,0BAA0B,gBAAgB;IACpD,aAAa,EACX,qCACA,yCACD;cAED,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAK,KAAK,MACT,kBAAC,GAAD,EAA2B,QAAO,EAApB,EAAI,GAAgB,CAClC;KACE,CAAA;IACM,CAAA;IAId,MAAa,SAAS,MAAa,YACnC,kBAAC,GAAD;IACE,OAAO,EAAG,4BAA4B,kBAAkB;IACxD,aAAa,EACX,uCACA,gDACD;cAED,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAM,KAAK,MACV,kBAAC,GAAD,EAA8B,SAAQ,EAAvB,EAAK,GAAkB,CACtC;KACE,CAAA;IACM,CAAA;IAId,MAAa,SAAS,MAAa,eACnC,kBAAC,GAAD;IACE,OAAO,EAAG,8BAA8B,oBAAoB;IAC5D,aAAa,EACX,yCACA,uDACD;cAED,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAS,KAAK,MACb,kBAAC,GAAD,EAAuC,YAAW,EAAhC,EAAQ,GAAwB,CAClD;KACE,CAAA;IACM,CAAA;IAId,MAAa,SAAS,MAAa,aACnC,kBAAC,GAAD;IACE,OAAO,EAAG,8BAA8B,sBAAsB;IAC9D,aAAa,EACX,yCACA,gCACD;cAED,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAO,KAAK,MACX,kBAAC,GAAD,EAAiC,UAAS,EAA1B,EAAM,GAAoB,CAC1C;KACE,CAAA;IACM,CAAA;GAEL"}
1
+ {"version":3,"file":"ResourcesPage.js","names":[],"sources":["../../../src/devportal/pages/ResourcesPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState } from \"react\";\nimport {\n Terminal,\n FileCode,\n Download,\n ExternalLink,\n Github,\n Code2,\n BookOpen,\n Wrench,\n Cpu,\n Boxes,\n Globe,\n Smartphone,\n Monitor,\n Layers,\n Palette,\n Search,\n Star,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { cn } from \"../utils/cn\";\nimport {\n nativeCopyText,\n nativeImpact,\n nativeNotify,\n} from \"../../utils/nativeBridge\";\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\ninterface SDK {\n id: string;\n name: string;\n language: string;\n description: string;\n version: string;\n downloads: string;\n icon: React.ReactNode;\n packageManager: string;\n installCommand: string;\n docsUrl: string;\n githubUrl: string;\n isOfficial: boolean;\n}\n\ninterface Tool {\n id: string;\n name: string;\n description: string;\n icon: React.ReactNode;\n type: \"cli\" | \"extension\" | \"library\" | \"utility\";\n url: string;\n isNew?: boolean;\n}\n\ninterface Starter {\n id: string;\n name: string;\n description: string;\n framework: string;\n icon: React.ReactNode;\n githubUrl: string;\n demoUrl?: string;\n stars: number;\n}\n\ninterface Guide {\n id: string;\n title: string;\n description: string;\n difficulty: \"beginner\" | \"intermediate\" | \"advanced\";\n duration: string;\n url: string;\n}\n\ntype ResourceCategory = \"all\" | \"sdks\" | \"tools\" | \"starters\" | \"guides\";\n\n// =============================================================================\n// DATA\n// =============================================================================\n\nconst sdks: SDK[] = [\n {\n id: \"sdk-node\",\n name: \"Node.js SDK\",\n language: \"TypeScript/JavaScript\",\n description:\n \"Official SDK for Node.js applications with TypeScript support\",\n version: \"2.4.1\",\n downloads: \"125k\",\n icon: <Code2 size={24} />,\n packageManager: \"npm\",\n installCommand: \"npm install @burdenoff/sdk-node\",\n docsUrl: \"https://docs.burdenoff.com/sdks/node\",\n githubUrl: \"https://github.com/burdenoff/sdk-node\",\n isOfficial: true,\n },\n {\n id: \"sdk-python\",\n name: \"Python SDK\",\n language: \"Python\",\n description: \"Official SDK for Python applications with async support\",\n version: \"1.8.0\",\n downloads: \"89k\",\n icon: <FileCode size={24} />,\n packageManager: \"pip\",\n installCommand: \"pip install burdenoff-sdk\",\n docsUrl: \"https://docs.burdenoff.com/sdks/python\",\n githubUrl: \"https://github.com/burdenoff/sdk-python\",\n isOfficial: true,\n },\n {\n id: \"sdk-go\",\n name: \"Go SDK\",\n language: \"Go\",\n description: \"Official SDK for Go applications\",\n version: \"1.5.2\",\n downloads: \"45k\",\n icon: <Cpu size={24} />,\n packageManager: \"go\",\n installCommand: \"go get github.com/burdenoff/sdk-go\",\n docsUrl: \"https://docs.burdenoff.com/sdks/go\",\n githubUrl: \"https://github.com/burdenoff/sdk-go\",\n isOfficial: true,\n },\n {\n id: \"sdk-react\",\n name: \"React SDK\",\n language: \"TypeScript/React\",\n description: \"Hooks and components for React applications\",\n version: \"3.1.0\",\n downloads: \"78k\",\n icon: <Boxes size={24} />,\n packageManager: \"npm\",\n installCommand: \"npm install @burdenoff/react\",\n docsUrl: \"https://docs.burdenoff.com/sdks/react\",\n githubUrl: \"https://github.com/burdenoff/sdk-react\",\n isOfficial: true,\n },\n {\n id: \"sdk-ruby\",\n name: \"Ruby SDK\",\n language: \"Ruby\",\n description: \"Community SDK for Ruby on Rails applications\",\n version: \"1.2.0\",\n downloads: \"12k\",\n icon: <FileCode size={24} />,\n packageManager: \"gem\",\n installCommand: \"gem install burdenoff\",\n docsUrl: \"https://docs.burdenoff.com/sdks/ruby\",\n githubUrl: \"https://github.com/burdenoff/sdk-ruby\",\n isOfficial: false,\n },\n];\n\nconst tools: Tool[] = [\n {\n id: \"cli\",\n name: \"Burdenoff CLI\",\n description:\n \"Command-line tool for managing apps, deployments, and testing\",\n icon: <Terminal size={24} />,\n type: \"cli\",\n url: \"https://docs.burdenoff.com/cli\",\n },\n {\n id: \"vscode\",\n name: \"VS Code Extension\",\n description:\n \"IntelliSense, snippets, and debugging for Burdenoff development\",\n icon: <Monitor size={24} />,\n type: \"extension\",\n url: \"https://marketplace.visualstudio.com/items?itemName=burdenoff.burdenoff-vscode\",\n isNew: true,\n },\n {\n id: \"graphql-playground\",\n name: \"GraphQL Playground\",\n description: \"Interactive GraphQL IDE for exploring and testing the API\",\n icon: <Globe size={24} />,\n type: \"utility\",\n url: \"https://api.burdenoff.com/graphql\",\n },\n {\n id: \"postman\",\n name: \"Postman Collection\",\n description: \"Pre-built Postman collection for REST API testing\",\n icon: <Layers size={24} />,\n type: \"utility\",\n url: \"https://www.postman.com/burdenoff/workspace/burdenoff-api\",\n },\n {\n id: \"webhook-tester\",\n name: \"Webhook Tester\",\n description: \"Tool for testing and debugging webhook integrations\",\n icon: <Wrench size={24} />,\n type: \"utility\",\n url: \"https://developers.burdenoff.com/tools/webhook-tester\",\n },\n {\n id: \"oauth-debugger\",\n name: \"OAuth Debugger\",\n description: \"Debug OAuth flows and inspect tokens\",\n icon: <Wrench size={24} />,\n type: \"utility\",\n url: \"https://developers.burdenoff.com/tools/oauth-debugger\",\n isNew: true,\n },\n {\n id: \"ui-kit\",\n name: \"UI Component Kit\",\n description: \"Figma design kit matching Burdenoff platform UI\",\n icon: <Palette size={24} />,\n type: \"library\",\n url: \"https://www.figma.com/community/file/burdenoff-ui-kit\",\n },\n];\n\nconst starters: Starter[] = [\n {\n id: \"nextjs-starter\",\n name: \"Next.js Starter\",\n description:\n \"Full-featured Next.js app with OAuth, webhooks, and API integration\",\n framework: \"Next.js 14\",\n icon: <Boxes size={24} />,\n githubUrl: \"https://github.com/burdenoff/starter-nextjs\",\n demoUrl: \"https://starter-nextjs.burdenoff.dev\",\n stars: 1240,\n },\n {\n id: \"express-starter\",\n name: \"Express.js Starter\",\n description:\n \"Backend starter with Express, TypeScript, and webhook handling\",\n framework: \"Express.js\",\n icon: <Code2 size={24} />,\n githubUrl: \"https://github.com/burdenoff/starter-express\",\n stars: 890,\n },\n {\n id: \"react-starter\",\n name: \"React Dashboard\",\n description: \"React dashboard template with Burdenoff SDK integration\",\n framework: \"React + Vite\",\n icon: <Monitor size={24} />,\n githubUrl: \"https://github.com/burdenoff/starter-react\",\n demoUrl: \"https://starter-react.burdenoff.dev\",\n stars: 756,\n },\n {\n id: \"python-starter\",\n name: \"FastAPI Starter\",\n description: \"Python FastAPI backend with async Burdenoff SDK\",\n framework: \"FastAPI\",\n icon: <FileCode size={24} />,\n githubUrl: \"https://github.com/burdenoff/starter-fastapi\",\n stars: 534,\n },\n {\n id: \"mobile-starter\",\n name: \"React Native Starter\",\n description: \"Mobile app template with Burdenoff authentication\",\n framework: \"React Native\",\n icon: <Smartphone size={24} />,\n githubUrl: \"https://github.com/burdenoff/starter-react-native\",\n stars: 423,\n },\n];\n\nconst guides: Guide[] = [\n {\n id: \"first-app\",\n title: \"Build Your First App\",\n description:\n \"Step-by-step guide to creating and publishing your first application\",\n difficulty: \"beginner\",\n duration: \"30 min\",\n url: \"https://docs.burdenoff.com/guides/first-app\",\n },\n {\n id: \"oauth-setup\",\n title: \"Setting Up OAuth 2.0\",\n description: \"Complete guide to implementing OAuth authentication\",\n difficulty: \"intermediate\",\n duration: \"45 min\",\n url: \"https://docs.burdenoff.com/guides/oauth-setup\",\n },\n {\n id: \"webhooks-guide\",\n title: \"Webhook Integration Guide\",\n description: \"Handle real-time events with webhooks\",\n difficulty: \"intermediate\",\n duration: \"40 min\",\n url: \"https://docs.burdenoff.com/guides/webhooks\",\n },\n {\n id: \"multi-tenant\",\n title: \"Building Multi-Tenant Apps\",\n description: \"Architecture patterns for multi-tenant applications\",\n difficulty: \"advanced\",\n duration: \"60 min\",\n url: \"https://docs.burdenoff.com/guides/multi-tenant\",\n },\n {\n id: \"graphql-subscriptions\",\n title: \"Real-time with GraphQL Subscriptions\",\n description: \"Implement real-time features using GraphQL subscriptions\",\n difficulty: \"advanced\",\n duration: \"50 min\",\n url: \"https://docs.burdenoff.com/guides/subscriptions\",\n },\n {\n id: \"app-security\",\n title: \"Security Best Practices\",\n description: \"Secure your application with industry best practices\",\n difficulty: \"intermediate\",\n duration: \"35 min\",\n url: \"https://docs.burdenoff.com/guides/security\",\n },\n];\n\n// =============================================================================\n// COMPONENTS\n// =============================================================================\n\nconst SDKCard: FC<{ sdk: SDK }> = ({ sdk }) => {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = async () => {\n void nativeImpact(\"light\");\n const ok = await nativeCopyText(sdk.installCommand);\n if (ok) {\n setCopied(true);\n void nativeNotify(\"success\");\n setTimeout(() => setCopied(false), 2000);\n } else {\n void nativeNotify(\"error\");\n }\n };\n\n return (\n <div className=\"flex flex-col rounded-lg border bg-card p-5\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-primary/10 p-2.5 text-primary\">\n {sdk.icon}\n </div>\n <div>\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-semibold\">{sdk.name}</h3>\n {sdk.isOfficial && (\n <span className=\"rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs font-medium text-status-info-text\">\n Official\n </span>\n )}\n </div>\n <p className=\"text-sm text-muted-foreground\">{sdk.language}</p>\n </div>\n </div>\n <span className=\"text-sm text-muted-foreground\">v{sdk.version}</span>\n </div>\n\n <p className=\"mt-3 text-sm text-muted-foreground\">{sdk.description}</p>\n\n <div className=\"mt-4 flex items-center gap-2 rounded-md bg-muted/50 p-2\">\n <code className=\"flex-1 text-xs\">{sdk.installCommand}</code>\n <button\n onClick={handleCopy}\n className=\"rounded px-2 py-1 text-xs hover:bg-muted transition-colors\"\n >\n {copied ? \"Copied!\" : \"Copy\"}\n </button>\n </div>\n\n <div className=\"mt-4 flex items-center justify-between text-sm\">\n <span className=\"flex items-center gap-1 text-muted-foreground\">\n <Download size={14} />\n {sdk.downloads} downloads\n </span>\n <div className=\"flex gap-2\">\n <a\n href={sdk.docsUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center gap-1 text-primary hover:underline\"\n >\n Docs <ExternalLink size={12} />\n </a>\n <a\n href={sdk.githubUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={`${sdk.name} on GitHub`}\n className=\"flex items-center gap-1 text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary\"\n >\n <Github size={14} aria-hidden=\"true\" />\n </a>\n </div>\n </div>\n </div>\n );\n};\n\nconst ToolCard: FC<{ tool: Tool }> = ({ tool }) => (\n <a\n href={tool.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"group flex items-start gap-4 rounded-lg border bg-card p-4 transition-all hover:border-primary/50 hover:shadow-md\"\n >\n <div className=\"rounded-lg bg-primary/10 p-2.5 text-primary\">\n {tool.icon}\n </div>\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <h3 className=\"font-semibold group-hover:text-primary\">{tool.name}</h3>\n {tool.isNew && (\n <span className=\"rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-xs font-medium text-status-success-text\">\n New\n </span>\n )}\n </div>\n <p className=\"mt-1 text-sm text-muted-foreground\">{tool.description}</p>\n </div>\n <ExternalLink\n size={16}\n className=\"text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100\"\n />\n </a>\n);\n\nconst StarterCard: FC<{ starter: Starter }> = ({ starter }) => (\n <div className=\"flex flex-col rounded-lg border bg-card p-5\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-primary/10 p-2.5 text-primary\">\n {starter.icon}\n </div>\n <div>\n <h3 className=\"font-semibold\">{starter.name}</h3>\n <p className=\"text-sm text-muted-foreground\">{starter.framework}</p>\n </div>\n </div>\n <span className=\"flex items-center gap-1 text-sm text-muted-foreground\">\n <Star size={14} className=\"text-status-warning-text\" />\n {starter.stars.toLocaleString()}\n </span>\n </div>\n\n <p className=\"mt-3 text-sm text-muted-foreground\">{starter.description}</p>\n\n <div className=\"mt-4 flex gap-2\">\n <a\n href={starter.githubUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex flex-1 items-center justify-center gap-2 rounded-md border bg-background px-3 py-2 text-sm font-medium hover:bg-accent transition-colors\"\n >\n <Github size={16} />\n View on GitHub\n </a>\n {starter.demoUrl && (\n <a\n href={starter.demoUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center justify-center gap-2 rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors\"\n >\n <Globe size={16} />\n Demo\n </a>\n )}\n </div>\n </div>\n);\n\nconst GuideCard: FC<{ guide: Guide }> = ({ guide }) => {\n const difficultyColors = {\n beginner: \"bg-status-success-bg-subtle text-status-success-text\",\n intermediate: \"bg-status-warning-bg-subtle text-status-warning-text\",\n advanced: \"bg-status-error-bg-subtle text-status-error-text\",\n };\n\n return (\n <a\n href={guide.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"group flex items-center gap-4 rounded-lg border bg-card p-4 transition-all hover:border-primary/50 hover:shadow-md\"\n >\n <div className=\"rounded-lg bg-primary/10 p-2.5 text-primary\">\n <BookOpen size={20} />\n </div>\n <div className=\"flex-1\">\n <h3 className=\"font-semibold group-hover:text-primary\">\n {guide.title}\n </h3>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n {guide.description}\n </p>\n <div className=\"mt-2 flex items-center gap-3\">\n <span\n className={cn(\n \"rounded-full px-2 py-0.5 text-xs font-medium capitalize\",\n difficultyColors[guide.difficulty],\n )}\n >\n {guide.difficulty}\n </span>\n <span className=\"text-xs text-muted-foreground\">\n {guide.duration}\n </span>\n </div>\n </div>\n <ExternalLink\n size={16}\n className=\"text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100\"\n />\n </a>\n );\n};\n\n// =============================================================================\n// PAGE COMPONENT\n// =============================================================================\n\nexport const ResourcesPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [category, setCategory] = useState<ResourceCategory>(\"all\");\n\n return (\n <PageLayout\n title={tr(\"devportal.developerResources\", \"Developer Resources\")}\n description={tr(\n \"devportal.resourcesDescription\",\n \"SDKs, tools, starter templates, and guides to accelerate your development\",\n )}\n >\n {/* Coming-soon banner — Resources is a deferred surface (see\n devportal stability tracker). The cards below are curated external\n links until the in-product CMS lands. */}\n <div\n role=\"status\"\n className=\"mb-6 rounded-lg border border-status-warning-border bg-status-warning-bg p-4 text-sm text-status-warning-text\"\n >\n <strong className=\"font-semibold\">\n {tr(\"devportal.resources.comingSoon.title\", \"Coming soon\")}\n </strong>\n <span className=\"ml-2\">\n {tr(\n \"devportal.resources.comingSoon.description\",\n \"An in-product resources hub is on the way. For now we're surfacing the most useful external SDKs, tools, and templates here.\",\n )}\n </span>\n </div>\n\n {/* Search and Filter */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"relative flex-1 max-w-md\">\n <Search\n size={16}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground\"\n />\n <input\n type=\"text\"\n placeholder={tr(\"devportal.searchResources\", \"Search resources...\")}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full rounded-md border bg-background pl-9 pr-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n />\n </div>\n <div className=\"flex items-center gap-1 rounded-md border p-1\">\n {[\n { id: \"all\", label: tr(\"devportal.filterAll\", \"All\") },\n { id: \"sdks\", label: tr(\"devportal.filterSdks\", \"SDKs\") },\n { id: \"tools\", label: tr(\"devportal.filterTools\", \"Tools\") },\n {\n id: \"starters\",\n label: tr(\"devportal.filterStarters\", \"Starters\"),\n },\n { id: \"guides\", label: tr(\"devportal.filterGuides\", \"Guides\") },\n ].map((cat) => (\n <button\n key={cat.id}\n onClick={() => setCategory(cat.id as ResourceCategory)}\n className={cn(\n \"rounded px-3 py-1.5 text-sm font-medium transition-colors\",\n category === cat.id\n ? \"bg-primary text-primary-foreground\"\n : \"hover:bg-muted\",\n )}\n >\n {cat.label}\n </button>\n ))}\n </div>\n </div>\n\n {/* SDKs */}\n {(category === \"all\" || category === \"sdks\") && (\n <PageSection\n title={tr(\"devportal.officialSdks\", \"Official SDKs\")}\n description={tr(\n \"devportal.officialSdksDescription\",\n \"Client libraries for popular languages\",\n )}\n >\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {sdks.map((sdk) => (\n <SDKCard key={sdk.id} sdk={sdk} />\n ))}\n </div>\n </PageSection>\n )}\n\n {/* Developer Tools */}\n {(category === \"all\" || category === \"tools\") && (\n <PageSection\n title={tr(\"devportal.developerTools\", \"Developer Tools\")}\n description={tr(\n \"devportal.developerToolsDescription\",\n \"Tools to streamline your development workflow\",\n )}\n >\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {tools.map((tool) => (\n <ToolCard key={tool.id} tool={tool} />\n ))}\n </div>\n </PageSection>\n )}\n\n {/* Starter Templates */}\n {(category === \"all\" || category === \"starters\") && (\n <PageSection\n title={tr(\"devportal.starterTemplates\", \"Starter Templates\")}\n description={tr(\n \"devportal.starterTemplatesDescription\",\n \"Production-ready templates to kickstart your project\",\n )}\n >\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {starters.map((starter) => (\n <StarterCard key={starter.id} starter={starter} />\n ))}\n </div>\n </PageSection>\n )}\n\n {/* Guides */}\n {(category === \"all\" || category === \"guides\") && (\n <PageSection\n title={tr(\"devportal.stepByStepGuides\", \"Step-by-Step Guides\")}\n description={tr(\n \"devportal.stepByStepGuidesDescription\",\n \"Learn with hands-on tutorials\",\n )}\n >\n <div className=\"grid gap-4 lg:grid-cols-2\">\n {guides.map((guide) => (\n <GuideCard key={guide.id} guide={guide} />\n ))}\n </div>\n </PageSection>\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}