user-app: redesigned home screen and product detail
Design language introduced here and reused across both screens:
- LESS colour tokens (@ink/@inkSoft/@inkMuted/@inkFaint, @wine/@wineSoft,
@canvas/@canvasSoft, @hairline/@hairlineSoft) added to
themeConfig/colors.json and injected globally via vite's modifyVars, so
scoped <style lang="less"> blocks resolve them with no import
- BEM-ish scoped class names, hairline-bordered cards at 14-18px radii,
ink surfaces with a wine accent, dashed-border empty states
- components/home/: SectionHead, ShowcaseCard, ShowcaseSlider, CategoryRail,
RateStrip, AccountStrip
Data honesty is deliberate throughout: no rial price is printed for a piece,
because a finished item's price is the live gold rate x weight plus wage,
computed at order time and never stored on the product. Only genuinely
present fields are shown (weight, making-charge percent, stock, category,
brand). Categories and the hero are derived from the real catalogue, so an
empty catalogue renders an empty state rather than placeholder tiles.
Also fixes a real bug in the product detail view: it ran, at module scope,
history.pushState + window.onpopstate = () => history.go(1). Because the
drawer mounts its slot eagerly, that fired for every product card on the
home screen and permanently hijacked the back button for the session.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a12fb0450e
commit
f2d83c53df
@@ -0,0 +1,59 @@
|
||||
<!-- Section heading with an optional "see all" affordance. -->
|
||||
<template>
|
||||
<header class="sec">
|
||||
<div class="sec__text">
|
||||
<h2 class="sec__title">{{ title }}</h2>
|
||||
<p v-if="subtitle" class="sec__sub">{{ subtitle }}</p>
|
||||
</div>
|
||||
<button v-if="actionLabel" type="button" class="sec__action" @click="emit('action')">
|
||||
{{ actionLabel }}
|
||||
<Icon icon="vuesax-linear:arrow-left-2" size="15" />
|
||||
</button>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Icon from '../icon/Icon.vue'
|
||||
|
||||
defineProps<{ title: string; subtitle?: string; actionLabel?: string }>()
|
||||
const emit = defineEmits<{ (e: 'action'): void }>()
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.sec {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding-bottom: 13px;
|
||||
}
|
||||
|
||||
.sec__title {
|
||||
margin: 0;
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
color: @ink;
|
||||
letter-spacing: -0.1px;
|
||||
}
|
||||
|
||||
.sec__sub {
|
||||
margin: 5px 0 0;
|
||||
font-size: 11.5px;
|
||||
color: @inkFaint;
|
||||
}
|
||||
|
||||
.sec__action {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
border: 0;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
font-family: inherit;
|
||||
font-size: 11.5px;
|
||||
font-weight: 700;
|
||||
color: @wine;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user