@cat-factory/app 0.302.2 → 0.303.1
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 +99 -14
- package/app/app.config.ts +19 -10
- package/app/assets/css/main.css +13 -13
- package/app/assets/css/prose.css +22 -22
- package/app/assets/css/tokens.css +298 -0
- package/app/components/assistant/AssistantModal.vue +22 -22
- package/app/components/auth/AuthGate.vue +1 -1
- package/app/components/auth/BackendMisconfiguredScreen.vue +10 -10
- package/app/components/auth/LoginScreen.vue +34 -36
- package/app/components/auth/ResetPasswordScreen.vue +12 -12
- package/app/components/auth/UserMenu.vue +4 -4
- package/app/components/binaryCandidates/BinaryCandidatesWindow.vue +27 -25
- package/app/components/binaryOutput/BinaryOutputReport.vue +15 -15
- package/app/components/binaryOutput/StoredAssetView.vue +5 -5
- package/app/components/board/AddTaskModal.vue +17 -20
- package/app/components/board/AgentFailureCard.vue +11 -11
- package/app/components/board/AgentFailureHistory.vue +2 -2
- package/app/components/board/BoardCanvas.vue +6 -5
- package/app/components/board/CreateInitiativeModal.vue +8 -10
- package/app/components/board/DependencyConnectOverlay.vue +1 -1
- package/app/components/board/FailureHistoryList.vue +7 -7
- package/app/components/board/RecurringPipelineModal.vue +17 -17
- package/app/components/board/ReviewFrictionDialog.vue +6 -6
- package/app/components/board/StepExecutionHistory.vue +13 -13
- package/app/components/board/TaskDependencyEdges.vue +8 -8
- package/app/components/board/nodes/AgentChip.vue +10 -10
- package/app/components/board/nodes/BlockNode.vue +29 -29
- package/app/components/board/nodes/DecisionBadge.vue +2 -2
- package/app/components/board/nodes/EpicNode.vue +14 -10
- package/app/components/board/nodes/FrameSwimlanes.vue +7 -9
- package/app/components/board/nodes/InitiativeCard.vue +8 -8
- package/app/components/board/nodes/LaneGroup.vue +1 -1
- package/app/components/board/nodes/LaneTask.vue +2 -2
- package/app/components/board/nodes/ResizeGrips.vue +4 -4
- package/app/components/board/nodes/TaskCard.vue +18 -18
- package/app/components/board/nodes/TaskLane.vue +5 -5
- package/app/components/board/nodes/TaskPipelineMini.vue +18 -18
- package/app/components/bootstrap/AdoptionReviewModal.vue +29 -26
- package/app/components/bootstrap/BootstrapModal.vue +21 -23
- package/app/components/bootstrap/BootstrapRunSteps.vue +1 -1
- package/app/components/brainstorm/BrainstormWindow.vue +30 -33
- package/app/components/bugFishing/BugFishingWindow.vue +49 -49
- package/app/components/clarity/ClarityReviewWindow.vue +30 -30
- package/app/components/common/AsyncViewError.vue +5 -5
- package/app/components/common/ClarificationItem.vue +8 -13
- package/app/components/common/ConfirmDialog.vue +4 -2
- package/app/components/common/DescriptorFields.vue +1 -1
- package/app/components/common/EmptyState.vue +3 -3
- package/app/components/common/InterviewGateNotice.vue +7 -7
- package/app/components/common/KeyboardShortcutsHelp.vue +1 -1
- package/app/components/common/MarkdownProse.vue +14 -13
- package/app/components/consensus/ConsensusSessionWindow.vue +26 -26
- package/app/components/context/ContextAttachmentFields.vue +17 -17
- package/app/components/docs/DocInterviewWindow.vue +14 -14
- package/app/components/documents/ContextDocumentPicker.vue +17 -17
- package/app/components/documents/DocumentImportModal.vue +7 -7
- package/app/components/documents/DocumentSourceConnectModal.vue +3 -3
- package/app/components/documents/DocumentSyncState.vue +5 -5
- package/app/components/documents/DocumentTemplatesModal.vue +15 -15
- package/app/components/documents/RepoContextDocPicker.vue +5 -5
- package/app/components/documents/SpawnPreviewModal.vue +12 -12
- package/app/components/documents/StartFromDesignModal.vue +11 -11
- package/app/components/documents/TaskContextDocs.vue +5 -5
- package/app/components/environments/EnvSetupStepper.vue +6 -6
- package/app/components/environments/EnvironmentStatusPanel.vue +17 -17
- package/app/components/environments/steps/EnvPickStep.vue +3 -3
- package/app/components/environments/steps/EnvPreflightStep.vue +9 -9
- package/app/components/environments/steps/EnvReviewStep.vue +25 -22
- package/app/components/environments/steps/EnvSaveStep.vue +7 -5
- package/app/components/environments/steps/JourneyStepNav.vue +1 -1
- package/app/components/focus/BlockFocusView.vue +17 -19
- package/app/components/followUp/FollowUpWindow.vue +23 -23
- package/app/components/forkDecision/ForkDecisionWindow.vue +37 -39
- package/app/components/foundational/FoundationalContractSummary.vue +7 -7
- package/app/components/foundational/FoundationalServiceCatalogList.vue +11 -11
- package/app/components/foundational/FoundationalServiceManager.vue +1 -1
- package/app/components/foundational/FoundationalServiceRegistry.vue +13 -13
- package/app/components/foundational/FoundationalServiceSources.vue +13 -13
- package/app/components/foundational/FoundationalSuppressions.vue +7 -7
- package/app/components/foundational/ServiceCatalogConnection.vue +10 -10
- package/app/components/fragments/FragmentLibraryManager.vue +41 -44
- package/app/components/fragments/FragmentSelector.vue +13 -13
- package/app/components/fragments/GitHubDocUrlImport.vue +1 -1
- package/app/components/gates/GateFailingCheckList.vue +5 -5
- package/app/components/gates/GateResultView.vue +50 -47
- package/app/components/github/AddServiceFromRepoModal.vue +14 -14
- package/app/components/github/BranchProtectionPreflight.vue +13 -13
- package/app/components/github/GitHubConnect.vue +7 -7
- package/app/components/github/GitHubOnboarding.vue +7 -7
- package/app/components/github/GitHubPanel.vue +37 -40
- package/app/components/github/RepoTreeBrowser.vue +18 -18
- package/app/components/humanTest/HumanTestWindow.vue +30 -33
- package/app/components/initiative/InitiativePlanNotice.vue +5 -5
- package/app/components/initiative/InitiativePlanReview.vue +27 -29
- package/app/components/initiative/InitiativePlanningWindow.vue +10 -10
- package/app/components/initiative/InitiativeTrackerWindow.vue +71 -65
- package/app/components/inputGate/InputGateNotice.vue +2 -4
- package/app/components/judge/JudgeResultView.vue +30 -32
- package/app/components/kaizen/KaizenPanel.vue +40 -36
- package/app/components/kaizen/KaizenStepStatus.vue +21 -21
- package/app/components/layout/AccountAuditLog.vue +10 -10
- package/app/components/layout/AccountDeploymentSettings.vue +20 -20
- package/app/components/layout/AccountFailureKindRules.vue +13 -13
- package/app/components/layout/AccountFoundationalSettings.vue +1 -1
- package/app/components/layout/AccountFragmentSettings.vue +1 -1
- package/app/components/layout/AccountModelPolicySettings.vue +9 -9
- package/app/components/layout/AccountPlatformAlertSettings.vue +11 -11
- package/app/components/layout/AccountRiskPolicySettings.vue +2 -2
- package/app/components/layout/AccountRunCredentialSettings.vue +5 -5
- package/app/components/layout/AccountSkillSettings.vue +1 -1
- package/app/components/layout/AccountTeamSettings.vue +23 -15
- package/app/components/layout/AiProvidersBanner.vue +11 -8
- package/app/components/layout/AppearanceSwitcher.vue +108 -0
- package/app/components/layout/BoardSwitcher.vue +8 -11
- package/app/components/layout/BoardToolbar.vue +3 -3
- package/app/components/layout/CommandBar.vue +7 -9
- package/app/components/layout/ConnectionStatusBanner.vue +2 -2
- package/app/components/layout/DefaultTestEnvBanner.vue +5 -5
- package/app/components/layout/GitHubPatBanner.vue +5 -5
- package/app/components/layout/GitHubPatPermissionsBanner.vue +16 -10
- package/app/components/layout/InfraSetupBanner.vue +6 -6
- package/app/components/layout/IntegrationsHub.vue +15 -15
- package/app/components/layout/LanguageSwitcher.vue +5 -5
- package/app/components/layout/ModelProvidersHub.vue +13 -16
- package/app/components/layout/NotificationsInbox.vue +10 -10
- package/app/components/layout/PersonalSetupModal.vue +8 -8
- package/app/components/layout/ProviderConfigBanner.vue +4 -4
- package/app/components/layout/RolePrompt.vue +7 -7
- package/app/components/layout/SideBar.vue +6 -4
- package/app/components/layout/SpendWarningBanner.vue +17 -14
- package/app/components/layout/TranslationWarningBanner.vue +4 -4
- package/app/components/layout/UiModeSwitcher.vue +13 -13
- package/app/components/layout/UiRoleSwitcher.vue +8 -8
- package/app/components/layout/WorkspaceMembersSettings.vue +15 -11
- package/app/components/media/ArtifactLightbox.vue +13 -13
- package/app/components/media/ImageCompare.vue +31 -24
- package/app/components/merge/MergeEffortChips.vue +2 -2
- package/app/components/notifications/NotificationSettingsPanel.vue +14 -12
- package/app/components/observability/OutcomeFilterChips.vue +6 -6
- package/app/components/observability/RunFailureSummary.vue +28 -25
- package/app/components/observability/StepMetricsBar.vue +26 -28
- package/app/components/observability/StepModelActivity.vue +2 -2
- package/app/components/observability/ToolCallList.vue +24 -24
- package/app/components/outcome/OutcomeSummaryWindow.vue +47 -47
- package/app/components/palettes/AgentPalette.vue +8 -8
- package/app/components/palettes/AgentTierSelect.vue +1 -1
- package/app/components/palettes/PipelinePurposeSelect.vue +1 -1
- package/app/components/panels/AgentStepDetail.vue +52 -51
- package/app/components/panels/AttemptEntryHeader.vue +4 -6
- package/app/components/panels/DecisionModal.vue +7 -7
- package/app/components/panels/GenericStructuredResultView.vue +7 -7
- package/app/components/panels/InspectorPanel.vue +17 -17
- package/app/components/panels/MergerResultView.vue +19 -19
- package/app/components/panels/ObservabilityPanel.vue +115 -123
- package/app/components/panels/OperatorDashboardPanel.vue +89 -97
- package/app/components/panels/ReportsPanel.vue +69 -66
- package/app/components/panels/ReportsSpendBreakdown.vue +9 -9
- package/app/components/panels/ResultWindowShell.vue +38 -38
- package/app/components/panels/RunDetailLoadState.vue +2 -2
- package/app/components/panels/StepContainerStatus.vue +9 -9
- package/app/components/panels/StepDelegatedStatus.logic.spec.ts +135 -0
- package/app/components/panels/StepDelegatedStatus.logic.ts +160 -0
- package/app/components/panels/StepDelegatedStatus.vue +181 -0
- package/app/components/panels/StepEffortReport.vue +16 -15
- package/app/components/panels/StepFragmentAdherence.vue +14 -10
- package/app/components/panels/StepMetadataCard.vue +74 -45
- package/app/components/panels/StepReproductionReport.vue +25 -21
- package/app/components/panels/StepRunMeta.vue +20 -20
- package/app/components/panels/StepTestReport.logic.spec.ts +8 -3
- package/app/components/panels/StepTestReport.logic.ts +4 -4
- package/app/components/panels/StepTestReport.vue +28 -28
- package/app/components/panels/StepToolServers.vue +14 -11
- package/app/components/panels/StepValidationReport.vue +7 -7
- package/app/components/panels/inspector/ContainerSummary.vue +9 -9
- package/app/components/panels/inspector/DocReferenceRepos.vue +3 -3
- package/app/components/panels/inspector/EnvProbeReport.vue +24 -27
- package/app/components/panels/inspector/EpicChildren.vue +8 -12
- package/app/components/panels/inspector/FrontendBindingsResolved.vue +11 -11
- package/app/components/panels/inspector/FrontendConfig.vue +37 -41
- package/app/components/panels/inspector/InitiativeInspector.vue +3 -3
- package/app/components/panels/inspector/InspectorSection.vue +6 -6
- package/app/components/panels/inspector/RecurringScheduleSettings.vue +16 -19
- package/app/components/panels/inspector/ServiceConnections.vue +2 -2
- package/app/components/panels/inspector/ServiceReleaseHealthConfig.vue +2 -2
- package/app/components/panels/inspector/ServiceSelfTests.vue +21 -17
- package/app/components/panels/inspector/ServiceTestConfig.vue +51 -59
- package/app/components/panels/inspector/ServiceTestSecrets.vue +5 -5
- package/app/components/panels/inspector/ServiceTestingContext.vue +3 -3
- package/app/components/panels/inspector/ServiceValidationConfig.vue +2 -2
- package/app/components/panels/inspector/TaskAgentConfig.vue +3 -3
- package/app/components/panels/inspector/TaskAprioriBranches.vue +8 -5
- package/app/components/panels/inspector/TaskDependencies.vue +1 -1
- package/app/components/panels/inspector/TaskEstimateBadge.vue +11 -11
- package/app/components/panels/inspector/TaskExecution.vue +17 -17
- package/app/components/panels/inspector/TaskReviewTarget.vue +2 -2
- package/app/components/panels/inspector/TaskRunSettings.vue +35 -37
- package/app/components/panels/inspector/TaskStructure.vue +3 -3
- package/app/components/pipeline/AgentKindIcon.vue +1 -1
- package/app/components/pipeline/AgentPromptEditor.vue +17 -17
- package/app/components/pipeline/BinaryOutputStepPicker.vue +42 -56
- package/app/components/pipeline/EstimateThresholdFields.vue +4 -4
- package/app/components/pipeline/GateConfigFields.vue +13 -10
- package/app/components/pipeline/IterationCapPrompt.vue +4 -2
- package/app/components/pipeline/PipelineBuilder.vue +47 -55
- package/app/components/pipeline/PipelineHealthModal.vue +27 -29
- package/app/components/pipeline/PipelinePicker.vue +10 -10
- package/app/components/pipeline/PipelinePreview.vue +10 -10
- package/app/components/pipeline/PipelineProgress.vue +64 -67
- package/app/components/prReview/PrReviewPhaseBadge.vue +7 -7
- package/app/components/prReview/PrReviewWindow.vue +75 -77
- package/app/components/providers/AiPresetMismatchDialog.vue +5 -5
- package/app/components/providers/AiProviderOnboardingModal.vue +9 -9
- package/app/components/providers/ApiKeysSection.vue +13 -13
- package/app/components/providers/PersonalCredentialModal.vue +2 -2
- package/app/components/providers/PersonalSubscriptionSection.vue +10 -10
- package/app/components/providers/SignInRequiredNotice.vue +1 -1
- package/app/components/providers/VendorCredentialsModal.vue +10 -10
- package/app/components/provisioning/ProvisioningLogsDrawer.vue +13 -13
- package/app/components/ralph/RalphLoopResultView.vue +28 -30
- package/app/components/recurring/RecurrenceEditor.vue +2 -2
- package/app/components/requirements/RequirementsReviewWindow.vue +51 -58
- package/app/components/riskPolicy/RiskPolicyPicker.vue +12 -15
- package/app/components/riskPolicy/RiskPolicyPreview.vue +14 -14
- package/app/components/sandbox/SandboxPanel.vue +58 -59
- package/app/components/settings/AccountSettingsPanel.vue +1 -1
- package/app/components/settings/ApiTokensPanel.vue +10 -10
- package/app/components/settings/BudgetSettings.vue +18 -22
- package/app/components/settings/CapabilityCredentialsPanel.vue +15 -15
- package/app/components/settings/CloudflareHandlerSection.vue +20 -20
- package/app/components/settings/ComposeEnvironmentSetupSection.vue +13 -13
- package/app/components/settings/ConnectionTestVerdict.vue +3 -3
- package/app/components/settings/ConnectionWarnings.vue +1 -1
- package/app/components/settings/ConsensusGroupsSection.vue +27 -35
- package/app/components/settings/CustomManifestTypeEditor.vue +10 -10
- package/app/components/settings/DefaultProvisionTypeSection.vue +6 -6
- package/app/components/settings/InfraHandlersConfigurator.vue +24 -22
- package/app/components/settings/InfrastructureBackendPicker.vue +6 -6
- package/app/components/settings/InfrastructureWindow.vue +5 -5
- package/app/components/settings/IssueTrackerPanel.vue +29 -23
- package/app/components/settings/KubernetesEngineForm.vue +11 -11
- package/app/components/settings/KubernetesEnvironmentForm.vue +4 -4
- package/app/components/settings/LocalContainerPoolSettings.vue +6 -11
- package/app/components/settings/LocalModelEndpointsPanel.vue +20 -18
- package/app/components/settings/McpAuthorizeScreen.vue +13 -15
- package/app/components/settings/McpOAuthCallbackScreen.vue +16 -10
- package/app/components/settings/MergeClassRulesEditor.vue +6 -9
- package/app/components/settings/MergeRolePolicyEditor.vue +16 -16
- package/app/components/settings/ModelConfigurationPanel.vue +23 -30
- package/app/components/settings/ModelPresetHealthModal.vue +15 -13
- package/app/components/settings/ObservabilityConnectionPanel.vue +4 -4
- package/app/components/settings/OpenRouterCatalogPanel.vue +26 -19
- package/app/components/settings/PackageRegistriesPanel.vue +8 -8
- package/app/components/settings/ProviderConnectionTab.vue +8 -11
- package/app/components/settings/ProviderManifestEditor.vue +9 -9
- package/app/components/settings/ProviderPreferenceEditor.vue +8 -8
- package/app/components/settings/RiskPolicyCreateForm.vue +10 -10
- package/app/components/settings/RiskPolicyEditorRow.vue +14 -14
- package/app/components/settings/RiskPolicyHealthModal.vue +15 -13
- package/app/components/settings/RiskPolicyInheritedRow.vue +1 -1
- package/app/components/settings/RiskPolicyPanel.vue +10 -15
- package/app/components/settings/ServiceFragmentDefaultsPanel.vue +7 -7
- package/app/components/settings/SharedStacksPanel.vue +9 -12
- package/app/components/settings/TaskSourceCard.vue +4 -4
- package/app/components/settings/TaskTypeSuppressionsPanel.vue +6 -6
- package/app/components/settings/ToolServerChecklist.vue +36 -29
- package/app/components/settings/UsageSettings.vue +15 -15
- package/app/components/settings/UserSecretsSection.vue +9 -12
- package/app/components/settings/WorkspaceMetadataSettings.vue +5 -5
- package/app/components/settings/WorkspaceSettingsPanel.vue +47 -47
- package/app/components/skills/ReviewSkillQueue.vue +10 -10
- package/app/components/skills/SkillLibraryManager.vue +23 -20
- package/app/components/slack/SlackPanel.vue +13 -17
- package/app/components/spec/ServiceSpecWindow.vue +45 -42
- package/app/components/tasks/BugHuntModal.vue +24 -27
- package/app/components/tasks/ContextIssuePicker.vue +11 -11
- package/app/components/tasks/TaskContextIssues.vue +3 -3
- package/app/components/tasks/TaskImportModal.vue +7 -7
- package/app/components/tasks/TaskSourceConnectModal.vue +10 -8
- package/app/components/testing/TestReportWindow.vue +99 -82
- package/app/components/theme/ThemeImportModal.vue +115 -0
- package/app/components/tutorial/TutorialCatalogue.vue +9 -9
- package/app/components/tutorial/TutorialNudge.vue +5 -5
- package/app/components/tutorial/TutorialOverlay.vue +12 -12
- package/app/components/tutorial/TutorialPrompt.vue +6 -9
- package/app/components/vcs/GitLabConnect.vue +4 -4
- package/app/components/vcs/VcsConnectSurfaces.vue +2 -2
- package/app/components/visualConfirm/VisualConfirmationWindow.vue +36 -36
- package/app/composables/api/client.ts +6 -1
- package/app/composables/usePipelineErrorToast.ts +17 -0
- package/app/modular/agent-kinds.ts +24 -0
- package/app/pages/index.vue +5 -5
- package/app/plugins/theme.client.ts +125 -0
- package/app/spa-loading-template.html +52 -14
- package/app/stores/agents.ts +1 -1
- package/app/stores/theme.spec.ts +56 -0
- package/app/stores/theme.ts +87 -0
- package/app/types/domain.ts +19 -0
- package/app/types/execution.ts +4 -0
- package/app/utils/agentOutput.ts +1 -1
- package/app/utils/binaryOutput.ts +6 -6
- package/app/utils/bootstrapSteps.ts +14 -14
- package/app/utils/catalog.ts +87 -83
- package/app/utils/colorTint.ts +10 -0
- package/app/utils/failureKinds.ts +1 -0
- package/app/utils/observability.ts +3 -3
- package/app/utils/pipelineRender.ts +13 -17
- package/app/utils/swimlanes.ts +4 -4
- package/app/utils/theme/bootPalette.spec.ts +54 -0
- package/app/utils/theme/bootPalette.ts +108 -0
- package/app/utils/theme/builtins.spec.ts +38 -0
- package/app/utils/theme/builtins.ts +55 -0
- package/app/utils/theme/css.ts +162 -0
- package/app/utils/theme/doc.ts +353 -0
- package/app/utils/theme/link.ts +93 -0
- package/app/utils/theme/presets.ts +509 -0
- package/app/utils/theme/theme.spec.ts +224 -0
- package/i18n/locales/de.json +61 -4
- package/i18n/locales/en.json +70 -4
- package/i18n/locales/es.json +61 -4
- package/i18n/locales/fr.json +61 -4
- package/i18n/locales/he.json +61 -4
- package/i18n/locales/it.json +61 -4
- package/i18n/locales/ja.json +61 -4
- package/i18n/locales/pl.json +61 -4
- package/i18n/locales/tr.json +61 -4
- package/i18n/locales/uk.json +61 -4
- package/nuxt.config.ts +37 -11
- package/package.json +10 -9
|
@@ -36,41 +36,44 @@ async function resume() {
|
|
|
36
36
|
re-enables pointer events on it. -->
|
|
37
37
|
<div v-if="exceeded && spend" class="pointer-events-auto w-full max-w-3xl">
|
|
38
38
|
<div
|
|
39
|
-
class="w-full max-w-3xl rounded-2xl border-2 border-
|
|
39
|
+
class="w-full max-w-3xl rounded-2xl border-2 border-app-error-500/70 bg-app-error-950/95 p-5 shadow-2xl backdrop-blur"
|
|
40
40
|
role="alert"
|
|
41
41
|
>
|
|
42
42
|
<div class="flex items-start gap-4">
|
|
43
|
-
<UIcon
|
|
43
|
+
<UIcon
|
|
44
|
+
name="i-lucide-octagon-alert"
|
|
45
|
+
class="mt-0.5 h-10 w-10 shrink-0 text-app-error-400"
|
|
46
|
+
/>
|
|
44
47
|
<div class="min-w-0 flex-1">
|
|
45
|
-
<h2 class="text-lg font-semibold text-
|
|
48
|
+
<h2 class="text-lg font-semibold text-app-error-100">
|
|
46
49
|
{{ t('layout.spendWarningBanner.title') }}
|
|
47
50
|
</h2>
|
|
48
|
-
<p class="mt-1 text-sm text-
|
|
51
|
+
<p class="mt-1 text-sm text-app-error-200/90">
|
|
49
52
|
{{ t('layout.spendWarningBanner.body') }}
|
|
50
53
|
</p>
|
|
51
54
|
|
|
52
55
|
<dl class="mt-4 grid grid-cols-2 gap-3 sm:grid-cols-3">
|
|
53
|
-
<div class="rounded-lg bg-
|
|
54
|
-
<dt class="text-[11px] uppercase tracking-wide text-
|
|
56
|
+
<div class="rounded-lg bg-app-error-900/50 px-3 py-2">
|
|
57
|
+
<dt class="text-[11px] uppercase tracking-wide text-app-error-300/80">
|
|
55
58
|
{{ t('layout.spendWarningBanner.spent') }}
|
|
56
59
|
</dt>
|
|
57
|
-
<dd class="text-base font-semibold tabular-nums text-
|
|
60
|
+
<dd class="text-base font-semibold tabular-nums text-app-error-50">
|
|
58
61
|
{{ money(spend.costSpent, spend.currency) }}
|
|
59
62
|
</dd>
|
|
60
63
|
</div>
|
|
61
|
-
<div class="rounded-lg bg-
|
|
62
|
-
<dt class="text-[11px] uppercase tracking-wide text-
|
|
64
|
+
<div class="rounded-lg bg-app-error-900/50 px-3 py-2">
|
|
65
|
+
<dt class="text-[11px] uppercase tracking-wide text-app-error-300/80">
|
|
63
66
|
{{ t('layout.spendWarningBanner.budget') }}
|
|
64
67
|
</dt>
|
|
65
|
-
<dd class="text-base font-semibold tabular-nums text-
|
|
68
|
+
<dd class="text-base font-semibold tabular-nums text-app-error-50">
|
|
66
69
|
{{ money(spend.costLimit, spend.currency) }}
|
|
67
70
|
</dd>
|
|
68
71
|
</div>
|
|
69
|
-
<div class="rounded-lg bg-
|
|
70
|
-
<dt class="text-[11px] uppercase tracking-wide text-
|
|
72
|
+
<div class="rounded-lg bg-app-error-900/50 px-3 py-2">
|
|
73
|
+
<dt class="text-[11px] uppercase tracking-wide text-app-error-300/80">
|
|
71
74
|
{{ t('layout.spendWarningBanner.tokens') }}
|
|
72
75
|
</dt>
|
|
73
|
-
<dd class="text-base font-semibold tabular-nums text-
|
|
76
|
+
<dd class="text-base font-semibold tabular-nums text-app-error-50">{{ tokens }}</dd>
|
|
74
77
|
</div>
|
|
75
78
|
</dl>
|
|
76
79
|
|
|
@@ -86,7 +89,7 @@ async function resume() {
|
|
|
86
89
|
>
|
|
87
90
|
{{ t('layout.spendWarningBanner.resume') }}
|
|
88
91
|
</UButton>
|
|
89
|
-
<span class="text-xs text-
|
|
92
|
+
<span class="text-xs text-app-error-300/70">
|
|
90
93
|
{{ t('layout.spendWarningBanner.resumeHint') }}
|
|
91
94
|
</span>
|
|
92
95
|
</div>
|
|
@@ -31,19 +31,19 @@ function dismiss() {
|
|
|
31
31
|
v-if="show"
|
|
32
32
|
data-testid="translation-warning"
|
|
33
33
|
role="alert"
|
|
34
|
-
class="flex shrink-0 items-center gap-3 border-b border-
|
|
34
|
+
class="flex shrink-0 items-center gap-3 border-b border-app-warning-500/40 bg-app-warning-950/95 px-4 py-2 text-[13px] text-app-warning-100 shadow-lg backdrop-blur"
|
|
35
35
|
>
|
|
36
|
-
<UIcon name="i-lucide-languages" class="h-4 w-4 shrink-0 text-
|
|
36
|
+
<UIcon name="i-lucide-languages" class="h-4 w-4 shrink-0 text-app-warning-400" />
|
|
37
37
|
<p class="min-w-0 flex-1">
|
|
38
38
|
<span class="font-semibold">{{ t('language.warning.title') }}</span>
|
|
39
|
-
<span class="mx-1.5 text-
|
|
39
|
+
<span class="mx-1.5 text-app-warning-400/60">·</span>
|
|
40
40
|
<i18n-t keypath="language.warning.body" tag="span" scope="global">
|
|
41
41
|
<template #repoLink>
|
|
42
42
|
<a
|
|
43
43
|
:href="REPO_URL"
|
|
44
44
|
target="_blank"
|
|
45
45
|
rel="noopener noreferrer"
|
|
46
|
-
class="inline-flex items-center gap-1 font-medium text-
|
|
46
|
+
class="inline-flex items-center gap-1 font-medium text-app-info-300 hover:underline"
|
|
47
47
|
>
|
|
48
48
|
{{ t('language.warning.repoLinkLabel') }}
|
|
49
49
|
<UIcon name="i-lucide-external-link" class="h-3 w-3" />
|
|
@@ -50,17 +50,17 @@ const pinnedTitle = computed(
|
|
|
50
50
|
v-if="uiMode.envPinned"
|
|
51
51
|
data-testid="ui-mode-pinned"
|
|
52
52
|
:title="pinnedTitle"
|
|
53
|
-
class="flex w-full items-center gap-2 rounded-lg border border-
|
|
53
|
+
class="flex w-full items-center gap-2 rounded-lg border border-default bg-default/40 p-2 text-start"
|
|
54
54
|
:class="collapsed ? 'justify-center' : ''"
|
|
55
55
|
>
|
|
56
|
-
<UIcon :name="icon" class="h-4 w-4 shrink-0 text-
|
|
56
|
+
<UIcon :name="icon" class="h-4 w-4 shrink-0 text-dimmed" />
|
|
57
57
|
<div v-if="!collapsed" class="min-w-0 flex-1">
|
|
58
|
-
<div class="truncate text-[10px] uppercase tracking-wide text-
|
|
58
|
+
<div class="truncate text-[10px] uppercase tracking-wide text-dimmed">
|
|
59
59
|
{{ t('uiMode.switcher') }}
|
|
60
60
|
</div>
|
|
61
|
-
<div class="truncate text-xs font-medium text-
|
|
61
|
+
<div class="truncate text-xs font-medium text-toned">{{ currentLabel }}</div>
|
|
62
62
|
</div>
|
|
63
|
-
<UIcon v-if="!collapsed" name="i-lucide-lock" class="h-3.5 w-3.5 shrink-0 text-
|
|
63
|
+
<UIcon v-if="!collapsed" name="i-lucide-lock" class="h-3.5 w-3.5 shrink-0 text-app-600" />
|
|
64
64
|
</div>
|
|
65
65
|
|
|
66
66
|
<!-- Rail: one button, flips the tier. The label rides under the glyph so the rail still says
|
|
@@ -72,23 +72,23 @@ const pinnedTitle = computed(
|
|
|
72
72
|
data-testid="ui-mode-toggle"
|
|
73
73
|
:aria-label="t('uiMode.switchTo', { mode: t(MODE_LABELS[otherMode]) })"
|
|
74
74
|
:title="t('uiMode.switchTo', { mode: t(MODE_LABELS[otherMode]) })"
|
|
75
|
-
class="flex w-full flex-col items-center gap-0.5 rounded-lg border border-
|
|
75
|
+
class="flex w-full flex-col items-center gap-0.5 rounded-lg border border-muted bg-default/60 px-1 py-1.5 transition hover:border-primary/60 hover:bg-elevated/60"
|
|
76
76
|
@click="uiMode.toggleMode()"
|
|
77
77
|
>
|
|
78
|
-
<UIcon :name="icon" class="h-4 w-4 shrink-0 text-
|
|
79
|
-
<span class="w-full truncate text-center text-[9px] font-medium uppercase text-
|
|
78
|
+
<UIcon :name="icon" class="h-4 w-4 shrink-0 text-primary" />
|
|
79
|
+
<span class="w-full truncate text-center text-[9px] font-medium uppercase text-toned">
|
|
80
80
|
{{ currentLabel }}
|
|
81
81
|
</span>
|
|
82
82
|
</button>
|
|
83
83
|
|
|
84
84
|
<div v-else data-testid="ui-mode-switcher" class="w-full">
|
|
85
|
-
<div class="mb-1 px-1 text-[10px] uppercase tracking-wide text-
|
|
85
|
+
<div class="mb-1 px-1 text-[10px] uppercase tracking-wide text-dimmed">
|
|
86
86
|
{{ t('uiMode.switcher') }}
|
|
87
87
|
</div>
|
|
88
88
|
<div
|
|
89
89
|
role="group"
|
|
90
90
|
:aria-label="t('uiMode.switcher')"
|
|
91
|
-
class="flex w-full gap-1 rounded-lg border border-
|
|
91
|
+
class="flex w-full gap-1 rounded-lg border border-muted bg-default/60 p-1"
|
|
92
92
|
>
|
|
93
93
|
<button
|
|
94
94
|
v-for="mode in UI_MODES"
|
|
@@ -99,8 +99,8 @@ const pinnedTitle = computed(
|
|
|
99
99
|
class="flex-1 truncate rounded-md px-2 py-1 text-xs font-medium transition"
|
|
100
100
|
:class="
|
|
101
101
|
mode === uiMode.mode
|
|
102
|
-
? 'bg-
|
|
103
|
-
: 'text-
|
|
102
|
+
? 'bg-primary/20 text-primary ring-1 ring-primary/50'
|
|
103
|
+
: 'text-muted hover:bg-elevated/70 hover:text-default'
|
|
104
104
|
"
|
|
105
105
|
@click="uiMode.setMode(mode)"
|
|
106
106
|
>
|
|
@@ -111,7 +111,7 @@ const pinnedTitle = computed(
|
|
|
111
111
|
|
|
112
112
|
<!-- The one-line "what this tier gives you", so the choice is self-explanatory. Dropped in
|
|
113
113
|
the collapsed rail, where the tooltip above carries the mode instead. -->
|
|
114
|
-
<p v-if="!collapsed" class="px-1 text-[10px] leading-snug text-
|
|
114
|
+
<p v-if="!collapsed" class="px-1 text-[10px] leading-snug text-dimmed">
|
|
115
115
|
{{ t(MODE_HINTS[uiMode.mode]) }}
|
|
116
116
|
</p>
|
|
117
117
|
</template>
|
|
@@ -44,10 +44,10 @@ const items = computed(() =>
|
|
|
44
44
|
data-testid="ui-role-toggle"
|
|
45
45
|
:aria-label="`${t('uiRole.switcher')}: ${currentLabel}`"
|
|
46
46
|
:title="`${t('uiRole.switcher')}: ${currentLabel}`"
|
|
47
|
-
class="flex w-full flex-col items-center gap-0.5 rounded-lg border border-
|
|
47
|
+
class="flex w-full flex-col items-center gap-0.5 rounded-lg border border-muted bg-default/60 px-1 py-1.5 transition hover:border-primary/60 hover:bg-elevated/60"
|
|
48
48
|
>
|
|
49
|
-
<UIcon :name="current.icon" class="h-4 w-4 shrink-0 text-
|
|
50
|
-
<span class="w-full truncate text-center text-[9px] font-medium uppercase text-
|
|
49
|
+
<UIcon :name="current.icon" class="h-4 w-4 shrink-0 text-primary" />
|
|
50
|
+
<span class="w-full truncate text-center text-[9px] font-medium uppercase text-toned">
|
|
51
51
|
{{ currentLabel }}
|
|
52
52
|
</span>
|
|
53
53
|
</button>
|
|
@@ -58,16 +58,16 @@ const items = computed(() =>
|
|
|
58
58
|
data-testid="ui-role-switcher"
|
|
59
59
|
:aria-label="t('uiRole.switcher')"
|
|
60
60
|
:title="t(current.hintKey)"
|
|
61
|
-
class="flex w-full items-center gap-2 rounded-lg border border-
|
|
61
|
+
class="flex w-full items-center gap-2 rounded-lg border border-muted bg-default/60 p-2 text-start transition hover:border-primary/60 hover:bg-elevated/60"
|
|
62
62
|
>
|
|
63
|
-
<UIcon :name="current.icon" class="h-4 w-4 shrink-0 text-
|
|
63
|
+
<UIcon :name="current.icon" class="h-4 w-4 shrink-0 text-primary" />
|
|
64
64
|
<div class="min-w-0 flex-1">
|
|
65
|
-
<div class="truncate text-[10px] uppercase tracking-wide text-
|
|
65
|
+
<div class="truncate text-[10px] uppercase tracking-wide text-dimmed">
|
|
66
66
|
{{ t('uiRole.switcher') }}
|
|
67
67
|
</div>
|
|
68
|
-
<div class="truncate text-xs font-medium text-
|
|
68
|
+
<div class="truncate text-xs font-medium text-default">{{ currentLabel }}</div>
|
|
69
69
|
</div>
|
|
70
|
-
<UIcon name="i-lucide-chevron-down" class="h-3.5 w-3.5 shrink-0 text-
|
|
70
|
+
<UIcon name="i-lucide-chevron-down" class="h-3.5 w-3.5 shrink-0 text-dimmed" />
|
|
71
71
|
</button>
|
|
72
72
|
</UDropdownMenu>
|
|
73
73
|
</template>
|
|
@@ -139,13 +139,13 @@ function memberLabel(userId: string, name?: string | null, email?: string | null
|
|
|
139
139
|
<template>
|
|
140
140
|
<div class="space-y-6 text-sm" data-testid="workspace-members-settings">
|
|
141
141
|
<!-- access mode -->
|
|
142
|
-
<section class="rounded-md border border-
|
|
142
|
+
<section class="rounded-md border border-default bg-elevated/40 p-4">
|
|
143
143
|
<div class="flex items-start justify-between gap-4">
|
|
144
144
|
<div>
|
|
145
|
-
<h3 class="mb-1 font-semibold text-
|
|
145
|
+
<h3 class="mb-1 font-semibold text-highlighted">
|
|
146
146
|
{{ t('layout.workspaceMembers.accessMode.title') }}
|
|
147
147
|
</h3>
|
|
148
|
-
<p class="text-
|
|
148
|
+
<p class="text-muted">
|
|
149
149
|
{{
|
|
150
150
|
restricted
|
|
151
151
|
? t('layout.workspaceMembers.accessMode.restrictedHint')
|
|
@@ -161,7 +161,7 @@ function memberLabel(userId: string, name?: string | null, email?: string | null
|
|
|
161
161
|
data-testid="workspace-restrict-toggle"
|
|
162
162
|
@update:model-value="setAccessMode"
|
|
163
163
|
/>
|
|
164
|
-
<span class="text-xs text-
|
|
164
|
+
<span class="text-xs text-toned">
|
|
165
165
|
{{ t('layout.workspaceMembers.accessMode.restrictToggle') }}
|
|
166
166
|
</span>
|
|
167
167
|
</label>
|
|
@@ -170,13 +170,15 @@ function memberLabel(userId: string, name?: string | null, email?: string | null
|
|
|
170
170
|
|
|
171
171
|
<!-- roster -->
|
|
172
172
|
<section>
|
|
173
|
-
<h3 class="mb-2 font-semibold text-
|
|
174
|
-
|
|
173
|
+
<h3 class="mb-2 font-semibold text-highlighted">
|
|
174
|
+
{{ t('layout.workspaceMembers.roster.title') }}
|
|
175
|
+
</h3>
|
|
176
|
+
<p v-if="!rosterReady" class="text-dimmed">{{ t('common.loading') }}</p>
|
|
175
177
|
<ul v-else class="space-y-1" data-testid="workspace-members-roster">
|
|
176
178
|
<li
|
|
177
179
|
v-for="m in members.members"
|
|
178
180
|
:key="m.userId"
|
|
179
|
-
class="flex items-center justify-between gap-2 rounded-md bg-
|
|
181
|
+
class="flex items-center justify-between gap-2 rounded-md bg-elevated/40 px-2 py-1"
|
|
180
182
|
data-testid="workspace-member-row"
|
|
181
183
|
:data-user-id="m.userId"
|
|
182
184
|
>
|
|
@@ -204,7 +206,7 @@ function memberLabel(userId: string, name?: string | null, email?: string | null
|
|
|
204
206
|
/>
|
|
205
207
|
</span>
|
|
206
208
|
</li>
|
|
207
|
-
<li v-if="members.members.length === 0" class="text-
|
|
209
|
+
<li v-if="members.members.length === 0" class="text-dimmed">
|
|
208
210
|
{{ t('layout.workspaceMembers.roster.empty') }}
|
|
209
211
|
</li>
|
|
210
212
|
</ul>
|
|
@@ -212,8 +214,10 @@ function memberLabel(userId: string, name?: string | null, email?: string | null
|
|
|
212
214
|
|
|
213
215
|
<!-- add member -->
|
|
214
216
|
<section>
|
|
215
|
-
<h3 class="mb-2 font-semibold text-
|
|
216
|
-
|
|
217
|
+
<h3 class="mb-2 font-semibold text-highlighted">
|
|
218
|
+
{{ t('layout.workspaceMembers.add.title') }}
|
|
219
|
+
</h3>
|
|
220
|
+
<p v-if="!accountId" class="text-dimmed">
|
|
217
221
|
{{ t('layout.workspaceMembers.add.noAccount') }}
|
|
218
222
|
</p>
|
|
219
223
|
<template v-else>
|
|
@@ -239,7 +243,7 @@ function memberLabel(userId: string, name?: string | null, email?: string | null
|
|
|
239
243
|
{{ t('layout.workspaceMembers.add.submit') }}
|
|
240
244
|
</UButton>
|
|
241
245
|
</form>
|
|
242
|
-
<p v-if="candidates.length === 0" class="mt-2 text-
|
|
246
|
+
<p v-if="candidates.length === 0" class="mt-2 text-dimmed">
|
|
243
247
|
{{ t('layout.workspaceMembers.add.allAdded') }}
|
|
244
248
|
</p>
|
|
245
249
|
</template>
|
|
@@ -160,7 +160,7 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey, true))
|
|
|
160
160
|
v-if="open"
|
|
161
161
|
ref="dialogRef"
|
|
162
162
|
tabindex="-1"
|
|
163
|
-
class="fixed inset-0 z-[60] flex flex-col bg-
|
|
163
|
+
class="fixed inset-0 z-[60] flex flex-col bg-app-950/95 backdrop-blur-sm focus:outline-none"
|
|
164
164
|
role="dialog"
|
|
165
165
|
aria-modal="true"
|
|
166
166
|
data-testid="artifact-lightbox"
|
|
@@ -172,27 +172,27 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey, true))
|
|
|
172
172
|
@click.self="close"
|
|
173
173
|
>
|
|
174
174
|
<!-- Toolbar -->
|
|
175
|
-
<div class="flex items-center gap-3 border-b border-
|
|
176
|
-
<span class="min-w-0 flex-1 truncate text-[13px] font-medium text-
|
|
175
|
+
<div class="flex items-center gap-3 border-b border-default/60 px-4 py-2.5">
|
|
176
|
+
<span class="min-w-0 flex-1 truncate text-[13px] font-medium text-default">
|
|
177
177
|
{{ current?.label ?? t('media.lightbox.fallbackTitle') }}
|
|
178
178
|
</span>
|
|
179
|
-
<span v-if="total > 1" class="shrink-0 text-[12px] tabular-nums text-
|
|
179
|
+
<span v-if="total > 1" class="shrink-0 text-[12px] tabular-nums text-muted">
|
|
180
180
|
{{ t('media.lightbox.counter', { current: index + 1, total }) }}
|
|
181
181
|
</span>
|
|
182
182
|
<div class="flex shrink-0 items-center gap-1">
|
|
183
183
|
<button
|
|
184
|
-
class="rounded-md p-1.5 text-
|
|
184
|
+
class="rounded-md p-1.5 text-muted hover:bg-elevated hover:text-default disabled:opacity-40"
|
|
185
185
|
:title="t('media.lightbox.zoomOut')"
|
|
186
186
|
:disabled="scale <= MIN_SCALE"
|
|
187
187
|
@click="zoomBy(1 / 1.25)"
|
|
188
188
|
>
|
|
189
189
|
<UIcon name="i-lucide-zoom-out" class="h-4 w-4" />
|
|
190
190
|
</button>
|
|
191
|
-
<span class="w-10 text-center text-[11px] tabular-nums text-
|
|
191
|
+
<span class="w-10 text-center text-[11px] tabular-nums text-dimmed">{{
|
|
192
192
|
n(scale, 'percent')
|
|
193
193
|
}}</span>
|
|
194
194
|
<button
|
|
195
|
-
class="rounded-md p-1.5 text-
|
|
195
|
+
class="rounded-md p-1.5 text-muted hover:bg-elevated hover:text-default disabled:opacity-40"
|
|
196
196
|
:title="t('media.lightbox.zoomIn')"
|
|
197
197
|
:disabled="scale >= MAX_SCALE"
|
|
198
198
|
@click="zoomBy(1.25)"
|
|
@@ -200,14 +200,14 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey, true))
|
|
|
200
200
|
<UIcon name="i-lucide-zoom-in" class="h-4 w-4" />
|
|
201
201
|
</button>
|
|
202
202
|
<button
|
|
203
|
-
class="rounded-md p-1.5 text-
|
|
203
|
+
class="rounded-md p-1.5 text-muted hover:bg-elevated hover:text-default"
|
|
204
204
|
:title="t('media.lightbox.reset')"
|
|
205
205
|
@click="resetView"
|
|
206
206
|
>
|
|
207
207
|
<UIcon name="i-lucide-maximize" class="h-4 w-4" />
|
|
208
208
|
</button>
|
|
209
209
|
<button
|
|
210
|
-
class="ms-1 rounded-md p-1.5 text-
|
|
210
|
+
class="ms-1 rounded-md p-1.5 text-muted hover:bg-elevated hover:text-default"
|
|
211
211
|
:title="t('media.lightbox.close')"
|
|
212
212
|
@click="close"
|
|
213
213
|
>
|
|
@@ -224,7 +224,7 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey, true))
|
|
|
224
224
|
>
|
|
225
225
|
<button
|
|
226
226
|
v-if="total > 1"
|
|
227
|
-
class="absolute start-3 top-1/2 z-10 -translate-y-1/2 rounded-full bg-
|
|
227
|
+
class="absolute start-3 top-1/2 z-10 -translate-y-1/2 rounded-full bg-default/80 p-2 text-toned hover:bg-elevated hover:text-highlighted"
|
|
228
228
|
:title="t('media.lightbox.prev')"
|
|
229
229
|
@click="go(-1)"
|
|
230
230
|
>
|
|
@@ -248,7 +248,7 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey, true))
|
|
|
248
248
|
@pointerup="onPointerUp"
|
|
249
249
|
@pointercancel="onPointerUp"
|
|
250
250
|
/>
|
|
251
|
-
<div v-else class="flex flex-col items-center gap-2 text-
|
|
251
|
+
<div v-else class="flex flex-col items-center gap-2 text-dimmed">
|
|
252
252
|
<UIcon
|
|
253
253
|
:name="state === 'error' ? 'i-lucide-image-off' : 'i-lucide-loader'"
|
|
254
254
|
class="h-8 w-8"
|
|
@@ -259,7 +259,7 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey, true))
|
|
|
259
259
|
</p>
|
|
260
260
|
<button
|
|
261
261
|
v-if="state === 'error' && current"
|
|
262
|
-
class="text-[12px] text-
|
|
262
|
+
class="text-[12px] text-app-warning-300 hover:underline"
|
|
263
263
|
@click="props.blobs.retry(current.artifactId)"
|
|
264
264
|
>
|
|
265
265
|
{{ t('common.retry') }}
|
|
@@ -268,7 +268,7 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey, true))
|
|
|
268
268
|
|
|
269
269
|
<button
|
|
270
270
|
v-if="total > 1"
|
|
271
|
-
class="absolute end-3 top-1/2 z-10 -translate-y-1/2 rounded-full bg-
|
|
271
|
+
class="absolute end-3 top-1/2 z-10 -translate-y-1/2 rounded-full bg-default/80 p-2 text-toned hover:bg-elevated hover:text-highlighted"
|
|
272
272
|
:title="t('media.lightbox.next')"
|
|
273
273
|
@click="go(1)"
|
|
274
274
|
>
|
|
@@ -82,6 +82,13 @@ function onSwipeUp() {
|
|
|
82
82
|
|
|
83
83
|
// --- diff canvas ---
|
|
84
84
|
const diffCanvas = ref<HTMLCanvasElement | null>(null)
|
|
85
|
+
// A fixed black backing, opting out of the theme on purpose. The CSS background does not take part
|
|
86
|
+
// in the canvas `difference` composite (that runs on the bitmap); it shows through wherever the
|
|
87
|
+
// bitmap is transparent, before the first draw and in any transparent region of the diff. Black
|
|
88
|
+
// there reads as "no difference", the same zero the difference composite produces, in either colour
|
|
89
|
+
// mode, so no mode-following token fits. Bound as a const so the guard's `fixed-colour-ok:` marker
|
|
90
|
+
// stays on the class string; the inline-template form gets reflowed off its own line by oxfmt.
|
|
91
|
+
const DIFF_CANVAS_CLASS = 'w-full rounded border border-default bg-black' // fixed-colour-ok: diff canvas backdrop
|
|
85
92
|
const CAP = 2000
|
|
86
93
|
// Bumped on every renderDiff entry so a render whose async work (image decode) is overtaken
|
|
87
94
|
// by a newer mode/image change bails out instead of drawing stale pixels onto the canvas.
|
|
@@ -148,19 +155,19 @@ function onRefInput(e: Event) {
|
|
|
148
155
|
</script>
|
|
149
156
|
|
|
150
157
|
<template>
|
|
151
|
-
<div class="rounded-lg border border-
|
|
158
|
+
<div class="rounded-lg border border-default bg-default/60 p-3">
|
|
152
159
|
<div class="mb-2 flex items-center justify-between gap-2">
|
|
153
|
-
<h3 class="min-w-0 truncate text-[12px] font-semibold text-
|
|
160
|
+
<h3 class="min-w-0 truncate text-[12px] font-semibold text-default">{{ view }}</h3>
|
|
154
161
|
<!-- Mode switch -->
|
|
155
162
|
<div
|
|
156
163
|
v-if="MODES.length > 1"
|
|
157
|
-
class="flex items-center gap-0.5 rounded-md border border-
|
|
164
|
+
class="flex items-center gap-0.5 rounded-md border border-default bg-app-950/60 p-0.5"
|
|
158
165
|
>
|
|
159
166
|
<button
|
|
160
167
|
v-for="m in MODES"
|
|
161
168
|
:key="m.id"
|
|
162
|
-
class="rounded px-1.5 py-1 text-
|
|
163
|
-
:class="mode === m.id ? 'bg-
|
|
169
|
+
class="rounded px-1.5 py-1 text-muted hover:text-default"
|
|
170
|
+
:class="mode === m.id ? 'bg-elevated text-app-100' : ''"
|
|
164
171
|
:title="m.label"
|
|
165
172
|
@click="mode = m.id"
|
|
166
173
|
>
|
|
@@ -172,12 +179,12 @@ function onRefInput(e: Event) {
|
|
|
172
179
|
<!-- SIDE BY SIDE -->
|
|
173
180
|
<div v-if="mode === 'side-by-side'" class="grid grid-cols-2 gap-3">
|
|
174
181
|
<figure class="space-y-1">
|
|
175
|
-
<figcaption class="text-[10px] uppercase tracking-wide text-
|
|
182
|
+
<figcaption class="text-[10px] uppercase tracking-wide text-dimmed">
|
|
176
183
|
{{ t('media.compare.actual') }}
|
|
177
184
|
</figcaption>
|
|
178
185
|
<button
|
|
179
186
|
v-if="actualUrl"
|
|
180
|
-
class="block w-full overflow-hidden rounded border border-
|
|
187
|
+
class="block w-full overflow-hidden rounded border border-default hover:border-app-600"
|
|
181
188
|
@click="actualId && emit('expand', actualId)"
|
|
182
189
|
>
|
|
183
190
|
<img
|
|
@@ -188,7 +195,7 @@ function onRefInput(e: Event) {
|
|
|
188
195
|
</button>
|
|
189
196
|
<div
|
|
190
197
|
v-else
|
|
191
|
-
class="flex h-32 items-center justify-center rounded border border-dashed border-
|
|
198
|
+
class="flex h-32 items-center justify-center rounded border border-dashed border-muted text-[11px] text-app-600"
|
|
192
199
|
>
|
|
193
200
|
{{
|
|
194
201
|
props.blobs.statusFor(actualId) === 'error'
|
|
@@ -201,15 +208,15 @@ function onRefInput(e: Event) {
|
|
|
201
208
|
</figure>
|
|
202
209
|
|
|
203
210
|
<figure class="space-y-1">
|
|
204
|
-
<figcaption class="text-[10px] uppercase tracking-wide text-
|
|
211
|
+
<figcaption class="text-[10px] uppercase tracking-wide text-dimmed">
|
|
205
212
|
{{ t('media.compare.reference') }}
|
|
206
|
-
<span v-if="referenceOrigin === 'design'" class="text-
|
|
213
|
+
<span v-if="referenceOrigin === 'design'" class="text-app-warning-300/80">
|
|
207
214
|
{{ t('media.compare.fromLinkedDesign') }}
|
|
208
215
|
</span>
|
|
209
216
|
</figcaption>
|
|
210
217
|
<button
|
|
211
218
|
v-if="refUrl"
|
|
212
|
-
class="group relative block w-full overflow-hidden rounded border border-
|
|
219
|
+
class="group relative block w-full overflow-hidden rounded border border-default hover:border-app-600"
|
|
213
220
|
@click="referenceId && emit('expand', referenceId)"
|
|
214
221
|
>
|
|
215
222
|
<img
|
|
@@ -218,7 +225,7 @@ function onRefInput(e: Event) {
|
|
|
218
225
|
class="w-full cursor-zoom-in"
|
|
219
226
|
/>
|
|
220
227
|
<span
|
|
221
|
-
class="absolute bottom-1 end-1 rounded bg-
|
|
228
|
+
class="absolute bottom-1 end-1 rounded bg-app-950/80 px-1.5 py-0.5 text-[10px] text-toned opacity-0 group-hover:opacity-100"
|
|
222
229
|
@click.stop="refInput?.click()"
|
|
223
230
|
>
|
|
224
231
|
{{ t('media.compare.replace') }}
|
|
@@ -230,8 +237,8 @@ function onRefInput(e: Event) {
|
|
|
230
237
|
class="flex h-32 cursor-pointer flex-col items-center justify-center gap-1 rounded border border-dashed text-[11px] transition"
|
|
231
238
|
:class="
|
|
232
239
|
dragOver
|
|
233
|
-
? 'border-
|
|
234
|
-
: 'border-
|
|
240
|
+
? 'border-app-warning-500 bg-app-warning-500/5 text-app-warning-300'
|
|
241
|
+
: 'border-muted text-app-600 hover:border-app-500 hover:text-muted'
|
|
235
242
|
"
|
|
236
243
|
@click="refInput?.click()"
|
|
237
244
|
@dragover.prevent="dragOver = true"
|
|
@@ -246,7 +253,7 @@ function onRefInput(e: Event) {
|
|
|
246
253
|
|
|
247
254
|
<!-- OVERLAY (onion-skin) -->
|
|
248
255
|
<div v-else-if="mode === 'overlay'" class="space-y-2">
|
|
249
|
-
<div class="relative w-full overflow-hidden rounded border border-
|
|
256
|
+
<div class="relative w-full overflow-hidden rounded border border-default">
|
|
250
257
|
<img :src="refUrl" :alt="t('media.compare.referenceAlt', { view })" class="w-full" />
|
|
251
258
|
<!-- object-contain so a differing aspect ratio onion-skins undistorted over the reference. -->
|
|
252
259
|
<img
|
|
@@ -256,14 +263,14 @@ function onRefInput(e: Event) {
|
|
|
256
263
|
:style="{ opacity: overlayOpacity / 100 }"
|
|
257
264
|
/>
|
|
258
265
|
</div>
|
|
259
|
-
<div class="flex items-center gap-2 text-[10px] uppercase tracking-wide text-
|
|
266
|
+
<div class="flex items-center gap-2 text-[10px] uppercase tracking-wide text-dimmed">
|
|
260
267
|
<span>{{ t('media.compare.reference') }}</span>
|
|
261
268
|
<input
|
|
262
269
|
v-model.number="overlayOpacity"
|
|
263
270
|
type="range"
|
|
264
271
|
min="0"
|
|
265
272
|
max="100"
|
|
266
|
-
class="flex-1 accent-
|
|
273
|
+
class="flex-1 accent-app-warning-500"
|
|
267
274
|
/>
|
|
268
275
|
<span>{{ t('media.compare.actual') }}</span>
|
|
269
276
|
</div>
|
|
@@ -273,7 +280,7 @@ function onRefInput(e: Event) {
|
|
|
273
280
|
<div
|
|
274
281
|
v-else-if="mode === 'swipe'"
|
|
275
282
|
ref="swipeBox"
|
|
276
|
-
class="relative w-full cursor-ew-resize select-none overflow-hidden rounded border border-
|
|
283
|
+
class="relative w-full cursor-ew-resize select-none overflow-hidden rounded border border-default"
|
|
277
284
|
@pointerdown="onSwipeDown"
|
|
278
285
|
@pointermove="moveSwipe"
|
|
279
286
|
@pointerup="onSwipeUp"
|
|
@@ -297,27 +304,27 @@ function onRefInput(e: Event) {
|
|
|
297
304
|
`clientX - rect.left`), so the handle and the corner labels stay PHYSICAL too.
|
|
298
305
|
Logical (`start-`/`end-`) here would flip the labels under RTL while the image
|
|
299
306
|
regions stayed put, mislabeling actual vs reference. -->
|
|
300
|
-
<div class="absolute inset-y-0 w-0.5 bg-
|
|
307
|
+
<div class="absolute inset-y-0 w-0.5 bg-app-warning-400" :style="{ left: `${splitPct}%` }">
|
|
301
308
|
<span
|
|
302
|
-
class="absolute top-1/2 left-1/2 flex h-6 w-6 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full bg-
|
|
309
|
+
class="absolute top-1/2 left-1/2 flex h-6 w-6 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full bg-app-warning-400 text-app-950 shadow"
|
|
303
310
|
>
|
|
304
311
|
<UIcon name="i-lucide-move-horizontal" class="h-3.5 w-3.5" />
|
|
305
312
|
</span>
|
|
306
313
|
</div>
|
|
307
314
|
<span
|
|
308
|
-
class="absolute left-1 top-1 rounded bg-
|
|
315
|
+
class="absolute left-1 top-1 rounded bg-app-950/70 px-1 text-[9px] uppercase text-toned"
|
|
309
316
|
>{{ t('media.compare.actual') }}</span
|
|
310
317
|
>
|
|
311
318
|
<span
|
|
312
|
-
class="absolute right-1 top-1 rounded bg-
|
|
319
|
+
class="absolute right-1 top-1 rounded bg-app-950/70 px-1 text-[9px] uppercase text-toned"
|
|
313
320
|
>{{ t('media.compare.reference') }}</span
|
|
314
321
|
>
|
|
315
322
|
</div>
|
|
316
323
|
|
|
317
324
|
<!-- DIFF (canvas) -->
|
|
318
325
|
<div v-else-if="mode === 'diff'" class="space-y-1">
|
|
319
|
-
<canvas ref="diffCanvas" class="
|
|
320
|
-
<p class="text-[10px] text-
|
|
326
|
+
<canvas ref="diffCanvas" :class="DIFF_CANVAS_CLASS" />
|
|
327
|
+
<p class="text-[10px] text-dimmed">{{ t('media.compare.diffHint') }}</p>
|
|
321
328
|
</div>
|
|
322
329
|
|
|
323
330
|
<!-- Hidden file input shared by replace/drop zone -->
|
|
@@ -88,7 +88,7 @@ function pick(effort: ReviewEffort) {
|
|
|
88
88
|
<div data-testid="merge-effort-chips" class="mt-2">
|
|
89
89
|
<div class="flex items-center gap-1.5">
|
|
90
90
|
<span
|
|
91
|
-
class="text-[10px] uppercase tracking-wide text-
|
|
91
|
+
class="text-[10px] uppercase tracking-wide text-dimmed"
|
|
92
92
|
:title="t('merge.effort.promptHint')"
|
|
93
93
|
>
|
|
94
94
|
{{ t('merge.effort.prompt') }}
|
|
@@ -119,7 +119,7 @@ function pick(effort: ReviewEffort) {
|
|
|
119
119
|
{{ chip.label }}
|
|
120
120
|
</UButton>
|
|
121
121
|
</div>
|
|
122
|
-
<p v-if="history" data-testid="merge-effort-history" class="mt-1 text-[10px] text-
|
|
122
|
+
<p v-if="history" data-testid="merge-effort-history" class="mt-1 text-[10px] text-dimmed">
|
|
123
123
|
{{ history }}
|
|
124
124
|
</p>
|
|
125
125
|
</div>
|
|
@@ -147,18 +147,18 @@ function resetToDefaults() {
|
|
|
147
147
|
</template>
|
|
148
148
|
<template #body>
|
|
149
149
|
<div class="space-y-4">
|
|
150
|
-
<p class="text-xs text-
|
|
150
|
+
<p class="text-xs text-muted">{{ t('notificationSettings.panel.intro') }}</p>
|
|
151
151
|
|
|
152
152
|
<div
|
|
153
153
|
v-if="notifications.settingsStatus === 'unavailable'"
|
|
154
|
-
class="rounded-lg border border-
|
|
154
|
+
class="rounded-lg border border-muted bg-elevated/40 p-3 text-xs text-muted"
|
|
155
155
|
>
|
|
156
156
|
{{ t('notificationSettings.unavailable') }}
|
|
157
157
|
</div>
|
|
158
158
|
|
|
159
159
|
<div
|
|
160
160
|
v-else-if="notifications.settingsStatus === 'failed'"
|
|
161
|
-
class="space-y-3 rounded-lg border border-
|
|
161
|
+
class="space-y-3 rounded-lg border border-app-warning-700/60 bg-app-warning-950/30 p-3 text-xs text-app-warning-200"
|
|
162
162
|
>
|
|
163
163
|
<p>{{ t('notificationSettings.loadFailed') }}</p>
|
|
164
164
|
<UButton color="neutral" variant="soft" size="xs" icon="i-lucide-rotate-cw" @click="load">
|
|
@@ -168,15 +168,13 @@ function resetToDefaults() {
|
|
|
168
168
|
|
|
169
169
|
<div
|
|
170
170
|
v-else-if="!editable"
|
|
171
|
-
class="rounded-lg border border-
|
|
171
|
+
class="rounded-lg border border-muted bg-elevated/40 p-3 text-xs text-muted"
|
|
172
172
|
>
|
|
173
173
|
{{ t('common.loading') }}
|
|
174
174
|
</div>
|
|
175
175
|
|
|
176
176
|
<template v-else>
|
|
177
|
-
<div
|
|
178
|
-
class="flex items-center gap-3 px-2 text-[10px] uppercase tracking-wide text-slate-500"
|
|
179
|
-
>
|
|
177
|
+
<div class="flex items-center gap-3 px-2 text-[10px] uppercase tracking-wide text-dimmed">
|
|
180
178
|
<span class="flex-1">{{ t('notificationSettings.column.event') }}</span>
|
|
181
179
|
<span class="w-16 text-center">{{ t('notificationSettings.column.inApp') }}</span>
|
|
182
180
|
<span class="w-16 text-center">{{ t('notificationSettings.column.email') }}</span>
|
|
@@ -186,9 +184,9 @@ function resetToDefaults() {
|
|
|
186
184
|
<div
|
|
187
185
|
v-for="type in TYPES"
|
|
188
186
|
:key="type"
|
|
189
|
-
class="flex items-center gap-3 rounded-lg border border-
|
|
187
|
+
class="flex items-center gap-3 rounded-lg border border-muted bg-elevated/40 p-2"
|
|
190
188
|
>
|
|
191
|
-
<span class="flex-1 text-sm text-
|
|
189
|
+
<span class="flex-1 text-sm text-toned">
|
|
192
190
|
{{ t(`notificationSettings.type.${type}`) }}
|
|
193
191
|
</span>
|
|
194
192
|
<div class="flex w-16 justify-center">
|
|
@@ -200,9 +198,13 @@ function resetToDefaults() {
|
|
|
200
198
|
</div>
|
|
201
199
|
</div>
|
|
202
200
|
|
|
203
|
-
<p class="text-[11px] text-
|
|
204
|
-
|
|
205
|
-
|
|
201
|
+
<p class="text-[11px] text-dimmed">
|
|
202
|
+
{{ t('notificationSettings.panel.inAppNote') }}
|
|
203
|
+
</p>
|
|
204
|
+
<p class="text-[11px] text-dimmed">
|
|
205
|
+
{{ t('notificationSettings.panel.emailNote') }}
|
|
206
|
+
</p>
|
|
207
|
+
<p class="text-[11px] text-dimmed">
|
|
206
208
|
{{ t('notificationSettings.panel.otherChannelsNote') }}
|
|
207
209
|
<UButton
|
|
208
210
|
v-if="slack.available"
|