diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css index 7414079..b9608c2 100644 --- a/frontend/src/assets/main.css +++ b/frontend/src/assets/main.css @@ -788,6 +788,76 @@ button { cursor: pointer; pointer-events: auto; } +.phone-dynamic-island { + position: absolute; + z-index: 98; + top: 12px; + left: 50%; + display: flex; + align-items: center; + gap: 10px; + width: 300px; + min-height: 72px; + padding: 10px 12px 10px 16px; + border: 1px solid rgb(255 255 255 / 10%); + border-radius: 28px; + color: #fff; + background: #050505; + box-shadow: 0 8px 24px rgb(0 0 0 / 45%); + transform: translateX(-50%); +} +.phone-dynamic-island__caller { + min-width: 0; + flex: 1; +} +.phone-dynamic-island__caller span, +.phone-dynamic-island__caller strong { + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.phone-dynamic-island__caller span { + color: rgb(255 255 255 / 58%); + font-size: 11px; + line-height: 14px; +} +.phone-dynamic-island__caller strong { + margin-top: 2px; + font-size: 15px; + line-height: 18px; +} +.phone-dynamic-island__actions { + display: flex; + gap: 8px; +} +.phone-dynamic-island__actions .sky-button--icon-only { + width: 44px; + min-width: 44px; + height: 44px; +} +.phone-dynamic-island__actions svg { + width: 19px; + height: 19px; +} +.phone-dynamic-island__answer { + --sky-app-accent: #34c759; +} +.phone-dynamic-island-enter-active, +.phone-dynamic-island-leave-active { + transition: opacity 180ms ease, transform 220ms cubic-bezier(0.22, 1, 0.36, 1); +} +.phone-dynamic-island-enter-from, +.phone-dynamic-island-leave-to { + opacity: 0; + transform: translateX(-50%) scale(0.86); +} +@media (prefers-reduced-motion: reduce) { + .phone-dynamic-island-enter-active, + .phone-dynamic-island-leave-active { + transition: none; + } +} .phone-home-indicator { position: absolute; z-index: 90; @@ -4460,9 +4530,9 @@ button { display: grid; grid-template-columns: 21px 1fr; gap: 4px 7px; - min-height: 82px; + min-height: 94px; margin: 0; - padding: 12px; + padding: 14px; border-radius: calc(var(--sky-radius-card) - 6px); } .weather-detail-card svg { diff --git a/frontend/src/components/NotesRichTextEditor.contract.test.ts b/frontend/src/components/NotesRichTextEditor.contract.test.ts index d74dea9..ff3a7aa 100644 --- a/frontend/src/components/NotesRichTextEditor.contract.test.ts +++ b/frontend/src/components/NotesRichTextEditor.contract.test.ts @@ -21,6 +21,8 @@ describe('NotesRichTextEditor formatting tabbar', () => { expect(source).toContain('@click="formatMode = true"') expect(source).toContain('@click="formatMode = false"') expect(source).toContain(':disabled="editor.state.selection.empty"') + expect(source).toContain('class="notes-rich-editor sky-ui-provider"') + expect(source).toContain("'sky-ui-provider--dark': dark") expect(source).not.toContain('notes-rich-editor__toolbar-row') expect(source).not.toContain('scrollToolbar') }) diff --git a/frontend/src/components/NotesRichTextEditor.vue b/frontend/src/components/NotesRichTextEditor.vue index 5894af1..f5abd65 100644 --- a/frontend/src/components/NotesRichTextEditor.vue +++ b/frontend/src/components/NotesRichTextEditor.vue @@ -263,8 +263,11 @@ onBeforeUnmount(() => editor.value?.destroy()) diff --git a/frontend/src/views/apps/CompaniesApp.vue b/frontend/src/views/apps/CompaniesApp.vue index 533ebd3..1a01ca9 100644 --- a/frontend/src/views/apps/CompaniesApp.vue +++ b/frontend/src/views/apps/CompaniesApp.vue @@ -364,12 +364,7 @@ function relativeTime(value: string): string { } function companyInitials(company: CompanySummary): string { - return company.name - .split(/\s+/) - .slice(0, 2) - .map((word) => word[0] ?? '') - .join('') - .toUpperCase() + return company.name.trim().charAt(0).toUpperCase() } function companySubtitle(company: CompanySummary): string { diff --git a/frontend/src/views/apps/HealthApp.contract.test.ts b/frontend/src/views/apps/HealthApp.contract.test.ts index 0852dbd..5735c5d 100644 --- a/frontend/src/views/apps/HealthApp.contract.test.ts +++ b/frontend/src/views/apps/HealthApp.contract.test.ts @@ -28,6 +28,13 @@ describe('HealthApp Sky UI contract', () => { expect(source).toContain('health.saveMedicalId') }) + it('uses the Sky iOS action sheet instead of a native blood type select', () => { + expect(source).toContain(' { expect(source).not.toContain('healthPercent') expect(source).not.toContain('recoveryPercent') diff --git a/frontend/src/views/apps/HealthApp.vue b/frontend/src/views/apps/HealthApp.vue index ee85c05..b8e78c6 100644 --- a/frontend/src/views/apps/HealthApp.vue +++ b/frontend/src/views/apps/HealthApp.vue @@ -2,6 +2,8 @@ import { Activity, ChartNoAxesColumnIncreasing, + Check, + ChevronDown, ContactRound, Flame, Footprints, @@ -19,6 +21,10 @@ import { usePhoneStore } from '@/stores/phone' import type { HealthMedicalIdInput } from '@/types/health' import { SkyAppPage, + SkyActionButton, + SkyActionGroup, + SkyActionSheet, + SkyActionsLabel, SkyButton, SkyEmptyState, SkyField, @@ -39,6 +45,7 @@ const phone = usePhoneStore() const health = useHealthStore() const activeTab = ref('today') const editingMedicalId = ref(false) +const bloodTypePickerOpened = ref(false) const actionError = ref('') const medicalDraft = reactive({ allergies: '', @@ -136,10 +143,11 @@ function formatMinutes(seconds: number): string { }) } -function weekday(date: string, narrow = true): string { - return new Intl.DateTimeFormat(phone.lang, { - weekday: narrow ? 'narrow' : 'short', - }).format(new Date(`${date}T12:00:00`)) +function weekday(date: string): string { + const value = new Intl.DateTimeFormat(phone.lang, { weekday: 'short' }) + .format(new Date(`${date}T12:00:00`)) + .replace(/\.$/, '') + return Array.from(value).slice(0, 2).join('') } function fullDate(date: string): string { @@ -168,6 +176,7 @@ function syncMedicalDraft(): void { async function toggleMedicalEdit(): Promise { actionError.value = '' + bloodTypePickerOpened.value = false if (!editingMedicalId.value) { syncMedicalDraft() editingMedicalId.value = true @@ -185,6 +194,11 @@ async function toggleMedicalEdit(): Promise { : translatedError } +function selectBloodType(value: string): void { + medicalDraft.bloodType = value + bloodTypePickerOpened.value = false +} + async function dial(number: string): Promise { if (!number) return actionError.value = '' @@ -429,12 +443,18 @@ onBeforeUnmount(() => {

{{ phone.t('Apps.health.medicalId.emergencyInformation') }}

    - +
  • + +
  • { + + + + {{ phone.t('Apps.health.medicalId.bloodType') }} + + + {{ option.label }} + + + + + {{ phone.t('Common.cancel') }} + + + + { border: calc(var(--sky-hairline-scale) * 1px) solid var(--health-panel-border); border-radius: var(--sky-radius-card); background: var(--health-panel); + flex: none; grid-template-columns: repeat(3, 1fr); } @@ -745,8 +799,9 @@ onBeforeUnmount(() => { } .health-metrics span { - color: var(--sky-muted); - font-size: 12px; + color: var(--sky-text); + font-size: 13px; + font-weight: 600; } .health-section { @@ -1099,6 +1154,53 @@ onBeforeUnmount(() => { list-style: none; } +.health-blood-type-field button { + display: grid; + width: 100%; + min-height: 58px; + align-items: center; + padding: 8px 16px; + border: 0; + background: transparent; + color: var(--sky-text); + cursor: pointer; + grid-template-columns: 1fr auto auto; + grid-template-rows: auto auto; + text-align: left; +} + +.health-blood-type-field button:focus-visible { + outline: 2px solid var(--sky-app-accent); + outline-offset: -2px; +} + +.health-blood-type-field span { + grid-column: 1 / -1; + color: var(--sky-muted); + font-size: 12px; + line-height: 16px; +} + +.health-blood-type-field strong { + font-size: 17px; + font-weight: 400; + line-height: 24px; +} + +.health-blood-type-field svg { + color: var(--sky-muted); +} + +.health-blood-type-option { + display: flex; + align-items: center; + justify-content: space-between; +} + +.health-blood-type-option svg { + color: var(--sky-app-accent); +} + .health-action-error { margin: 0; padding: 0 4px; diff --git a/frontend/src/views/apps/NotesApp.vue b/frontend/src/views/apps/NotesApp.vue index eaca7cc..9767ccc 100644 --- a/frontend/src/views/apps/NotesApp.vue +++ b/frontend/src/views/apps/NotesApp.vue @@ -1,15 +1,4 @@ @@ -903,7 +922,6 @@ onBeforeUnmount(() => { ref="phoneContent" class="phone-call-content" :class="{ 'phone-call-content--profile': selectedNumber }" - @scroll.passive="handlePhoneContentScroll" >

    {{ phone.t('Apps.phone.noSim') }}

    @@ -911,10 +929,7 @@ onBeforeUnmount(() => {