@cat-factory/app 0.307.1 → 0.309.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/app/assets/css/main.css +22 -0
- package/app/assets/css/prose.css +4 -4
- package/app/assets/css/type.css +24 -0
- package/app/components/assistant/AssistantModal.vue +3 -2
- package/app/components/auth/UserMenu.vue +1 -1
- package/app/components/binaryCandidates/BinaryCandidatesWindow.vue +15 -15
- package/app/components/binaryOutput/BinaryOutputReport.vue +10 -14
- package/app/components/binaryOutput/StoredAssetView.vue +5 -5
- package/app/components/board/AddTaskModal.vue +16 -14
- package/app/components/board/AgentFailureCard.vue +9 -9
- package/app/components/board/AgentFailureHistory.vue +1 -1
- package/app/components/board/CreateInitiativeModal.vue +2 -2
- package/app/components/board/FailureDetail.vue +1 -1
- package/app/components/board/FailureHistoryList.vue +5 -5
- package/app/components/board/RecurringPipelineModal.vue +12 -11
- package/app/components/board/ReviewFrictionDialog.vue +4 -3
- package/app/components/board/StepExecutionHistory.vue +8 -8
- package/app/components/board/nodes/AgentChip.vue +1 -1
- package/app/components/board/nodes/BlockNode.vue +8 -9
- package/app/components/board/nodes/EpicNode.vue +4 -4
- package/app/components/board/nodes/FrameSwimlanes.vue +4 -7
- package/app/components/board/nodes/InitiativeCard.vue +4 -4
- package/app/components/board/nodes/LaneGroup.vue +3 -5
- package/app/components/board/nodes/TaskCard.vue +8 -8
- package/app/components/board/nodes/TaskLane.vue +3 -3
- package/app/components/board/nodes/TaskPipelineMini.vue +13 -12
- package/app/components/bootstrap/AdoptionReviewModal.vue +7 -6
- package/app/components/bootstrap/BootstrapModal.vue +11 -10
- package/app/components/bootstrap/BootstrapRunSteps.vue +1 -1
- package/app/components/brainstorm/BrainstormWindow.vue +8 -7
- package/app/components/bugFishing/BugFishingWindow.vue +37 -36
- package/app/components/clarity/ClarityReviewWindow.vue +8 -7
- package/app/components/common/AsyncViewError.vue +1 -1
- package/app/components/common/ClarificationItem.vue +6 -6
- package/app/components/common/DescriptorFields.vue +1 -1
- package/app/components/common/EmptyState.vue +1 -1
- package/app/components/common/InterviewGateNotice.vue +4 -4
- package/app/components/common/MarkdownProse.vue +8 -2
- package/app/components/common/SectionLabel.vue +38 -0
- package/app/components/consensus/ConsensusSessionWindow.vue +10 -9
- package/app/components/context/ContextAttachmentFields.vue +9 -8
- package/app/components/docs/DocInterviewWindow.vue +10 -9
- package/app/components/documents/ContextDocumentPicker.vue +10 -12
- package/app/components/documents/DocumentImportModal.vue +3 -2
- package/app/components/documents/DocumentSourceConnectModal.vue +2 -2
- package/app/components/documents/DocumentSyncState.vue +1 -1
- package/app/components/documents/DocumentTemplatesModal.vue +5 -4
- package/app/components/documents/RepoContextDocPicker.vue +3 -6
- package/app/components/documents/StartFromDesignModal.vue +4 -4
- package/app/components/documents/TaskContextDocs.vue +1 -1
- package/app/components/environments/EnvSetupStepper.vue +3 -3
- package/app/components/environments/EnvironmentStatusPanel.vue +11 -10
- package/app/components/environments/steps/EnvPreflightStep.vue +8 -8
- package/app/components/environments/steps/EnvReviewStep.vue +23 -22
- package/app/components/environments/steps/EnvSaveStep.vue +5 -5
- package/app/components/focus/BlockFocusView.vue +11 -10
- package/app/components/followUp/FollowUpWindow.vue +10 -10
- package/app/components/forkDecision/ForkDecisionWindow.vue +23 -26
- package/app/components/foundational/FoundationalContractSummary.vue +2 -2
- package/app/components/foundational/FoundationalServiceCatalogList.vue +3 -3
- package/app/components/foundational/FoundationalServiceRegistry.vue +3 -3
- package/app/components/foundational/FoundationalSuppressions.vue +2 -2
- package/app/components/fragments/FragmentLibraryManager.vue +3 -3
- package/app/components/fragments/FragmentSelector.vue +10 -11
- package/app/components/gates/GateFailingCheckList.vue +3 -3
- package/app/components/gates/GateResultView.vue +39 -38
- package/app/components/github/AddServiceFromRepoModal.vue +5 -4
- package/app/components/github/BranchProtectionPreflight.vue +5 -5
- package/app/components/github/GitHubConnect.vue +5 -3
- package/app/components/github/GitHubPanel.vue +14 -13
- package/app/components/github/RepoTreeBrowser.vue +1 -1
- package/app/components/humanTest/HumanTestWindow.vue +18 -17
- package/app/components/initiative/InitiativePlanNotice.vue +3 -3
- package/app/components/initiative/InitiativePlanReview.vue +19 -21
- package/app/components/initiative/InitiativePlanningWindow.vue +5 -5
- package/app/components/initiative/InitiativeTrackerWindow.vue +54 -53
- package/app/components/judge/JudgeResultView.vue +24 -25
- package/app/components/kaizen/KaizenPanel.vue +4 -4
- package/app/components/kaizen/KaizenStepStatus.vue +7 -6
- package/app/components/layout/AccountAuditLog.vue +1 -1
- package/app/components/layout/AccountDeploymentSettings.vue +10 -10
- 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 +7 -7
- package/app/components/layout/AccountPlatformAlertSettings.vue +8 -8
- package/app/components/layout/AccountRiskPolicySettings.vue +2 -2
- package/app/components/layout/AccountRunCredentialSettings.vue +3 -3
- package/app/components/layout/AccountSkillSettings.vue +1 -1
- package/app/components/layout/AccountTeamSettings.vue +4 -0
- package/app/components/layout/AiProvidersBanner.vue +1 -1
- package/app/components/layout/AppearanceSwitcher.vue +1 -1
- package/app/components/layout/BoardSwitcher.vue +3 -2
- package/app/components/layout/BoardToolbar.vue +6 -2
- package/app/components/layout/CommandBar.vue +4 -2
- package/app/components/layout/DefaultTestEnvBanner.vue +2 -2
- package/app/components/layout/IntegrationsHub.vue +4 -3
- package/app/components/layout/LanguageSwitcher.vue +1 -1
- package/app/components/layout/ModelProvidersHub.vue +6 -4
- package/app/components/layout/NotificationsInbox.vue +8 -7
- package/app/components/layout/PersonalSetupModal.vue +5 -3
- package/app/components/layout/RolePrompt.vue +1 -1
- package/app/components/layout/SideBar.vue +3 -5
- package/app/components/layout/SpendWarningBanner.vue +3 -3
- package/app/components/layout/TranslationWarningBanner.vue +1 -1
- package/app/components/layout/UiModeSwitcher.vue +7 -6
- package/app/components/layout/UiRoleSwitcher.vue +2 -2
- package/app/components/media/ArtifactLightbox.vue +6 -6
- package/app/components/media/ImageCompare.vue +16 -16
- package/app/components/merge/MergeEffortChips.vue +4 -6
- package/app/components/notifications/NotificationSettingsPanel.vue +6 -5
- package/app/components/observability/OutcomeFilterChips.vue +1 -1
- package/app/components/observability/RunFailureSummary.vue +14 -17
- package/app/components/observability/StepMetricsBar.vue +9 -8
- package/app/components/observability/StepModelActivity.vue +4 -3
- package/app/components/observability/ToolCallList.vue +15 -18
- package/app/components/outcome/OutcomeSummaryWindow.vue +43 -42
- package/app/components/palettes/AgentPalette.vue +7 -5
- package/app/components/palettes/AgentTierSelect.vue +1 -1
- package/app/components/palettes/PipelinePurposeSelect.vue +2 -1
- package/app/components/panels/AgentStepDetail.vue +27 -30
- package/app/components/panels/AttemptEntryHeader.vue +2 -2
- package/app/components/panels/DecisionModal.vue +1 -1
- package/app/components/panels/GenericStructuredResultView.vue +6 -5
- package/app/components/panels/InspectorPanel.vue +15 -13
- package/app/components/panels/MergerResultView.vue +10 -9
- package/app/components/panels/ObservabilityPanel.vue +66 -76
- package/app/components/panels/OperatorDashboardPanel.vue +27 -26
- package/app/components/panels/ReportsPanel.vue +26 -25
- package/app/components/panels/ReportsSpendBreakdown.vue +2 -2
- package/app/components/panels/ResultWindowShell.vue +19 -18
- package/app/components/panels/RunDetailLoadState.vue +1 -1
- package/app/components/panels/StepContainerStatus.vue +8 -7
- package/app/components/panels/StepDelegatedStatus.vue +13 -12
- package/app/components/panels/StepEffortReport.vue +12 -17
- package/app/components/panels/StepFragmentAdherence.vue +9 -10
- package/app/components/panels/StepMetadataCard.vue +41 -43
- package/app/components/panels/StepReproductionReport.vue +18 -20
- package/app/components/panels/StepRunMeta.vue +27 -26
- package/app/components/panels/StepTestReport.vue +16 -15
- package/app/components/panels/StepToolServers.vue +7 -8
- package/app/components/panels/StepValidationReport.vue +5 -5
- package/app/components/panels/inspector/ContainerSummary.vue +4 -4
- package/app/components/panels/inspector/DocReferenceRepos.vue +5 -4
- package/app/components/panels/inspector/EnvProbeReport.vue +16 -13
- package/app/components/panels/inspector/EpicChildren.vue +8 -7
- package/app/components/panels/inspector/FrontendBindingsResolved.vue +5 -4
- package/app/components/panels/inspector/FrontendConfig.vue +26 -34
- package/app/components/panels/inspector/InitiativeInspector.vue +3 -3
- package/app/components/panels/inspector/InspectorSection.vue +7 -4
- package/app/components/panels/inspector/RecurringScheduleSettings.vue +9 -8
- 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 +9 -13
- package/app/components/panels/inspector/ServiceTestConfig.vue +41 -45
- package/app/components/panels/inspector/ServiceTestSecrets.vue +3 -3
- package/app/components/panels/inspector/ServiceTestingContext.vue +2 -2
- package/app/components/panels/inspector/ServiceValidationConfig.vue +2 -2
- package/app/components/panels/inspector/TaskAgentConfig.vue +2 -2
- package/app/components/panels/inspector/TaskAprioriBranches.vue +6 -5
- package/app/components/panels/inspector/TaskDependencies.vue +1 -1
- package/app/components/panels/inspector/TaskEstimateBadge.vue +3 -7
- package/app/components/panels/inspector/TaskExecution.vue +13 -12
- package/app/components/panels/inspector/TaskRunSettings.vue +35 -38
- package/app/components/panels/inspector/TaskStructure.vue +5 -4
- package/app/components/pipeline/AgentPromptEditor.vue +15 -14
- package/app/components/pipeline/BinaryOutputStepPicker.vue +42 -52
- package/app/components/pipeline/EstimateThresholdFields.vue +2 -2
- package/app/components/pipeline/GateConfigFields.vue +6 -6
- package/app/components/pipeline/IterationCapPrompt.vue +1 -1
- package/app/components/pipeline/PipelineBuilder.vue +28 -27
- package/app/components/pipeline/PipelineHealthModal.vue +7 -7
- package/app/components/pipeline/PipelinePicker.vue +3 -3
- package/app/components/pipeline/PipelinePreview.vue +6 -7
- package/app/components/pipeline/PipelineProgress.vue +23 -24
- package/app/components/prReview/PrReviewWindow.vue +42 -41
- package/app/components/providers/AiPresetMismatchDialog.vue +4 -3
- package/app/components/providers/AiProviderOnboardingModal.vue +2 -2
- package/app/components/providers/ApiKeysSection.vue +7 -6
- package/app/components/providers/PersonalSubscriptionSection.vue +4 -3
- package/app/components/providers/VendorCredentialsModal.vue +5 -4
- package/app/components/provisioning/ProvisioningLogsDrawer.vue +10 -9
- package/app/components/ralph/RalphLoopResultView.vue +25 -26
- package/app/components/requirements/RequirementsReviewWindow.vue +13 -12
- package/app/components/riskPolicy/RiskPolicyPicker.vue +5 -5
- package/app/components/riskPolicy/RiskPolicyPreview.vue +16 -15
- package/app/components/sandbox/SandboxPanel.vue +21 -20
- package/app/components/settings/ApiTokensPanel.vue +1 -1
- package/app/components/settings/BudgetSettings.vue +18 -17
- package/app/components/settings/CapabilityCredentialsPanel.vue +5 -5
- package/app/components/settings/CloudflareHandlerSection.vue +16 -16
- package/app/components/settings/ComposeEnvironmentSetupSection.vue +14 -12
- package/app/components/settings/ConnectionTestVerdict.vue +1 -1
- package/app/components/settings/ConsensusGroupsSection.vue +21 -20
- package/app/components/settings/CustomManifestTypeEditor.vue +8 -7
- package/app/components/settings/DefaultProvisionTypeSection.vue +5 -5
- package/app/components/settings/InfraHandlersConfigurator.vue +14 -15
- package/app/components/settings/InfrastructureBackendPicker.vue +2 -2
- package/app/components/settings/IssueTrackerPanel.vue +9 -15
- package/app/components/settings/KubernetesEngineForm.vue +9 -8
- package/app/components/settings/KubernetesEnvironmentForm.vue +4 -3
- package/app/components/settings/LocalContainerPoolSettings.vue +2 -2
- package/app/components/settings/LocalModelEndpointsPanel.vue +10 -9
- package/app/components/settings/MergeClassRulesEditor.vue +6 -5
- package/app/components/settings/MergeRolePolicyEditor.vue +13 -12
- package/app/components/settings/ModelConfigurationPanel.vue +8 -11
- package/app/components/settings/ModelPresetHealthModal.vue +3 -3
- package/app/components/settings/ObservabilityConnectionPanel.vue +1 -1
- package/app/components/settings/OpenRouterCatalogPanel.vue +6 -5
- package/app/components/settings/PackageRegistriesPanel.vue +4 -4
- package/app/components/settings/ProviderConnectionTab.vue +5 -4
- package/app/components/settings/ProviderManifestEditor.vue +9 -8
- package/app/components/settings/ProviderPreferenceEditor.vue +8 -7
- package/app/components/settings/RiskPolicyCreateForm.vue +40 -26
- package/app/components/settings/RiskPolicyEditorRow.vue +18 -17
- package/app/components/settings/RiskPolicyHealthModal.vue +3 -3
- package/app/components/settings/RiskPolicyPanel.vue +11 -13
- package/app/components/settings/ServiceFragmentDefaultsPanel.vue +5 -4
- package/app/components/settings/SharedStacksPanel.vue +5 -5
- package/app/components/settings/TaskSourceCard.vue +2 -2
- package/app/components/settings/TaskTypeSuppressionsPanel.vue +4 -4
- package/app/components/settings/ToolServerChecklist.vue +22 -22
- package/app/components/settings/UsageSettings.vue +13 -13
- package/app/components/settings/UserSecretsSection.vue +4 -3
- package/app/components/settings/WorkspaceMetadataSettings.vue +6 -5
- package/app/components/settings/WorkspaceSettingsPanel.vue +72 -58
- package/app/components/skills/ReviewSkillQueue.vue +8 -7
- package/app/components/skills/SkillLibraryManager.vue +2 -2
- package/app/components/slack/SlackPanel.vue +8 -7
- package/app/components/spec/ServiceSpecWindow.vue +15 -16
- package/app/components/tasks/BugHuntModal.vue +1 -1
- package/app/components/tasks/ContextIssuePicker.vue +4 -6
- package/app/components/tasks/TaskContextIssues.vue +1 -1
- package/app/components/tasks/TaskImportModal.vue +3 -2
- package/app/components/tasks/TaskSourceConnectModal.vue +5 -5
- package/app/components/testing/TestReportWindow.vue +54 -53
- package/app/components/tutorial/TutorialNudge.vue +3 -2
- package/app/components/tutorial/TutorialOverlay.vue +3 -2
- package/app/components/vcs/GitLabConnect.vue +1 -1
- package/app/components/visualConfirm/VisualConfirmationWindow.vue +23 -25
- package/app/composables/usePipelineErrorToast.ts +2 -0
- package/app/utils/catalog.ts +8 -0
- package/app/utils/theme/builtins.ts +7 -1
- package/i18n/locales/de.json +6 -3
- package/i18n/locales/en.json +6 -3
- package/i18n/locales/es.json +6 -3
- package/i18n/locales/fr.json +6 -3
- package/i18n/locales/he.json +6 -3
- package/i18n/locales/it.json +6 -3
- package/i18n/locales/ja.json +6 -3
- package/i18n/locales/pl.json +6 -3
- package/i18n/locales/tr.json +6 -3
- package/i18n/locales/uk.json +6 -3
- package/package.json +2 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { DropdownMenuItem } from '@nuxt/ui'
|
|
3
3
|
import type { CloudProvider } from '~/types/domain'
|
|
4
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
4
5
|
|
|
5
6
|
// Account + board switching. Picks the active account (personal / org) and the
|
|
6
7
|
// active board within it, and manages boards (new / rename / delete). The account
|
|
@@ -265,9 +266,9 @@ async function submitPrompt() {
|
|
|
265
266
|
:name="accounts.activeAccount?.type === 'org' ? 'i-lucide-users' : 'i-lucide-user'"
|
|
266
267
|
class="h-3.5 w-3.5 shrink-0 text-muted"
|
|
267
268
|
/>
|
|
268
|
-
<span class="truncate
|
|
269
|
+
<SectionLabel as="span" class="truncate">
|
|
269
270
|
{{ accounts.activeAccount?.name ?? t('layout.boardSwitcher.accountFallback') }}
|
|
270
|
-
</
|
|
271
|
+
</SectionLabel>
|
|
271
272
|
<UIcon name="i-lucide-chevrons-up-down" class="ms-auto h-3.5 w-3.5 shrink-0 text-app-600" />
|
|
272
273
|
</button>
|
|
273
274
|
</UDropdownMenu>
|
|
@@ -153,14 +153,18 @@ const decisionItems = computed(() =>
|
|
|
153
153
|
drops on narrow viewports) so the zoom level is never a mystery. -->
|
|
154
154
|
<button
|
|
155
155
|
type="button"
|
|
156
|
-
class="w-16 rounded text-center text-xs tabular-nums text-toned hover:bg-elevated focus-visible:ring-2 focus-visible:ring-app-400/60 sm:w-20"
|
|
156
|
+
class="w-16 rounded-sm text-center text-xs tabular-nums text-toned hover:bg-elevated focus-visible:ring-2 focus-visible:ring-app-400/60 sm:w-20"
|
|
157
157
|
:title="t('board.toolbar.resetZoom')"
|
|
158
158
|
:aria-label="t('board.toolbar.resetZoom')"
|
|
159
159
|
data-testid="board-zoom-reset"
|
|
160
160
|
@click="resetZoom()"
|
|
161
161
|
>
|
|
162
162
|
{{ zoomPct }}%
|
|
163
|
-
|
|
163
|
+
<!-- The zoom band this readout is currently in, under the percentage: a second VALUE
|
|
164
|
+
annotating the first, not a heading over what follows, so it is not a
|
|
165
|
+
`common/SectionLabel.vue`. It stays a step smaller and unweighted so it does not compete
|
|
166
|
+
with the percentage inside a `w-20` button. -->
|
|
167
|
+
<span class="hidden text-3xs uppercase tracking-wide text-dimmed sm:block">{{
|
|
164
168
|
lodLabel
|
|
165
169
|
}}</span>
|
|
166
170
|
</button>
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
// from the add-task flow.) Commands are assembled from the live stores so only
|
|
7
7
|
// available actions (connected integrations, etc.) show.
|
|
8
8
|
|
|
9
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
10
|
+
|
|
9
11
|
interface Command {
|
|
10
12
|
id: string
|
|
11
13
|
label: string
|
|
@@ -276,9 +278,9 @@ function indexOf(cmd: Command) {
|
|
|
276
278
|
</p>
|
|
277
279
|
|
|
278
280
|
<div v-for="group in groups" :key="group.name" class="mb-1">
|
|
279
|
-
<p class="px-2 pb-1 pt-2
|
|
281
|
+
<SectionLabel as="p" class="px-2 pb-1 pt-2">
|
|
280
282
|
{{ group.name }}
|
|
281
|
-
</
|
|
283
|
+
</SectionLabel>
|
|
282
284
|
<button
|
|
283
285
|
v-for="cmd in group.items"
|
|
284
286
|
:key="cmd.id"
|
|
@@ -74,7 +74,7 @@ function openConfig(event: MouseEvent) {
|
|
|
74
74
|
@click="ui.dismissDefaultProvision()"
|
|
75
75
|
/>
|
|
76
76
|
</div>
|
|
77
|
-
<p class="mt-1 text-
|
|
77
|
+
<p class="mt-1 text-sm text-app-info-200/90">
|
|
78
78
|
{{ t('layout.defaultTestEnvBanner.body') }}
|
|
79
79
|
</p>
|
|
80
80
|
<div class="mt-3 flex flex-wrap items-center gap-x-3 gap-y-2">
|
|
@@ -92,7 +92,7 @@ function openConfig(event: MouseEvent) {
|
|
|
92
92
|
<!-- The URL itself, shown so it can be read and copied, not just clicked. -->
|
|
93
93
|
<a
|
|
94
94
|
:href="configUrl"
|
|
95
|
-
class="min-w-0 truncate font-mono text-
|
|
95
|
+
class="min-w-0 truncate font-mono text-2xs text-app-info-300/80 underline decoration-dotted underline-offset-2 hover:text-app-info-200"
|
|
96
96
|
data-testid="default-test-env-url"
|
|
97
97
|
@click="openConfig"
|
|
98
98
|
>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { showOverrideField } from '~/utils/uiMode'
|
|
3
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
3
4
|
|
|
4
5
|
// The Integrations hub: a single modal that lists the OPTIONAL external systems the WORKSPACE
|
|
5
6
|
// can enable or link in — the ones that feed a run its context (source control, documents,
|
|
@@ -422,9 +423,9 @@ const filteredGroups = computed<IntegrationGroup[]>(() => {
|
|
|
422
423
|
</p>
|
|
423
424
|
|
|
424
425
|
<section v-for="group in filteredGroups" :key="group.title">
|
|
425
|
-
<h3 class="mb-2 px-1
|
|
426
|
+
<SectionLabel as="h3" class="mb-2 px-1">
|
|
426
427
|
{{ group.title }}
|
|
427
|
-
</
|
|
428
|
+
</SectionLabel>
|
|
428
429
|
<div class="space-y-1.5">
|
|
429
430
|
<button
|
|
430
431
|
v-for="item in group.items"
|
|
@@ -443,7 +444,7 @@ const filteredGroups = computed<IntegrationGroup[]>(() => {
|
|
|
443
444
|
<UBadge v-else-if="item.attention" color="warning" variant="subtle" size="sm">
|
|
444
445
|
{{ item.attentionLabel || t('layout.integrationsHub.status.needsAttention') }}
|
|
445
446
|
</UBadge>
|
|
446
|
-
<span v-else class="text-
|
|
447
|
+
<span v-else class="text-2xs text-dimmed">{{
|
|
447
448
|
t('layout.integrationsHub.status.notConnected')
|
|
448
449
|
}}</span>
|
|
449
450
|
<UBadge
|
|
@@ -50,7 +50,7 @@ const items = computed<DropdownMenuItem[][]>(() => [
|
|
|
50
50
|
>
|
|
51
51
|
<UIcon name="i-lucide-languages" class="h-4 w-4 shrink-0 text-muted" />
|
|
52
52
|
<div v-if="!collapsed" class="min-w-0 flex-1">
|
|
53
|
-
<div class="truncate text-
|
|
53
|
+
<div class="truncate text-2xs uppercase tracking-wide text-muted">
|
|
54
54
|
{{ t('language.switcher') }}
|
|
55
55
|
</div>
|
|
56
56
|
<div class="truncate text-xs font-medium text-highlighted">{{ current }}</div>
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
// `ui.openFromModelProviders(...)`, so opening one closes this hub and gives that panel a
|
|
13
13
|
// "Back to Model providers" control (IntegrationBackTitle). Layout mirrors the Integrations
|
|
14
14
|
// hub row-for-row so the two read as siblings.
|
|
15
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
16
|
+
|
|
15
17
|
const { t } = useI18n()
|
|
16
18
|
const ui = useUiStore()
|
|
17
19
|
const apiKeys = useApiKeysStore()
|
|
@@ -200,9 +202,9 @@ const filteredGroups = computed<ProviderGroup[]>(() => {
|
|
|
200
202
|
</p>
|
|
201
203
|
|
|
202
204
|
<section v-for="group in filteredGroups" :key="group.title">
|
|
203
|
-
<h3 class="mb-2 px-1
|
|
205
|
+
<SectionLabel as="h3" class="mb-2 px-1">
|
|
204
206
|
{{ group.title }}
|
|
205
|
-
</
|
|
207
|
+
</SectionLabel>
|
|
206
208
|
<div class="space-y-1.5">
|
|
207
209
|
<button
|
|
208
210
|
v-for="item in group.items"
|
|
@@ -219,7 +221,7 @@ const filteredGroups = computed<ProviderGroup[]>(() => {
|
|
|
219
221
|
<UBadge v-if="item.connected" color="success" variant="subtle" size="sm">
|
|
220
222
|
{{ item.status || t('layout.modelProvidersHub.status.connected') }}
|
|
221
223
|
</UBadge>
|
|
222
|
-
<span v-else class="text-
|
|
224
|
+
<span v-else class="text-2xs text-dimmed">{{
|
|
223
225
|
t('layout.modelProvidersHub.status.notConnected')
|
|
224
226
|
}}</span>
|
|
225
227
|
<UBadge
|
|
@@ -239,7 +241,7 @@ const filteredGroups = computed<ProviderGroup[]>(() => {
|
|
|
239
241
|
/>
|
|
240
242
|
</button>
|
|
241
243
|
</div>
|
|
242
|
-
<p v-if="group.note" class="mt-1.5 px-1 text-
|
|
244
|
+
<p v-if="group.note" class="mt-1.5 px-1 text-2xs text-dimmed">{{ group.note }}</p>
|
|
243
245
|
</section>
|
|
244
246
|
</div>
|
|
245
247
|
</template>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { Notification } from '~/types/domain'
|
|
3
3
|
import type { ReviewEffort } from '~/types/merge'
|
|
4
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
4
5
|
|
|
5
6
|
// The board's notification inbox: a bell with an open-count badge that opens a
|
|
6
7
|
// panel of human-actionable items (a PR awaiting a merge decision, a completed
|
|
@@ -406,9 +407,9 @@ function revealDecision(n: Notification) {
|
|
|
406
407
|
|
|
407
408
|
<template #content>
|
|
408
409
|
<div class="max-h-[28rem] w-[min(24rem,92vw)] overflow-y-auto p-2">
|
|
409
|
-
<
|
|
410
|
+
<SectionLabel class="px-2 py-1">
|
|
410
411
|
{{ t('layout.notifications.heading') }}
|
|
411
|
-
</
|
|
412
|
+
</SectionLabel>
|
|
412
413
|
<div
|
|
413
414
|
v-for="n in notifications.open"
|
|
414
415
|
:key="n.id"
|
|
@@ -437,18 +438,18 @@ function revealDecision(n: Notification) {
|
|
|
437
438
|
</button>
|
|
438
439
|
<span
|
|
439
440
|
v-if="isUrgent(n)"
|
|
440
|
-
class="shrink-0 rounded bg-app-error-500/20 px-1.5 py-0.5 text-
|
|
441
|
+
class="shrink-0 rounded-sm bg-app-error-500/20 px-1.5 py-0.5 text-3xs font-semibold uppercase tracking-wide text-app-error-400"
|
|
441
442
|
>
|
|
442
443
|
{{ t('layout.notifications.overdue') }}
|
|
443
444
|
</span>
|
|
444
445
|
</div>
|
|
445
|
-
<p class="mt-0.5 text-
|
|
446
|
+
<p class="mt-0.5 text-2xs leading-snug text-muted">{{ n.body }}</p>
|
|
446
447
|
<a
|
|
447
448
|
v-if="n.payload?.prUrl"
|
|
448
449
|
:href="n.payload.prUrl"
|
|
449
450
|
target="_blank"
|
|
450
451
|
rel="noopener"
|
|
451
|
-
class="mt-1 inline-flex items-center gap-1 text-
|
|
452
|
+
class="mt-1 inline-flex items-center gap-1 text-2xs text-app-info-400 hover:underline"
|
|
452
453
|
>
|
|
453
454
|
<UIcon name="i-lucide-external-link" class="h-3 w-3" />
|
|
454
455
|
{{ t('layout.notifications.openPr') }}
|
|
@@ -467,7 +468,7 @@ function revealDecision(n: Notification) {
|
|
|
467
468
|
v-for="run in failingRuns(n)"
|
|
468
469
|
:key="run.executionId"
|
|
469
470
|
:type="canOpenFailingRun(run) ? 'button' : undefined"
|
|
470
|
-
class="flex items-center gap-1 text-start text-
|
|
471
|
+
class="flex items-center gap-1 text-start text-2xs"
|
|
471
472
|
:class="
|
|
472
473
|
canOpenFailingRun(run)
|
|
473
474
|
? 'text-app-info-400 hover:underline'
|
|
@@ -486,7 +487,7 @@ function revealDecision(n: Notification) {
|
|
|
486
487
|
})
|
|
487
488
|
}}</span>
|
|
488
489
|
</component>
|
|
489
|
-
<span v-if="failingRunsOmitted(n) > 0" class="text-
|
|
490
|
+
<span v-if="failingRunsOmitted(n) > 0" class="text-2xs text-dimmed">
|
|
490
491
|
{{ t('layout.notifications.failingRunsMore', { count: failingRunsOmitted(n) }) }}
|
|
491
492
|
</span>
|
|
492
493
|
</div>
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
// previously sat, confusingly, among the workspace-wide integrations. Each row reuses the
|
|
6
6
|
// existing per-panel handlers via `ui.openFromPersonal(...)`, so opening one closes this
|
|
7
7
|
// hub, reveals that panel, and gives it a "Back to My setup" control (IntegrationBackTitle).
|
|
8
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
9
|
+
|
|
8
10
|
const { t } = useI18n()
|
|
9
11
|
const ui = useUiStore()
|
|
10
12
|
const userSecrets = useUserSecretsStore()
|
|
@@ -117,9 +119,9 @@ const groups = computed<PersonalGroup[]>(() => {
|
|
|
117
119
|
</p>
|
|
118
120
|
|
|
119
121
|
<section v-for="group in groups" :key="group.title">
|
|
120
|
-
<h3 class="mb-2 px-1
|
|
122
|
+
<SectionLabel as="h3" class="mb-2 px-1">
|
|
121
123
|
{{ group.title }}
|
|
122
|
-
</
|
|
124
|
+
</SectionLabel>
|
|
123
125
|
<div class="space-y-1.5">
|
|
124
126
|
<button
|
|
125
127
|
v-for="item in group.items"
|
|
@@ -135,7 +137,7 @@ const groups = computed<PersonalGroup[]>(() => {
|
|
|
135
137
|
<UBadge v-if="item.connected" color="success" variant="subtle" size="sm">
|
|
136
138
|
{{ item.status || t('layout.personalSetup.connected') }}
|
|
137
139
|
</UBadge>
|
|
138
|
-
<span v-else class="text-
|
|
140
|
+
<span v-else class="text-2xs text-dimmed">
|
|
139
141
|
{{ t('layout.personalSetup.notConnected') }}
|
|
140
142
|
</span>
|
|
141
143
|
</div>
|
|
@@ -56,7 +56,7 @@ function pick(role: UiRole) {
|
|
|
56
56
|
</div>
|
|
57
57
|
<!-- The choice is not a commitment, and saying so is what makes the narrowed role
|
|
58
58
|
pickable: it is one dropdown at the top of the sidebar to leave again. -->
|
|
59
|
-
<p class="text-
|
|
59
|
+
<p class="text-2xs leading-snug text-dimmed">{{ t('uiRole.prompt.change') }}</p>
|
|
60
60
|
</div>
|
|
61
61
|
</template>
|
|
62
62
|
<template #footer>
|
|
@@ -20,6 +20,7 @@ import UiRoleSwitcher from '~/components/layout/UiRoleSwitcher.vue'
|
|
|
20
20
|
import UserMenu from '~/components/auth/UserMenu.vue'
|
|
21
21
|
import { useViewport } from '~/composables/useViewport'
|
|
22
22
|
import type { NavContribution } from '~/modular/nav-contributions'
|
|
23
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
23
24
|
|
|
24
25
|
const { t } = useI18n()
|
|
25
26
|
|
|
@@ -248,12 +249,9 @@ watch(
|
|
|
248
249
|
<template v-for="section in sidebarGroups" :key="section.group">
|
|
249
250
|
<USeparator />
|
|
250
251
|
<section>
|
|
251
|
-
<h2
|
|
252
|
-
v-if="!railed"
|
|
253
|
-
class="mb-2 px-1 text-[11px] font-semibold uppercase tracking-wide text-muted"
|
|
254
|
-
>
|
|
252
|
+
<SectionLabel v-if="!railed" as="h2" class="mb-2 px-1">
|
|
255
253
|
{{ t(section.labelKey) }}
|
|
256
|
-
</
|
|
254
|
+
</SectionLabel>
|
|
257
255
|
<div class="space-y-1.5">
|
|
258
256
|
<UButton
|
|
259
257
|
v-for="item in section.items"
|
|
@@ -54,7 +54,7 @@ async function resume() {
|
|
|
54
54
|
|
|
55
55
|
<dl class="mt-4 grid grid-cols-2 gap-3 sm:grid-cols-3">
|
|
56
56
|
<div class="rounded-lg bg-app-error-900/50 px-3 py-2">
|
|
57
|
-
<dt class="text-
|
|
57
|
+
<dt class="text-2xs uppercase tracking-wide text-app-error-300/80">
|
|
58
58
|
{{ t('layout.spendWarningBanner.spent') }}
|
|
59
59
|
</dt>
|
|
60
60
|
<dd class="text-base font-semibold tabular-nums text-app-error-50">
|
|
@@ -62,7 +62,7 @@ async function resume() {
|
|
|
62
62
|
</dd>
|
|
63
63
|
</div>
|
|
64
64
|
<div class="rounded-lg bg-app-error-900/50 px-3 py-2">
|
|
65
|
-
<dt class="text-
|
|
65
|
+
<dt class="text-2xs uppercase tracking-wide text-app-error-300/80">
|
|
66
66
|
{{ t('layout.spendWarningBanner.budget') }}
|
|
67
67
|
</dt>
|
|
68
68
|
<dd class="text-base font-semibold tabular-nums text-app-error-50">
|
|
@@ -70,7 +70,7 @@ async function resume() {
|
|
|
70
70
|
</dd>
|
|
71
71
|
</div>
|
|
72
72
|
<div class="rounded-lg bg-app-error-900/50 px-3 py-2">
|
|
73
|
-
<dt class="text-
|
|
73
|
+
<dt class="text-2xs uppercase tracking-wide text-app-error-300/80">
|
|
74
74
|
{{ t('layout.spendWarningBanner.tokens') }}
|
|
75
75
|
</dt>
|
|
76
76
|
<dd class="text-base font-semibold tabular-nums text-app-error-50">{{ tokens }}</dd>
|
|
@@ -31,7 +31,7 @@ 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-app-warning-500/40 bg-app-warning-950/95 px-4 py-2 text-
|
|
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-sm text-app-warning-100 shadow-lg backdrop-blur"
|
|
35
35
|
>
|
|
36
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">
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
3
|
import { UI_MODES, type UiMode } from '~/utils/uiMode'
|
|
4
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
4
5
|
|
|
5
6
|
// Interface-tier picker, shown at the TOP of the sidebar under the board switcher. Basic mode
|
|
6
7
|
// hides the power-user destinations and the less-used run options; advanced shows everything.
|
|
@@ -55,9 +56,9 @@ const pinnedTitle = computed(
|
|
|
55
56
|
>
|
|
56
57
|
<UIcon :name="icon" class="h-4 w-4 shrink-0 text-dimmed" />
|
|
57
58
|
<div v-if="!collapsed" class="min-w-0 flex-1">
|
|
58
|
-
<
|
|
59
|
+
<SectionLabel class="truncate">
|
|
59
60
|
{{ t('uiMode.switcher') }}
|
|
60
|
-
</
|
|
61
|
+
</SectionLabel>
|
|
61
62
|
<div class="truncate text-xs font-medium text-toned">{{ currentLabel }}</div>
|
|
62
63
|
</div>
|
|
63
64
|
<UIcon v-if="!collapsed" name="i-lucide-lock" class="h-3.5 w-3.5 shrink-0 text-app-600" />
|
|
@@ -76,15 +77,15 @@ const pinnedTitle = computed(
|
|
|
76
77
|
@click="uiMode.toggleMode()"
|
|
77
78
|
>
|
|
78
79
|
<UIcon :name="icon" class="h-4 w-4 shrink-0 text-primary" />
|
|
79
|
-
<span class="w-full truncate text-center text-
|
|
80
|
+
<span class="w-full truncate text-center text-3xs font-medium uppercase text-toned">
|
|
80
81
|
{{ currentLabel }}
|
|
81
82
|
</span>
|
|
82
83
|
</button>
|
|
83
84
|
|
|
84
85
|
<div v-else data-testid="ui-mode-switcher" class="w-full">
|
|
85
|
-
<
|
|
86
|
+
<SectionLabel class="mb-1 px-1">
|
|
86
87
|
{{ t('uiMode.switcher') }}
|
|
87
|
-
</
|
|
88
|
+
</SectionLabel>
|
|
88
89
|
<div
|
|
89
90
|
role="group"
|
|
90
91
|
:aria-label="t('uiMode.switcher')"
|
|
@@ -111,7 +112,7 @@ const pinnedTitle = computed(
|
|
|
111
112
|
|
|
112
113
|
<!-- The one-line "what this tier gives you", so the choice is self-explanatory. Dropped in
|
|
113
114
|
the collapsed rail, where the tooltip above carries the mode instead. -->
|
|
114
|
-
<p v-if="!collapsed" class="px-1 text-
|
|
115
|
+
<p v-if="!collapsed" class="px-1 text-3xs leading-snug text-dimmed">
|
|
115
116
|
{{ t(MODE_HINTS[uiMode.mode]) }}
|
|
116
117
|
</p>
|
|
117
118
|
</template>
|
|
@@ -47,7 +47,7 @@ const items = computed(() =>
|
|
|
47
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
49
|
<UIcon :name="current.icon" class="h-4 w-4 shrink-0 text-primary" />
|
|
50
|
-
<span class="w-full truncate text-center text-
|
|
50
|
+
<span class="w-full truncate text-center text-3xs font-medium uppercase text-toned">
|
|
51
51
|
{{ currentLabel }}
|
|
52
52
|
</span>
|
|
53
53
|
</button>
|
|
@@ -62,7 +62,7 @@ const items = computed(() =>
|
|
|
62
62
|
>
|
|
63
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-
|
|
65
|
+
<div class="truncate text-2xs uppercase tracking-wide text-muted">
|
|
66
66
|
{{ t('uiRole.switcher') }}
|
|
67
67
|
</div>
|
|
68
68
|
<div class="truncate text-xs font-medium text-default">{{ currentLabel }}</div>
|
|
@@ -173,10 +173,10 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey, true))
|
|
|
173
173
|
>
|
|
174
174
|
<!-- Toolbar -->
|
|
175
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-
|
|
176
|
+
<span class="min-w-0 flex-1 truncate text-sm 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-
|
|
179
|
+
<span v-if="total > 1" class="shrink-0 text-xs 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">
|
|
@@ -188,7 +188,7 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey, true))
|
|
|
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-
|
|
191
|
+
<span class="w-10 text-center text-2xs tabular-nums text-dimmed">{{
|
|
192
192
|
n(scale, 'percent')
|
|
193
193
|
}}</span>
|
|
194
194
|
<button
|
|
@@ -236,7 +236,7 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey, true))
|
|
|
236
236
|
:src="url"
|
|
237
237
|
:alt="current?.alt ?? ''"
|
|
238
238
|
draggable="false"
|
|
239
|
-
class="max-h-full max-w-full select-none rounded shadow-2xl"
|
|
239
|
+
class="max-h-full max-w-full select-none rounded-sm shadow-2xl"
|
|
240
240
|
:class="[
|
|
241
241
|
scale > 1 ? (dragging ? 'cursor-grabbing' : 'cursor-grab') : 'cursor-zoom-in',
|
|
242
242
|
dragging ? '' : 'transition-transform duration-100',
|
|
@@ -254,12 +254,12 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey, true))
|
|
|
254
254
|
class="h-8 w-8"
|
|
255
255
|
:class="state === 'error' ? '' : 'animate-spin'"
|
|
256
256
|
/>
|
|
257
|
-
<p class="text-
|
|
257
|
+
<p class="text-xs">
|
|
258
258
|
{{ state === 'error' ? t('media.lightbox.failed') : t('media.lightbox.loading') }}
|
|
259
259
|
</p>
|
|
260
260
|
<button
|
|
261
261
|
v-if="state === 'error' && current"
|
|
262
|
-
class="text-
|
|
262
|
+
class="text-xs text-app-warning-300 hover:underline"
|
|
263
263
|
@click="props.blobs.retry(current.artifactId)"
|
|
264
264
|
>
|
|
265
265
|
{{ t('common.retry') }}
|
|
@@ -88,7 +88,7 @@ const diffCanvas = ref<HTMLCanvasElement | null>(null)
|
|
|
88
88
|
// there reads as "no difference", the same zero the difference composite produces, in either colour
|
|
89
89
|
// mode, so no mode-following token fits. Bound as a const so the guard's `fixed-colour-ok:` marker
|
|
90
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
|
|
91
|
+
const DIFF_CANVAS_CLASS = 'w-full rounded-sm border border-default bg-black' // fixed-colour-ok: diff canvas backdrop
|
|
92
92
|
const CAP = 2000
|
|
93
93
|
// Bumped on every renderDiff entry so a render whose async work (image decode) is overtaken
|
|
94
94
|
// by a newer mode/image change bails out instead of drawing stale pixels onto the canvas.
|
|
@@ -157,7 +157,7 @@ function onRefInput(e: Event) {
|
|
|
157
157
|
<template>
|
|
158
158
|
<div class="rounded-lg border border-default bg-default/60 p-3">
|
|
159
159
|
<div class="mb-2 flex items-center justify-between gap-2">
|
|
160
|
-
<h3 class="min-w-0 truncate text-
|
|
160
|
+
<h3 class="min-w-0 truncate text-xs font-semibold text-default">{{ view }}</h3>
|
|
161
161
|
<!-- Mode switch -->
|
|
162
162
|
<div
|
|
163
163
|
v-if="MODES.length > 1"
|
|
@@ -166,7 +166,7 @@ function onRefInput(e: Event) {
|
|
|
166
166
|
<button
|
|
167
167
|
v-for="m in MODES"
|
|
168
168
|
:key="m.id"
|
|
169
|
-
class="rounded px-1.5 py-1 text-muted hover:text-default"
|
|
169
|
+
class="rounded-sm px-1.5 py-1 text-muted hover:text-default"
|
|
170
170
|
:class="mode === m.id ? 'bg-elevated text-app-100' : ''"
|
|
171
171
|
:title="m.label"
|
|
172
172
|
@click="mode = m.id"
|
|
@@ -179,12 +179,12 @@ function onRefInput(e: Event) {
|
|
|
179
179
|
<!-- SIDE BY SIDE -->
|
|
180
180
|
<div v-if="mode === 'side-by-side'" class="grid grid-cols-2 gap-3">
|
|
181
181
|
<figure class="space-y-1">
|
|
182
|
-
<figcaption class="text-
|
|
182
|
+
<figcaption class="text-3xs uppercase tracking-wide text-dimmed">
|
|
183
183
|
{{ t('media.compare.actual') }}
|
|
184
184
|
</figcaption>
|
|
185
185
|
<button
|
|
186
186
|
v-if="actualUrl"
|
|
187
|
-
class="block w-full overflow-hidden rounded border border-default hover:border-app-600"
|
|
187
|
+
class="block w-full overflow-hidden rounded-sm border border-default hover:border-app-600"
|
|
188
188
|
@click="actualId && emit('expand', actualId)"
|
|
189
189
|
>
|
|
190
190
|
<img
|
|
@@ -195,7 +195,7 @@ function onRefInput(e: Event) {
|
|
|
195
195
|
</button>
|
|
196
196
|
<div
|
|
197
197
|
v-else
|
|
198
|
-
class="flex h-32 items-center justify-center rounded border border-dashed border-muted text-
|
|
198
|
+
class="flex h-32 items-center justify-center rounded-sm border border-dashed border-muted text-2xs text-app-600"
|
|
199
199
|
>
|
|
200
200
|
{{
|
|
201
201
|
props.blobs.statusFor(actualId) === 'error'
|
|
@@ -208,7 +208,7 @@ function onRefInput(e: Event) {
|
|
|
208
208
|
</figure>
|
|
209
209
|
|
|
210
210
|
<figure class="space-y-1">
|
|
211
|
-
<figcaption class="text-
|
|
211
|
+
<figcaption class="text-3xs uppercase tracking-wide text-dimmed">
|
|
212
212
|
{{ t('media.compare.reference') }}
|
|
213
213
|
<span v-if="referenceOrigin === 'design'" class="text-app-warning-300/80">
|
|
214
214
|
{{ t('media.compare.fromLinkedDesign') }}
|
|
@@ -216,7 +216,7 @@ function onRefInput(e: Event) {
|
|
|
216
216
|
</figcaption>
|
|
217
217
|
<button
|
|
218
218
|
v-if="refUrl"
|
|
219
|
-
class="group relative block w-full overflow-hidden rounded border border-default hover:border-app-600"
|
|
219
|
+
class="group relative block w-full overflow-hidden rounded-sm border border-default hover:border-app-600"
|
|
220
220
|
@click="referenceId && emit('expand', referenceId)"
|
|
221
221
|
>
|
|
222
222
|
<img
|
|
@@ -225,7 +225,7 @@ function onRefInput(e: Event) {
|
|
|
225
225
|
class="w-full cursor-zoom-in"
|
|
226
226
|
/>
|
|
227
227
|
<span
|
|
228
|
-
class="absolute bottom-1 end-1 rounded bg-app-950/80 px-1.5 py-0.5 text-
|
|
228
|
+
class="absolute bottom-1 end-1 rounded-sm bg-app-950/80 px-1.5 py-0.5 text-3xs text-toned opacity-0 group-hover:opacity-100"
|
|
229
229
|
@click.stop="refInput?.click()"
|
|
230
230
|
>
|
|
231
231
|
{{ t('media.compare.replace') }}
|
|
@@ -234,7 +234,7 @@ function onRefInput(e: Event) {
|
|
|
234
234
|
<!-- Drop zone when no reference yet -->
|
|
235
235
|
<div
|
|
236
236
|
v-else
|
|
237
|
-
class="flex h-32 cursor-pointer flex-col items-center justify-center gap-1 rounded border border-dashed text-
|
|
237
|
+
class="flex h-32 cursor-pointer flex-col items-center justify-center gap-1 rounded-sm border border-dashed text-2xs transition"
|
|
238
238
|
:class="
|
|
239
239
|
dragOver
|
|
240
240
|
? 'border-app-warning-500 bg-app-warning-500/5 text-app-warning-300'
|
|
@@ -253,7 +253,7 @@ function onRefInput(e: Event) {
|
|
|
253
253
|
|
|
254
254
|
<!-- OVERLAY (onion-skin) -->
|
|
255
255
|
<div v-else-if="mode === 'overlay'" class="space-y-2">
|
|
256
|
-
<div class="relative w-full overflow-hidden rounded border border-default">
|
|
256
|
+
<div class="relative w-full overflow-hidden rounded-sm border border-default">
|
|
257
257
|
<img :src="refUrl" :alt="t('media.compare.referenceAlt', { view })" class="w-full" />
|
|
258
258
|
<!-- object-contain so a differing aspect ratio onion-skins undistorted over the reference. -->
|
|
259
259
|
<img
|
|
@@ -263,7 +263,7 @@ function onRefInput(e: Event) {
|
|
|
263
263
|
:style="{ opacity: overlayOpacity / 100 }"
|
|
264
264
|
/>
|
|
265
265
|
</div>
|
|
266
|
-
<div class="flex items-center gap-2 text-
|
|
266
|
+
<div class="flex items-center gap-2 text-2xs uppercase tracking-wide text-muted">
|
|
267
267
|
<span>{{ t('media.compare.reference') }}</span>
|
|
268
268
|
<input
|
|
269
269
|
v-model.number="overlayOpacity"
|
|
@@ -280,7 +280,7 @@ function onRefInput(e: Event) {
|
|
|
280
280
|
<div
|
|
281
281
|
v-else-if="mode === 'swipe'"
|
|
282
282
|
ref="swipeBox"
|
|
283
|
-
class="relative w-full cursor-ew-resize select-none overflow-hidden rounded border border-default"
|
|
283
|
+
class="relative w-full cursor-ew-resize select-none overflow-hidden rounded-sm border border-default"
|
|
284
284
|
@pointerdown="onSwipeDown"
|
|
285
285
|
@pointermove="moveSwipe"
|
|
286
286
|
@pointerup="onSwipeUp"
|
|
@@ -312,11 +312,11 @@ function onRefInput(e: Event) {
|
|
|
312
312
|
</span>
|
|
313
313
|
</div>
|
|
314
314
|
<span
|
|
315
|
-
class="absolute left-1 top-1 rounded bg-app-950/70 px-1 text-
|
|
315
|
+
class="absolute left-1 top-1 rounded-sm bg-app-950/70 px-1 text-3xs uppercase text-toned"
|
|
316
316
|
>{{ t('media.compare.actual') }}</span
|
|
317
317
|
>
|
|
318
318
|
<span
|
|
319
|
-
class="absolute right-1 top-1 rounded bg-app-950/70 px-1 text-
|
|
319
|
+
class="absolute right-1 top-1 rounded-sm bg-app-950/70 px-1 text-3xs uppercase text-toned"
|
|
320
320
|
>{{ t('media.compare.reference') }}</span
|
|
321
321
|
>
|
|
322
322
|
</div>
|
|
@@ -324,7 +324,7 @@ function onRefInput(e: Event) {
|
|
|
324
324
|
<!-- DIFF (canvas) -->
|
|
325
325
|
<div v-else-if="mode === 'diff'" class="space-y-1">
|
|
326
326
|
<canvas ref="diffCanvas" :class="DIFF_CANVAS_CLASS" />
|
|
327
|
-
<p class="text-
|
|
327
|
+
<p class="text-3xs text-dimmed">{{ t('media.compare.diffHint') }}</p>
|
|
328
328
|
</div>
|
|
329
329
|
|
|
330
330
|
<!-- Hidden file input shared by replace/drop zone -->
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { computed } from 'vue'
|
|
11
11
|
import { REVIEW_EFFORTS } from '@cat-factory/contracts'
|
|
12
12
|
import type { ChangeClass, MergeClassRollup, ReviewEffort } from '~/types/merge'
|
|
13
|
+
import SectionLabel from '~/components/common/SectionLabel.vue'
|
|
13
14
|
|
|
14
15
|
const props = defineProps<{
|
|
15
16
|
/** The currently picked effort, or null for "not chosen". */
|
|
@@ -87,12 +88,9 @@ function pick(effort: ReviewEffort) {
|
|
|
87
88
|
<template>
|
|
88
89
|
<div data-testid="merge-effort-chips" class="mt-2">
|
|
89
90
|
<div class="flex items-center gap-1.5">
|
|
90
|
-
<span
|
|
91
|
-
class="text-[10px] uppercase tracking-wide text-dimmed"
|
|
92
|
-
:title="t('merge.effort.promptHint')"
|
|
93
|
-
>
|
|
91
|
+
<SectionLabel as="span" :title="t('merge.effort.promptHint')">
|
|
94
92
|
{{ t('merge.effort.prompt') }}
|
|
95
|
-
</
|
|
93
|
+
</SectionLabel>
|
|
96
94
|
<UBadge
|
|
97
95
|
v-if="classLabel"
|
|
98
96
|
data-testid="merge-effort-class"
|
|
@@ -119,7 +117,7 @@ function pick(effort: ReviewEffort) {
|
|
|
119
117
|
{{ chip.label }}
|
|
120
118
|
</UButton>
|
|
121
119
|
</div>
|
|
122
|
-
<p v-if="history" data-testid="merge-effort-history" class="mt-1 text-
|
|
120
|
+
<p v-if="history" data-testid="merge-effort-history" class="mt-1 text-3xs text-dimmed">
|
|
123
121
|
{{ history }}
|
|
124
122
|
</p>
|
|
125
123
|
</div>
|