mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-29 01:08:59 +00:00
ENH - refine CityMarkt glass interface
This commit is contained in:
@@ -65,4 +65,7 @@ const formattedAmount = computed(() =>
|
||||
<style scoped>
|
||||
.citymarkt-offer{width:92%;padding:11px;border:1px solid #ffc92842;border-radius:14px;align-self:flex-start;background:linear-gradient(145deg,#332d19,var(--panel));box-shadow:0 7px 18px #0003}.citymarkt-offer--own{align-self:flex-end}.citymarkt-offer header{display:flex;align-items:center;gap:8px}.citymarkt-offer header>span{width:32px;height:32px;flex:none;border-radius:10px;display:grid;place-items:center;background:var(--yellow);color:#171816}.citymarkt-offer header>div{min-width:0;flex:1}.citymarkt-offer header small,.citymarkt-offer header strong{display:block}.citymarkt-offer header small{color:var(--muted);font-size:9px;font-weight:800;letter-spacing:.02em;text-transform:uppercase}.citymarkt-offer header strong{margin-top:1px;font-size:18px}.citymarkt-offer header i{padding:5px 7px;border-radius:7px;background:#ffc92817;color:var(--yellow);font-size:8px;font-style:normal;font-weight:900;text-transform:uppercase}.citymarkt-offer>p{margin:7px 0 0;color:var(--muted);font-size:9px;line-height:1.35}.citymarkt-offer--accepted{border-color:#54d68173;background:linear-gradient(145deg,#193526,var(--panel))}.citymarkt-offer--accepted header>span{background:#54d681}.citymarkt-offer--accepted header i{background:#54d6811c;color:#67e494}.citymarkt-offer--rejected,.citymarkt-offer--countered{border-color:#ffffff14;filter:saturate(.65)}.citymarkt-offer--rejected header>span,.citymarkt-offer--countered header>span{background:#555750;color:#ddd}.citymarkt-offer--rejected header i,.citymarkt-offer--countered header i{background:#ffffff0c;color:var(--muted)}.citymarkt-offer__actions{margin-top:10px;display:grid;grid-template-columns:1fr 1fr;gap:6px}.citymarkt-offer__actions button{min-height:35px;padding:7px 6px;border:1px solid #ffffff12;border-radius:10px;display:flex;align-items:center;justify-content:center;gap:4px;background:#ffffff09;color:inherit;font-size:9.5px;font-weight:850;line-height:1.1}.citymarkt-offer__actions button.accept{border:0;background:#54d681;color:#102319}.citymarkt-offer__actions button.reject{grid-column:1/-1;color:#ff8078}:global(.citymarkt--light) .citymarkt-offer{background:linear-gradient(145deg,#fff8d9,#fff);box-shadow:0 7px 18px #0001}:global(.citymarkt--light) .citymarkt-offer--accepted{background:linear-gradient(145deg,#e6faed,#fff)}
|
||||
.citymarkt-offer{padding:12px}.citymarkt-offer header>span{width:35px;height:35px}.citymarkt-offer header small{font-size:10.5px}.citymarkt-offer header strong{font-size:20px}.citymarkt-offer header i{padding:5px 8px;font-size:9.5px}.citymarkt-offer>p{margin-top:8px;font-size:11.5px}.citymarkt-offer__actions{margin-top:11px;gap:7px}.citymarkt-offer__actions button{min-height:40px;padding:8px;font-size:12px;font-weight:850;gap:5px}.citymarkt-offer__actions button svg{width:15px;height:15px}
|
||||
.citymarkt-offer:not(.citymarkt-offer--accepted) {
|
||||
border-color: transparent;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { Check, ChevronDown } from 'lucide-vue-next'
|
||||
import { kGlass } from 'konsta/vue'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
type SelectOption = {
|
||||
@@ -20,7 +21,9 @@ const root = ref<HTMLElement | null>(null)
|
||||
const isOpen = ref(false)
|
||||
const highlightedIndex = ref(0)
|
||||
const selectedLabel = computed(
|
||||
() => props.options.find((option) => option.value === props.modelValue)?.label ?? '',
|
||||
() =>
|
||||
props.options.find((option) => option.value === props.modelValue)?.label ??
|
||||
'',
|
||||
)
|
||||
|
||||
function open(): void {
|
||||
@@ -44,7 +47,8 @@ function handleKeydown(event: KeyboardEvent): void {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault()
|
||||
if (!isOpen.value) open()
|
||||
else select(props.options[highlightedIndex.value]?.value ?? props.modelValue)
|
||||
else
|
||||
select(props.options[highlightedIndex.value]?.value ?? props.modelValue)
|
||||
return
|
||||
}
|
||||
if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return
|
||||
@@ -52,7 +56,8 @@ function handleKeydown(event: KeyboardEvent): void {
|
||||
if (!isOpen.value) open()
|
||||
const direction = event.key === 'ArrowDown' ? 1 : -1
|
||||
highlightedIndex.value =
|
||||
(highlightedIndex.value + direction + props.options.length) % props.options.length
|
||||
(highlightedIndex.value + direction + props.options.length) %
|
||||
props.options.length
|
||||
}
|
||||
|
||||
function handleOutsidePointer(event: PointerEvent): void {
|
||||
@@ -60,12 +65,15 @@ function handleOutsidePointer(event: PointerEvent): void {
|
||||
}
|
||||
|
||||
onMounted(() => window.addEventListener('pointerdown', handleOutsidePointer))
|
||||
onUnmounted(() => window.removeEventListener('pointerdown', handleOutsidePointer))
|
||||
onUnmounted(() =>
|
||||
window.removeEventListener('pointerdown', handleOutsidePointer),
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="root" class="citymarkt-select" @keydown="handleKeydown">
|
||||
<button
|
||||
<k-glass
|
||||
component="button"
|
||||
class="citymarkt-select__trigger"
|
||||
type="button"
|
||||
aria-haspopup="listbox"
|
||||
@@ -74,7 +82,7 @@ onUnmounted(() => window.removeEventListener('pointerdown', handleOutsidePointer
|
||||
>
|
||||
<span>{{ selectedLabel }}</span>
|
||||
<ChevronDown :size="14" :class="{ open: isOpen }" />
|
||||
</button>
|
||||
</k-glass>
|
||||
|
||||
<Transition name="citymarkt-select">
|
||||
<div v-if="isOpen" class="citymarkt-select__menu" role="listbox">
|
||||
@@ -100,7 +108,105 @@ onUnmounted(() => window.removeEventListener('pointerdown', handleOutsidePointer
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.citymarkt-select{position:relative;min-width:0}.citymarkt-select__trigger{width:100%;height:36px;padding:0 10px;border:1px solid #ffffff0d;border-radius:10px;display:flex;align-items:center;justify-content:space-between;gap:6px;background:var(--panel);color:inherit;font-size:10px;text-align:left}.citymarkt-select__trigger span{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.citymarkt-select__trigger svg{flex:none;color:var(--yellow);transition:transform .18s ease}.citymarkt-select__trigger svg.open{transform:rotate(180deg)}.citymarkt-select__menu{position:absolute;z-index:12;top:calc(100% + 5px);right:0;left:0;max-height:176px;padding:4px;border:1px solid #ffffff16;border-radius:11px;overflow-y:auto;background:#292a27;box-shadow:0 12px 28px #0009;scrollbar-width:none}:global(.citymarkt--light) .citymarkt-select__menu{border-color:#00000014;background:#fff;box-shadow:0 12px 28px #0003}.citymarkt-select__menu button{width:100%;min-height:31px;padding:6px 7px;border:0;border-radius:8px;display:flex;align-items:center;justify-content:space-between;gap:5px;background:none;color:var(--muted);font-size:10px;text-align:left}.citymarkt-select__menu button.highlighted{background:#ffffff0b;color:inherit}:global(.citymarkt--light) .citymarkt-select__menu button.highlighted{background:#0000000b}.citymarkt-select__menu button.selected{color:var(--yellow);font-weight:800}.citymarkt-select-enter-active,.citymarkt-select-leave-active{transition:opacity .15s ease,transform .15s ease}.citymarkt-select-enter-from,.citymarkt-select-leave-to{opacity:0;transform:translateY(-4px) scale(.98)}
|
||||
.citymarkt-select__trigger{height:40px;font-size:13px}
|
||||
.citymarkt-select__menu button{min-height:36px;padding:7px 8px;font-size:12px}
|
||||
.citymarkt-select {
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
}
|
||||
.citymarkt-select__trigger {
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
padding: 0 10px;
|
||||
border: 0;
|
||||
border-radius: 9999px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 6px;
|
||||
color: inherit;
|
||||
font-size: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
.citymarkt-select__trigger span {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.citymarkt-select__trigger svg {
|
||||
flex: none;
|
||||
color: var(--yellow);
|
||||
transition: transform 0.18s ease;
|
||||
}
|
||||
.citymarkt-select__trigger svg.open {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
.citymarkt-select__menu {
|
||||
position: absolute;
|
||||
z-index: 12;
|
||||
top: calc(100% + 5px);
|
||||
right: 0;
|
||||
left: 0;
|
||||
max-height: 176px;
|
||||
padding: 4px;
|
||||
border: 1px solid #ffffff14;
|
||||
border-radius: 11px;
|
||||
overflow-y: auto;
|
||||
background: #292a27;
|
||||
box-shadow: 0 12px 28px #0009;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
:global(.citymarkt--light) .citymarkt-select__menu {
|
||||
border-color: #00000012;
|
||||
background: #fff;
|
||||
box-shadow: 0 12px 28px #0003;
|
||||
}
|
||||
.citymarkt-select__menu button {
|
||||
width: 100%;
|
||||
min-height: 31px;
|
||||
padding: 6px 7px;
|
||||
border: 0;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 5px;
|
||||
background: none;
|
||||
color: var(--muted);
|
||||
font-size: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
.citymarkt-select__menu button.highlighted {
|
||||
background: #ffffff0b;
|
||||
color: inherit;
|
||||
}
|
||||
:global(.citymarkt--light) .citymarkt-select__menu button.highlighted {
|
||||
background: #0000000b;
|
||||
}
|
||||
.citymarkt-select__menu button.selected {
|
||||
background: #ffffff14;
|
||||
color: inherit;
|
||||
font-weight: 800;
|
||||
}
|
||||
:global(.citymarkt--light) .citymarkt-select__menu button.selected {
|
||||
background: #0000000d;
|
||||
}
|
||||
.citymarkt-select-enter-active,
|
||||
.citymarkt-select-leave-active {
|
||||
transition:
|
||||
opacity 0.15s ease,
|
||||
transform 0.15s ease;
|
||||
}
|
||||
.citymarkt-select-enter-from,
|
||||
.citymarkt-select-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(-4px) scale(0.98);
|
||||
}
|
||||
.citymarkt-select__trigger {
|
||||
height: 40px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.citymarkt-select__menu button {
|
||||
min-height: 36px;
|
||||
padding: 7px 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -496,7 +496,7 @@ const defaultLocales: LocaleTree = {
|
||||
reportReasons: { prohibited: 'Prohibited item', fraud: 'Suspected fraud', spam: 'Spam', offensive: 'Offensive content', other: 'Other' },
|
||||
searchPlaceholder: 'What are you looking for?', allCategories: 'All categories', allDistricts: 'All districts',
|
||||
sortNewest: 'Newest first', sortPriceAsc: 'Lowest price', sortPriceDesc: 'Highest price',
|
||||
freshOffers: 'Fresh offers', offers: 'offers', noListings: 'No offers found',
|
||||
freshOffers: 'Fresh offers', offers: 'offers', compactView: 'Compact view', largeView: 'Large view', noListings: 'No offers found',
|
||||
noListingsBody: 'Try another search or category.', noDistrict: 'No district',
|
||||
free: 'Free', negotiablePrice: '${price} negotiable', money: '${price}',
|
||||
hoursAgo: '{count}h ago', daysAgo: '{count}d ago', photos: 'photos', activeListings: 'active listings',
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -354,7 +354,7 @@ Locales["en"] = {
|
||||
reportReasons = { prohibited = "Prohibited item", fraud = "Suspected fraud", spam = "Spam", offensive = "Offensive content", other = "Other" },
|
||||
searchPlaceholder = "What are you looking for?", allCategories = "All categories", allDistricts = "All districts",
|
||||
sortNewest = "Newest first", sortPriceAsc = "Lowest price", sortPriceDesc = "Highest price",
|
||||
freshOffers = "Fresh offers", offers = "offers", noListings = "No offers found",
|
||||
freshOffers = "Fresh offers", offers = "offers", compactView = "Compact view", largeView = "Large view", noListings = "No offers found",
|
||||
noListingsBody = "Try another search or category.", noDistrict = "No district",
|
||||
free = "Free", negotiablePrice = "${price} negotiable", money = "${price}",
|
||||
hoursAgo = "{count}h ago", daysAgo = "{count}d ago", photos = "photos", activeListings = "active listings",
|
||||
|
||||
Reference in New Issue
Block a user