FIX - refine SkyRide layout and ride details

This commit is contained in:
Leon.Schmidt
2026-08-16 18:28:38 +02:00
parent a183d4978b
commit 784cb55c6c
7 changed files with 144 additions and 21 deletions
+1 -1
View File
@@ -2502,7 +2502,7 @@ const defaultLocales: LocaleTree = {
home: 'Home',
rides: 'Rides',
activity: 'Activity',
messages: 'Messages',
messages: 'Chat',
profile: 'Profile',
},
rides: 'Your Rides',
+2
View File
@@ -25,7 +25,9 @@ const ride: SkyRideRide = {
createdAt: 1_755_000_000,
currency: '$',
destination,
distanceMeters: 5_200,
driver: null,
durationSeconds: 640,
id: 'ride-1',
pickup,
price: 48,
+2
View File
@@ -87,7 +87,9 @@ export type SkyRideRide = {
createdAt: number
currency: string
destination: SkyRideLocation
distanceMeters: number
driver: SkyRideDriver | null
durationSeconds: number
finalPrice?: number
id: string
passenger?: SkyRidePassenger
@@ -0,0 +1,42 @@
import { readFileSync } from 'node:fs'
import { describe, expect, it } from 'vitest'
const source = readFileSync(
new URL('./SkyRideApp.vue', import.meta.url),
'utf8',
)
const types = readFileSync(
new URL('../../types/skyride.ts', import.meta.url),
'utf8',
)
describe('SkyRide app layout', () => {
it('shows the server-authoritative ride distance in history', () => {
expect(types).toContain('distanceMeters: number')
expect(source).toContain('formatRideDistance(ride.distanceMeters)')
expect(source).toContain('skyride-history-card__distance')
})
it('aligns rider and activity surfaces to one content width', () => {
expect(source).toMatch(
/\.skyride-location-list,\s*\.skyride-activity-list\s*\{[^}]*margin-inline:\s*2px !important;/s,
)
expect(source).toMatch(
/\.skyride-home-panel\s*\{[^}]*background:\s*linear-gradient/s,
)
})
it('uses a compact swipeable profile editor with equal actions', () => {
expect(source).toContain('class="skyride-profile-sheet"')
expect(source).toContain('swipe-to-close')
expect(source).toContain('@swipeclose="closeProfileEditor"')
expect(source).toMatch(
/\.skyride-profile-sheet :deep\(\.sky-sheet__panel\)\s*\{[^}]*max-height:\s*78%;/s,
)
expect(source.match(/<SkyButton\s+block\s+large\s+rounded/g)).toHaveLength(
2,
)
expect(source).toContain('skyride-profile-media-button')
})
})
+88 -19
View File
@@ -229,6 +229,10 @@ function formatQuoteDistance(
)
}
function formatRideDistance(distanceMeters: number): string {
return formatQuoteDistance(Math.max(0, distanceMeters) / 1000, 'kilometer')
}
function formatDistanceRate(option: SkyRideQuoteOption): string {
const unitKey =
skyride.quote?.distanceUnit === 'mile' ? 'perMile' : 'perKilometer'
@@ -1256,12 +1260,18 @@ onBeforeUnmount(() => {
</div>
<template #footer>
<div class="skyride-history-card__footer">
<span>{{
ride.driver?.name ??
ride.passenger?.name ??
phone.t('Apps.skyride.ride')
}}</span
><strong>{{
<div class="skyride-history-card__meta">
<span>{{
ride.driver?.name ??
ride.passenger?.name ??
phone.t('Apps.skyride.ride')
}}</span>
<span class="skyride-history-card__distance">
<Route :size="13" aria-hidden="true" />
{{ formatRideDistance(ride.distanceMeters) }}
</span>
</div>
<strong>{{
formatMoney(ride.finalPrice ?? ride.price, ride.currency)
}}</strong>
</div>
@@ -1497,11 +1507,12 @@ onBeforeUnmount(() => {
class="skyride-profile-sheet"
:opened="profileEditorOpened"
:aria-label="phone.t('Apps.skyride.editProfile')"
swipe-to-close
@backdropclick="closeProfileEditor"
@escape="closeProfileEditor"
@swipeclose="closeProfileEditor"
>
<section class="skyride-profile-editor">
<div class="skyride-sheet__handle" aria-hidden="true"></div>
<div class="skyride-sheet__title">
<div>
<span>{{ phone.t('Apps.skyride.profile') }}</span>
@@ -1524,10 +1535,18 @@ onBeforeUnmount(() => {
</div>
<strong>{{ phone.t('Apps.skyride.profilePhoto') }}</strong>
<div>
<SkyButton outline rounded @click="openProfileMedia('photos')">
<SkyButton
rounded
class="skyride-profile-media-button"
@click="openProfileMedia('photos')"
>
<Images :size="17" /> {{ phone.t('Apps.skyride.gallery') }}
</SkyButton>
<SkyButton outline rounded @click="openProfileMedia('camera')">
<SkyButton
rounded
class="skyride-profile-media-button"
@click="openProfileMedia('camera')"
>
<Camera :size="17" /> {{ phone.t('Apps.skyride.camera') }}
</SkyButton>
</div>
@@ -1556,6 +1575,7 @@ onBeforeUnmount(() => {
<div class="skyride-profile-editor__actions">
<SkyButton
block
large
rounded
variant="secondary"
@click="closeProfileEditor"
@@ -1737,6 +1757,7 @@ onBeforeUnmount(() => {
.skyride-app {
--ride-accent: #f5c518;
--ride-accent-strong: #725600;
--ride-bg-rgb: 244 244 247;
--ride-bg: #f4f4f7;
--ride-card: rgba(255, 255, 255, 0.88);
--ride-card-strong: #fff;
@@ -1744,6 +1765,7 @@ onBeforeUnmount(() => {
--ride-text: #171719;
--ride-muted: #707078;
--ride-map: #07131f;
--ride-profile-media-bg: #725600;
--sky-bg: var(--ride-bg);
--sky-surface: var(--ride-card-strong);
--sky-surface-muted: #e6e6eb;
@@ -1760,6 +1782,7 @@ onBeforeUnmount(() => {
.skyride-app--dark {
--ride-accent-strong: #f5c518;
--ride-bg-rgb: 8 9 11;
--ride-bg: #08090b;
--ride-card: rgba(29, 30, 33, 0.9);
--ride-card-strong: #1c1d20;
@@ -1767,6 +1790,7 @@ onBeforeUnmount(() => {
--ride-text: #f7f7f8;
--ride-muted: #a2a2aa;
--ride-map: #050a10;
--ride-profile-media-bg: #9b7600;
--sky-surface-muted: #2c2c2e;
--sky-danger: #ff453a;
}
@@ -1884,7 +1908,12 @@ onBeforeUnmount(() => {
.skyride-home-panel {
min-height: 320px;
margin-top: 0;
background: var(--ride-bg);
background: linear-gradient(
180deg,
rgb(var(--ride-bg-rgb) / 0) 0,
rgb(var(--ride-bg-rgb) / 0.78) 54px,
var(--ride-bg) 112px
);
}
.skyride-heading,
@@ -1950,6 +1979,11 @@ onBeforeUnmount(() => {
margin-block: 0 14px;
}
.skyride-location-list,
.skyride-activity-list {
margin-inline: 2px !important;
}
.skyride-location-list :deep(li),
.skyride-service-list :deep(li),
.skyride-activity-list :deep(li),
@@ -2514,10 +2548,30 @@ onBeforeUnmount(() => {
.skyride-history-card__footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
font-size: 12px;
}
.skyride-history-card__meta {
display: flex;
min-width: 0;
flex-direction: column;
gap: 2px;
}
.skyride-history-card__distance {
display: inline-flex;
align-items: center;
gap: 4px;
}
.skyride-history-card__distance > svg {
flex: 0 0 auto;
color: var(--ride-accent-strong);
}
.skyride-message-contact > svg {
color: var(--ride-muted);
}
@@ -2651,6 +2705,7 @@ button.skyride-profile-avatar--editable {
font-weight: 600;
line-height: 13px;
text-overflow: ellipsis;
white-space: nowrap;
}
.skyride-tab-pane :deep(> .sky-tab-button .sky-tab-button__icon) {
@@ -2675,24 +2730,24 @@ button.skyride-profile-avatar--editable {
.skyride-profile-editor {
box-sizing: border-box;
height: 100%;
overflow-y: auto;
padding: calc(var(--sky-safe-area-top) + 8px) 14px
calc(var(--sky-safe-area-bottom) + 12px);
min-height: 0;
padding: 4px 14px calc(var(--sky-safe-area-bottom) + 12px);
color: var(--ride-text);
background: var(--ride-bg);
border-radius: 0;
border-radius: 0 0 28px 28px;
}
.skyride-profile-sheet :deep(.sky-overlay-backdrop) {
background: var(--ride-bg);
background: rgba(0, 0, 0, 0.38);
}
.skyride-profile-sheet :deep(.sky-sheet__panel) {
top: 0;
max-height: none;
top: auto;
max-height: 78%;
overflow-x: hidden;
overflow-y: auto;
border: 0;
border-radius: 0;
border-radius: 28px 28px 0 0;
background: var(--ride-bg);
box-shadow: none;
}
@@ -2724,6 +2779,20 @@ button.skyride-profile-avatar--editable {
gap: 6px;
}
.skyride-profile-editor__avatar :deep(.skyride-profile-media-button) {
border-color: var(--ride-profile-media-bg);
background: var(--ride-profile-media-bg);
color: #fff !important;
}
.skyride-profile-editor__avatar
:deep(.skyride-profile-media-button:active:not(:disabled)) {
border-color: var(--ride-profile-media-bg);
background: var(--ride-profile-media-bg);
color: #fff !important;
filter: brightness(0.9);
}
.skyride-profile-editor__actions {
margin-top: 4px;
}
+8
View File
@@ -1114,7 +1114,9 @@ let skyRideAvailableRequests = [
createdAt: unixTime(-90),
currency: '$',
destination: skyRideQuickLocations[1],
distanceMeters: 4200,
driver: null,
durationSeconds: 480,
id: 'skyride-request-demo',
passenger: {
avatarUrl:
@@ -1136,7 +1138,9 @@ let skyRideHistory = [
createdAt: unixTime(-22 * 60 * 60),
currency: '$',
destination: skyRideQuickLocations[3],
distanceMeters: 4800,
driver: skyRideDriver,
durationSeconds: 620,
finalPrice: 31,
id: 'skyride-history-1',
passenger: skyRidePassenger,
@@ -1150,7 +1154,9 @@ let skyRideHistory = [
createdAt: unixTime(-3 * 24 * 60 * 60),
currency: '$',
destination: skyRideQuickLocations[2],
distanceMeters: 18700,
driver: skyRideDriver,
durationSeconds: 1380,
finalPrice: 68,
id: 'skyride-history-2',
passenger: skyRidePassenger,
@@ -7411,7 +7417,9 @@ app.post('/api/:endpoint', (request, response) => {
createdAt: now,
currency: quote.option.currency,
destination: quote.destination,
distanceMeters: quote.distanceMeters,
driver: null,
durationSeconds: quote.durationSeconds,
id: `skyride-ride-${skyRideSequence++}`,
passenger: skyRidePassenger,
pickup: quote.pickup,
+1 -1
View File
@@ -1187,7 +1187,7 @@ Locales["en"] = {
cancelled = "This ride is no longer active.",
},
navigation = "SkyRide navigation",
tabs = { home = "Home", rides = "Rides", activity = "Activity", messages = "Messages", profile = "Profile" },
tabs = { home = "Home", rides = "Rides", activity = "Activity", messages = "Chat", profile = "Profile" },
rides = "Your Rides", ridesBody = "Review completed and cancelled rides.", noRides = "No rides yet",
noRidesBody = "Completed and cancelled rides will appear here.", activity = "Activity",
activityBody = "Recent trip updates and milestones.", noActivity = "No recent activity",