This commit is contained in:
@@ -9,6 +9,7 @@ button, input, select, textarea { font: inherit; }
|
||||
button, a, input, select, textarea { &:focus-visible { outline: var(--border-strong) solid var(--color-focus); outline-offset: 3px; box-shadow: var(--glow-focus); } }
|
||||
button { cursor: pointer; }
|
||||
h1, h2, h3, h4 { margin: 0; font-family: var(--font-display); line-height: var(--leading-tight); }
|
||||
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; border: 0; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; }
|
||||
|
||||
.catalog-page, .detail-page, .showcase-page { min-height: 100vh; background: var(--color-background); }
|
||||
.catalog-header, .catalog-results { width: min(1120px, calc(100% - var(--space-8))); margin: 0 auto; }
|
||||
@@ -55,6 +56,7 @@ h1 { max-width: 760px; margin: var(--space-3) 0 var(--space-4); font-size: var(-
|
||||
.admin-workspace-grid form { display: grid; gap: var(--space-3); }
|
||||
.admin-wizard { display: grid; gap: var(--space-4); margin: var(--space-8) 0; }
|
||||
.admin-wizard__nav { display: flex; justify-content: space-between; gap: var(--space-3); }
|
||||
.admin-wizard > [role="region"]:focus { outline: var(--border-strong) solid var(--color-focus); outline-offset: 3px; }
|
||||
.admin-list { margin-top: var(--space-8); }
|
||||
.admin-list h2 { margin-bottom: var(--space-3); font-size: var(--text-xl); }
|
||||
.admin-list ul { display: grid; gap: var(--space-2); margin: 0; padding: 0; list-style: none; }
|
||||
|
||||
@@ -1,8 +1,27 @@
|
||||
import { expect, userEvent, within } from "@storybook/test";
|
||||
|
||||
import AdminHomePage from "./AdminHomePage.vue";
|
||||
|
||||
export default { title: "Pages/AdminHomePage", component: AdminHomePage };
|
||||
export const Overview = {};
|
||||
|
||||
export const WizardStepFocusManagement = {
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story:
|
||||
"Selecting a wizard stage moves focus to that stage's panel and announces the step change for assistive technology.",
|
||||
},
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await userEvent.click(canvas.getByRole("button", { name: /Sources/ }));
|
||||
await expect(canvas.getByRole("region", { name: "Sources step" })).toHaveFocus();
|
||||
await expect(await canvas.findByText("Step 2 of 6: Sources - Link markets")).toBeInTheDocument();
|
||||
},
|
||||
};
|
||||
|
||||
export const ProviderMappingWorkflow = {
|
||||
parameters: {
|
||||
docs: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import { computed, nextTick, onMounted, ref } from "vue";
|
||||
|
||||
import { useAuth } from "@/composables/useAuth.js";
|
||||
import InventoryWorkflowStepper from "@/components/molecules/InventoryWorkflowStepper.vue";
|
||||
@@ -428,10 +428,23 @@ async function overridePricing() {
|
||||
}
|
||||
}
|
||||
|
||||
const wizardPanels = {};
|
||||
function setWizardPanelRef(stepId, el) {
|
||||
wizardPanels[stepId] = el;
|
||||
}
|
||||
|
||||
const activeStepAnnouncement = computed(() => {
|
||||
const index = activeStepIndex.value;
|
||||
const step = workflowSteps.value[index];
|
||||
if (!step) return "";
|
||||
return `Step ${index + 1} of ${WIZARD_STEP_IDS.length}: ${step.label} - ${step.description}`;
|
||||
});
|
||||
|
||||
function goToStep(stepId) {
|
||||
if (!WIZARD_STEP_IDS.includes(stepId)) return;
|
||||
activeStepId.value = stepId;
|
||||
localStorage.setItem(WIZARD_STORAGE_KEY, stepId);
|
||||
nextTick(() => wizardPanels[stepId]?.focus());
|
||||
}
|
||||
|
||||
function goToNextStep() {
|
||||
@@ -586,10 +599,11 @@ onMounted(() => {
|
||||
</section>
|
||||
|
||||
<InventoryWorkflowStepper :steps="workflowSteps" :active-step-id="activeStepId" @select="goToStep" />
|
||||
<p class="visually-hidden" role="status">{{ activeStepAnnouncement }}</p>
|
||||
|
||||
<div class="admin-wizard">
|
||||
<ProductIdentityStep
|
||||
v-show="activeStepId === 'workflow-product'"
|
||||
<div v-show="activeStepId === 'workflow-product'" :ref="(el) => setWizardPanelRef('workflow-product', el)" tabindex="-1" role="region" aria-label="Product step">
|
||||
<ProductIdentityStep
|
||||
:product-name="productName"
|
||||
:category-id="categoryId"
|
||||
:categories="categories"
|
||||
@@ -598,8 +612,9 @@ onMounted(() => {
|
||||
@update:category-id="categoryId = $event"
|
||||
@submit="createProduct"
|
||||
/>
|
||||
<ProviderMappingStep
|
||||
v-show="activeStepId === 'workflow-mapping'"
|
||||
</div>
|
||||
<div v-show="activeStepId === 'workflow-mapping'" :ref="(el) => setWizardPanelRef('workflow-mapping', el)" tabindex="-1" role="region" aria-label="Sources step">
|
||||
<ProviderMappingStep
|
||||
:product-id="mappingProductId"
|
||||
:provider-id="mappingProviderId"
|
||||
:mapping-type="mappingType"
|
||||
@@ -615,8 +630,9 @@ onMounted(() => {
|
||||
@product-change="loadProviderMappings($event)"
|
||||
@submit="createProviderMapping"
|
||||
/>
|
||||
<InventoryCopyStep
|
||||
v-show="activeStepId === 'workflow-inventory'"
|
||||
</div>
|
||||
<div v-show="activeStepId === 'workflow-inventory'" :ref="(el) => setWizardPanelRef('workflow-inventory', el)" tabindex="-1" role="region" aria-label="Copy step">
|
||||
<InventoryCopyStep
|
||||
:product-id="inventoryProductId"
|
||||
:condition-id="conditionId"
|
||||
:products="products"
|
||||
@@ -626,13 +642,15 @@ onMounted(() => {
|
||||
@update:condition-id="conditionId = $event"
|
||||
@submit="createInventory"
|
||||
/>
|
||||
<InventoryImagesStep
|
||||
v-show="activeStepId === 'workflow-images'"
|
||||
</div>
|
||||
<div v-show="activeStepId === 'workflow-images'" :ref="(el) => setWizardPanelRef('workflow-images', el)" tabindex="-1" role="region" aria-label="Images step">
|
||||
<InventoryImagesStep
|
||||
:inventory="inventory"
|
||||
:missing-images="dashboard?.counts.missingImages ?? 0"
|
||||
/>
|
||||
<PricingReviewStep
|
||||
v-show="activeStepId === 'workflow-pricing'"
|
||||
</div>
|
||||
<div v-show="activeStepId === 'workflow-pricing'" :ref="(el) => setWizardPanelRef('workflow-pricing', el)" tabindex="-1" role="region" aria-label="Pricing step">
|
||||
<PricingReviewStep
|
||||
:inventory-item-id="pricingInventoryId"
|
||||
:provider="pricingProvider"
|
||||
:source-identifier="pricingSource"
|
||||
@@ -652,8 +670,9 @@ onMounted(() => {
|
||||
@refresh="refreshPricing"
|
||||
@override="overridePricing"
|
||||
/>
|
||||
<ReviewListStep
|
||||
v-show="activeStepId === 'workflow-listing'"
|
||||
</div>
|
||||
<div v-show="activeStepId === 'workflow-listing'" :ref="(el) => setWizardPanelRef('workflow-listing', el)" tabindex="-1" role="region" aria-label="List step">
|
||||
<ReviewListStep
|
||||
:inventory-item-id="listingInventoryId"
|
||||
:asking-price="askingPrice"
|
||||
:inventory="inventory"
|
||||
@@ -662,6 +681,7 @@ onMounted(() => {
|
||||
@update:asking-price="askingPrice = $event"
|
||||
@submit="createListing"
|
||||
/>
|
||||
</div>
|
||||
<div class="admin-wizard__nav">
|
||||
<button class="button button--secondary" type="button" :disabled="activeStepIndex === 0" @click="goToPreviousStep">Back</button>
|
||||
<button class="button button--secondary" type="button" :disabled="activeStepIndex === WIZARD_STEP_IDS.length - 1" @click="goToNextStep">Next</button>
|
||||
|
||||
Reference in New Issue
Block a user