@7365admin1/layer-common 3.2.7 → 3.2.8-staging.201
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/css/primitives.css +1113 -0
- package/assets/css/screens.css +1097 -0
- package/assets/css/shell.css +258 -0
- package/assets/css/tokens.css +236 -0
- package/components/AcceptDialog.vue +17 -18
- package/components/AccessCard/AvailableStats.vue +24 -16
- package/components/AccessCardAddForm.vue +42 -42
- package/components/AccessCardAssignToUnitForm.vue +13 -21
- package/components/AccessCardDeleteDialog.vue +41 -39
- package/components/AccessCardDetailsDialog.vue +125 -79
- package/components/AccessCardPreviewDialog.vue +58 -84
- package/components/AccessCardQrTagging.vue +60 -63
- package/components/AccessCardReplaceForm.vue +27 -23
- package/components/AccessManagement.vue +86 -85
- package/components/AddEqupmentForm.vue +18 -22
- package/components/AddPassKeyToVisitor.vue +95 -73
- package/components/AppButton.vue +62 -0
- package/components/AppCard.vue +20 -0
- package/components/AppDateField.vue +49 -0
- package/components/AppField.vue +76 -0
- package/components/AppKpiTile.vue +65 -0
- package/components/AppSegmented.vue +38 -0
- package/components/AppSelect.vue +247 -0
- package/components/AreaChecklistHistoryLogs.vue +51 -44
- package/components/AreaChecklistHistoryMain.vue +14 -7
- package/components/AreaFormDialog.vue +71 -59
- package/components/AreaMain.vue +73 -107
- package/components/AttachmentsViewer.vue +84 -22
- package/components/AttendanceCheckInOutDialog.vue +85 -88
- package/components/AttendanceDetailsDialog.vue +57 -63
- package/components/AttendanceMain.vue +4 -3
- package/components/AttendanceMapSearchDialog.vue +42 -44
- package/components/AttendanceSettingsDialog.vue +79 -63
- package/components/Avatar/Main.vue +54 -2
- package/components/BillingMain.vue +26 -30
- package/components/BtnUploadFile.vue +53 -11
- package/components/BuildingForm.vue +34 -27
- package/components/BuildingManagement/buildings.vue +39 -39
- package/components/BuildingManagement/units.vue +26 -42
- package/components/BuildingUnitFormAdd.vue +20 -23
- package/components/BuildingUnitFormEdit.vue +8 -4
- package/components/BulletinBoardForm.vue +19 -24
- package/components/BulletinBoardManagement.vue +49 -57
- package/components/BulletinBoardView.vue +9 -6
- package/components/BulletinExpirationChip.vue +13 -4
- package/components/Button/Close.vue +2 -2
- package/components/CameraForm.vue +21 -22
- package/components/CameraMain.vue +50 -49
- package/components/Card/DeleteConfirmation.vue +24 -22
- package/components/Card/MemberInfoSummary.vue +28 -3
- package/components/Card/Toggle.vue +15 -3
- package/components/CardToolbar.vue +37 -0
- package/components/Carousel.vue +56 -36
- package/components/Chat/Bubbles.vue +43 -14
- package/components/Chat/Information.vue +49 -32
- package/components/Chat/ListCard.vue +38 -9
- package/components/Chat/Message.vue +41 -15
- package/components/Chat/Navigation.vue +27 -15
- package/components/Chat/SkeletonLoader.vue +9 -2
- package/components/ChecklistItemRow.vue +25 -1
- package/components/CleaningScheduleMain.vue +44 -49
- package/components/ClientDetailForm.vue +81 -56
- package/components/ClientMain.vue +92 -82
- package/components/ConfirmDialog.vue +14 -8
- package/components/Container/Standard.vue +9 -7
- package/components/CreateSubsciptionPlan.vue +148 -89
- package/components/DashboardEmptyState.vue +48 -3
- package/components/DashboardMain.vue +924 -676
- package/components/DashboardPanel.vue +84 -21
- package/components/DeliveryCompany.vue +34 -20
- package/components/Dialog/DeleteConfirmation.vue +20 -21
- package/components/Dialog/ReplaceAutofillPrompt.vue +19 -26
- package/components/Dialog/ReusablePrompt.vue +30 -29
- package/components/Dialog/UpdateMoreAction.vue +62 -59
- package/components/DocumentForm.vue +14 -21
- package/components/DocumentManagement.vue +162 -108
- package/components/DocumentViewer.vue +29 -12
- package/components/DrawImage.vue +29 -21
- package/components/EntryPass/QrTemplatePreview.vue +27 -16
- package/components/EntryPassInformation.vue +40 -10
- package/components/EntryPassMain.vue +49 -27
- package/components/EquipmentItemMain.vue +84 -97
- package/components/EquipmentManagementMain.vue +81 -103
- package/components/Facility/BookingSetup.vue +43 -52
- package/components/Feedback/Form.vue +26 -12
- package/components/FeedbackMain.vue +35 -49
- package/components/FileInput.vue +75 -58
- package/components/FileInputWithList.vue +59 -12
- package/components/FormDialog.vue +60 -21
- package/components/HidAccessLogDashboard.vue +512 -490
- package/components/HidCameraCaptureDialog.vue +216 -0
- package/components/HidEnabledGate.vue +67 -9
- package/components/HidIntercomManagement.vue +1322 -653
- package/components/HidQrCodeConfiguration.vue +1030 -258
- package/components/HidReaderForm.vue +142 -59
- package/components/HidReaderManagement.vue +211 -323
- package/components/HidServiceSettingsPanel.vue +44 -13
- package/components/HidUserEnrollment.vue +1185 -412
- package/components/HygieneUpdateMoreAction.vue +44 -44
- package/components/IncidentReport/Authorities.vue +30 -18
- package/components/IncidentReport/IncidentInformation.vue +10 -10
- package/components/IncidentReport/IncidentInformationDownload.vue +3 -4
- package/components/IncidentReport/affectedEntities.vue +41 -20
- package/components/Input/Date.vue +3 -0
- package/components/Input/DatePicker.vue +1 -2
- package/components/Input/DateTimePicker.vue +1 -1
- package/components/Input/File.vue +55 -10
- package/components/Input/FileV2.vue +39 -6
- package/components/Input/InputPhoneNumberV2.vue +2 -1
- package/components/Input/ListGroupSelection.vue +56 -8
- package/components/Input/NRICNumber.vue +1 -0
- package/components/Input/NewDate.vue +1 -0
- package/components/Input/Number.vue +1 -0
- package/components/Input/Password.vue +1 -0
- package/components/Input/PhoneNumber.vue +21 -1
- package/components/Input/VehicleNumber.vue +1 -0
- package/components/InputLabel.vue +2 -2
- package/components/InvitationClientForm.vue +21 -19
- package/components/InvitationForm.vue +15 -21
- package/components/InvitationMain.vue +46 -61
- package/components/Layout/Header.vue +263 -36
- package/components/Layout/NavigationDrawer.vue +300 -30
- package/components/ListItem.vue +33 -3
- package/components/LocalPagination.vue +27 -3
- package/components/ManageChecklistMain.vue +136 -86
- package/components/MemberInformation.vue +32 -16
- package/components/MemberMain.vue +113 -93
- package/components/MyAttendanceMain.vue +3 -5
- package/components/NavigationItem.vue +83 -3
- package/components/Nfc/NFCPatrolReportMain.vue +47 -33
- package/components/Nfc/NFCPatrolRouteForm.vue +18 -20
- package/components/Nfc/NFCPatrolRouteMain.vue +116 -103
- package/components/Nfc/NFCPatrolSettings.vue +14 -4
- package/components/Nfc/NFCTagForm.vue +22 -8
- package/components/Nfc/NFCTagMain.vue +41 -43
- package/components/Nfc/PatrolReport/DailyReportTab.vue +8 -1
- package/components/Nfc/PatrolReport/MonthlyReportTab.vue +8 -1
- package/components/Nfc/PatrolReport/MonthlyReportTable.vue +5 -3
- package/components/Nfc/PatrolReport/PatrolActivityTable.vue +26 -6
- package/components/Nfc/PatrolReport/PatrolReportTab.vue +8 -0
- package/components/Nfc/PatrolReport/PatrolRouteSummary.vue +41 -9
- package/components/Nfc/PatrolReport/RemarksDialog.vue +39 -9
- package/components/Nfc/PatrolReport/ReportEmptyState.vue +29 -9
- package/components/Nfc/PatrolReport/ReportFilters.vue +19 -10
- package/components/Nfc/PatrolReport/ReportLocationHeader.vue +32 -6
- package/components/Nfc/PatrolReport/SummaryReportTable.vue +28 -6
- package/components/NotificationSettings.vue +373 -0
- package/components/NumberSettingField.vue +9 -2
- package/components/OnlineFormConfigurationForm.vue +725 -237
- package/components/OnlineFormFill.vue +213 -106
- package/components/OnlineFormRenderPreview.vue +25 -30
- package/components/OnlineFormsConfiguration.vue +113 -109
- package/components/OrgViewDialog.vue +34 -16
- package/components/OvernightParkingAvailability.vue +49 -26
- package/components/OvernightParkingManagement.vue +78 -18
- package/components/PageHeader.vue +43 -0
- package/components/PassInformation.vue +109 -53
- package/components/PasswordConfirmation.vue +44 -26
- package/components/PeopleForm.vue +41 -20
- package/components/PhotoUpload.vue +110 -48
- package/components/PlaceholderComponent.vue +35 -19
- package/components/PlanActionsMenu.vue +12 -2
- package/components/PlanStatusBadge.vue +7 -8
- package/components/PlateNumberDisplay.vue +9 -6
- package/components/QrTemplate/PrintDialog.vue +66 -43
- package/components/RolePermissionFormCreate.vue +104 -79
- package/components/RolePermissionFormPreviewUpdate.vue +111 -109
- package/components/RolePermissionMain.vue +183 -81
- package/components/ScanVisitorQRCode.vue +99 -35
- package/components/ScheduleAreaMain.vue +34 -59
- package/components/ScheduleTaskForm.vue +61 -42
- package/components/ScheduleTaskMain.vue +56 -69
- package/components/SearchVehicleNumberUser.vue +39 -37
- package/components/ServiceProviderFormCreate.vue +29 -20
- package/components/ServiceProviderInvitationPrompt.vue +155 -0
- package/components/ServiceProviderMain.vue +601 -432
- package/components/Signature.vue +40 -34
- package/components/SignaturePad.vue +5 -29
- package/components/SiteSettings.vue +41 -11
- package/components/SiteSettingsWorkOrder.vue +61 -30
- package/components/SlideCardGroup.vue +35 -11
- package/components/Snackbar.vue +36 -3
- package/components/SpecificAttr.vue +18 -8
- package/components/StatusChip.vue +156 -0
- package/components/StockCard.vue +17 -12
- package/components/SubscriptionPlanTable.vue +207 -140
- package/components/SwitchContext.vue +201 -9
- package/components/TableHygiene.vue +36 -46
- package/components/TableList.vue +10 -10
- package/components/TableListSecondary.vue +105 -54
- package/components/TableMain.vue +251 -78
- package/components/TableV3.vue +61 -70
- package/components/TiptapEditor.vue +33 -40
- package/components/TiptapEditorQr.vue +5 -2
- package/components/Tooltip/Info.vue +69 -24
- package/components/UnitMain.vue +40 -60
- package/components/UnitPersonCard.vue +42 -13
- package/components/VehicleAddSelection.vue +48 -32
- package/components/VehicleForm.vue +112 -129
- package/components/VehicleManagement.vue +26 -12
- package/components/VehicleUpdateMoreAction.vue +59 -46
- package/components/VisitorDataFromScannedQRCodeForm.vue +90 -65
- package/components/VisitorForm.vue +774 -210
- package/components/VisitorFormSelection.vue +40 -37
- package/components/VisitorManagement.vue +239 -82
- package/components/VisitorPassKeyQRScanner.vue +65 -18
- package/components/VisitorSearchResultSummary.vue +60 -16
- package/components/VisitorSocketPopUp.vue +22 -14
- package/components/VisitorsReportPreview.vue +44 -29
- package/components/WorkOrder/Create.vue +26 -17
- package/components/WorkOrder/ListView.vue +38 -7
- package/components/WorkOrder/Main.vue +62 -59
- package/composables/useFeedback.ts +3 -3
- package/composables/useHidAmico.ts +269 -0
- package/composables/useHidNavigation.ts +2 -9
- package/composables/useMember.ts +3 -3
- package/composables/useNFCPatrolDailyReport.ts +13 -0
- package/composables/useNFCPatrolMonthlyReport.ts +22 -56
- package/composables/useNFCPatrolReport.ts +13 -0
- package/composables/useNotificationPreference.ts +87 -0
- package/composables/useOnlineFormPages.ts +2 -0
- package/composables/useRole.ts +22 -0
- package/composables/useServiceProvider.ts +3 -3
- package/composables/useServiceProviderInvitation.ts +145 -0
- package/composables/useSipWebPhone.ts +336 -0
- package/composables/useSubscriptionPlan.ts +62 -0
- package/composables/useThemePreference.ts +63 -0
- package/composables/useVisitor.ts +6 -1
- package/composables/useWebUsb.ts +127 -37
- package/composables/useWorkOrder.ts +17 -3
- package/error.vue +30 -6
- package/nuxt.config.ts +36 -0
- package/package.json +25 -4
- package/pages/[org]/[site]/access-mgmt/administrator/index.vue +2 -2
- package/pages/[org]/[site]/access-mgmt/{identity-mapping → hid-cards}/index.vue +2 -2
- package/pages/[org]/[site]/access-mgmt/intercom/index.vue +1 -1
- package/pages/notification-settings.vue +19 -0
- package/pages/payment-method-linked.vue +34 -10
- package/pages/require-customer.vue +48 -10
- package/pages/require-organization-membership.vue +32 -8
- package/pages/unauthorized.vue +29 -4
- package/plugins/secure-member.client.ts +21 -56
- package/plugins/vuetify.ts +69 -2
- package/types/nfc-patrol-report.ts +3 -2
- package/types/site.d.ts +71 -0
- package/types/subscription.ts +18 -11
- package/utils/breadcrumb.test.ts +108 -0
- package/utils/breadcrumb.ts +82 -0
- package/utils/dashboard.test.ts +118 -0
- package/utils/dashboard.ts +53 -0
- package/utils/data.test.ts +95 -0
- package/utils/data.ts +40 -2
- package/utils/hid-discover.test.ts +102 -0
- package/utils/list-page.test.ts +60 -0
- package/utils/list-page.ts +38 -0
- package/utils/materialSymbols.ts +363 -0
- package/utils/nav-sections.test.ts +190 -0
- package/utils/nav-sections.ts +151 -0
- package/utils/nfc-patrol-report.test.ts +130 -0
- package/utils/nfc-patrol-report.ts +101 -0
- package/utils/role.test.ts +69 -0
- package/utils/role.ts +10 -0
- package/utils/route-name.test.ts +85 -0
- package/utils/route-name.ts +24 -0
- package/utils/status.test.ts +110 -0
- package/utils/status.ts +135 -0
- package/utils/table-card.test.ts +84 -0
- package/utils/theme-aa-ledger.ts +148 -0
- package/utils/theme.test.ts +485 -7
- package/utils/theme.ts +295 -110
- package/.changeset/README.md +0 -8
- package/.changeset/config.json +0 -11
- package/.editorconfig +0 -12
- package/.github/workflows/main.yml +0 -17
- package/.github/workflows/publish-staging.yml +0 -47
- package/.github/workflows/publish.yml +0 -39
- package/PUBLISHING.md +0 -269
- package/components/HidIdentityMapping.vue +0 -975
- package/components/ScheduleTaskAreaFormDialog.vue +0 -144
- package/components/ScheduleTaskAreaUpdateMoreAction.vue +0 -109
- package/components/ScheduleTastTicketMain.vue +0 -182
- package/components/TableWithButton.vue +0 -94
- package/test/visitor-socket.test.mjs +0 -36
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-dialog
|
|
3
|
+
:model-value="modelValue"
|
|
4
|
+
max-width="520"
|
|
5
|
+
persistent
|
|
6
|
+
@update:model-value="emit('update:modelValue', $event)"
|
|
7
|
+
>
|
|
8
|
+
<!-- `rounded="lg"` is dropped, not replaced. Measured on the glass, the card
|
|
9
|
+
read 16px BEFORE and after: the `.rounded-lg` utility it compiled to was
|
|
10
|
+
already being overridden, so the prop stated a radius the card never
|
|
11
|
+
had. `.screen-modal` states the same 16px as `--r-modal`, on purpose. -->
|
|
12
|
+
<v-card class="camera-dialog screen-modal">
|
|
13
|
+
<v-card-title class="d-flex align-center justify-space-between">
|
|
14
|
+
<span>Take Facial Photo</span>
|
|
15
|
+
<v-btn
|
|
16
|
+
icon="mdi-close"
|
|
17
|
+
variant="text"
|
|
18
|
+
class="screen-modal__close"
|
|
19
|
+
aria-label="Close camera"
|
|
20
|
+
@click="close"
|
|
21
|
+
/>
|
|
22
|
+
</v-card-title>
|
|
23
|
+
|
|
24
|
+
<v-card-text class="screen-modal__body">
|
|
25
|
+
<div class="camera-viewport">
|
|
26
|
+
<video
|
|
27
|
+
ref="videoElement"
|
|
28
|
+
class="camera-preview"
|
|
29
|
+
autoplay
|
|
30
|
+
muted
|
|
31
|
+
playsinline
|
|
32
|
+
/>
|
|
33
|
+
|
|
34
|
+
<div v-if="starting" class="camera-state">
|
|
35
|
+
<v-progress-circular indeterminate color="primary" />
|
|
36
|
+
<span class="mt-3">Starting camera...</span>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<div v-else-if="cameraError" class="camera-state px-6 text-center">
|
|
40
|
+
<v-icon icon="mdi-camera-off-outline" size="42" color="error" />
|
|
41
|
+
<span class="mt-3 text-error">{{ cameraError }}</span>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<canvas ref="canvasElement" class="d-none" />
|
|
46
|
+
|
|
47
|
+
<div class="camera-dialog__hint text-center">
|
|
48
|
+
Keep your face centered and make sure the area is well lit.
|
|
49
|
+
</div>
|
|
50
|
+
</v-card-text>
|
|
51
|
+
|
|
52
|
+
<!-- `color="primary"` on a `v-btn` is the design's FOREGROUND token - the
|
|
53
|
+
link ink - not a fill, so the capture button was accent-on-accent.
|
|
54
|
+
`.screen-btn-primary` states the fill the design does draw. -->
|
|
55
|
+
<div class="screen-modal__footer">
|
|
56
|
+
<v-btn class="text-none screen-btn-ghost" variant="flat" @click="close">
|
|
57
|
+
Cancel
|
|
58
|
+
</v-btn>
|
|
59
|
+
<v-btn
|
|
60
|
+
class="text-none screen-btn-primary"
|
|
61
|
+
variant="flat"
|
|
62
|
+
prepend-icon="mdi-camera"
|
|
63
|
+
:disabled="starting || !!cameraError || !stream"
|
|
64
|
+
@click="capture"
|
|
65
|
+
>
|
|
66
|
+
Take Photo
|
|
67
|
+
</v-btn>
|
|
68
|
+
</div>
|
|
69
|
+
</v-card>
|
|
70
|
+
</v-dialog>
|
|
71
|
+
</template>
|
|
72
|
+
|
|
73
|
+
<script setup lang="ts">
|
|
74
|
+
const props = defineProps<{ modelValue: boolean }>();
|
|
75
|
+
const emit = defineEmits<{
|
|
76
|
+
"update:modelValue": [value: boolean];
|
|
77
|
+
capture: [dataUrl: string];
|
|
78
|
+
}>();
|
|
79
|
+
|
|
80
|
+
const videoElement = ref<HTMLVideoElement | null>(null);
|
|
81
|
+
const canvasElement = ref<HTMLCanvasElement | null>(null);
|
|
82
|
+
const stream = shallowRef<MediaStream | null>(null);
|
|
83
|
+
const starting = ref(false);
|
|
84
|
+
const cameraError = ref("");
|
|
85
|
+
|
|
86
|
+
function stopCamera() {
|
|
87
|
+
stream.value?.getTracks().forEach((track) => track.stop());
|
|
88
|
+
stream.value = null;
|
|
89
|
+
if (videoElement.value) videoElement.value.srcObject = null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function getCameraErrorMessage(caught: unknown) {
|
|
93
|
+
if (caught instanceof DOMException) {
|
|
94
|
+
if (caught.name === "NotAllowedError") {
|
|
95
|
+
return "Camera permission was denied. Allow camera access and try again.";
|
|
96
|
+
}
|
|
97
|
+
if (caught.name === "NotFoundError") {
|
|
98
|
+
return "No camera was found on this device.";
|
|
99
|
+
}
|
|
100
|
+
if (caught.name === "NotReadableError") {
|
|
101
|
+
return "The camera is currently being used by another application.";
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return "Unable to open the camera. Use HTTPS or check the browser camera permission.";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function startCamera() {
|
|
108
|
+
stopCamera();
|
|
109
|
+
cameraError.value = "";
|
|
110
|
+
starting.value = true;
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
if (!navigator.mediaDevices?.getUserMedia) {
|
|
114
|
+
throw new Error("Camera API is unavailable");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
stream.value = await navigator.mediaDevices.getUserMedia({
|
|
118
|
+
audio: false,
|
|
119
|
+
video: {
|
|
120
|
+
facingMode: "user",
|
|
121
|
+
width: { ideal: 1280 },
|
|
122
|
+
height: { ideal: 960 },
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
await nextTick();
|
|
127
|
+
if (!videoElement.value) throw new Error("Camera preview is unavailable");
|
|
128
|
+
videoElement.value.srcObject = stream.value;
|
|
129
|
+
await videoElement.value.play();
|
|
130
|
+
} catch (caught: unknown) {
|
|
131
|
+
stopCamera();
|
|
132
|
+
cameraError.value = getCameraErrorMessage(caught);
|
|
133
|
+
} finally {
|
|
134
|
+
starting.value = false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function capture() {
|
|
139
|
+
const video = videoElement.value;
|
|
140
|
+
const canvas = canvasElement.value;
|
|
141
|
+
if (!video || !canvas || !video.videoWidth || !video.videoHeight) return;
|
|
142
|
+
|
|
143
|
+
canvas.width = video.videoWidth;
|
|
144
|
+
canvas.height = video.videoHeight;
|
|
145
|
+
const context = canvas.getContext("2d");
|
|
146
|
+
if (!context) return;
|
|
147
|
+
|
|
148
|
+
context.translate(canvas.width, 0);
|
|
149
|
+
context.scale(-1, 1);
|
|
150
|
+
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
151
|
+
|
|
152
|
+
emit("capture", canvas.toDataURL("image/jpeg", 0.9));
|
|
153
|
+
close();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function close() {
|
|
157
|
+
stopCamera();
|
|
158
|
+
emit("update:modelValue", false);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
watch(
|
|
162
|
+
() => props.modelValue,
|
|
163
|
+
(isOpen) => {
|
|
164
|
+
if (isOpen) void startCamera();
|
|
165
|
+
else stopCamera();
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
onBeforeUnmount(stopCamera);
|
|
170
|
+
</script>
|
|
171
|
+
|
|
172
|
+
<style scoped>
|
|
173
|
+
.camera-dialog {
|
|
174
|
+
overflow: hidden;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.camera-viewport {
|
|
178
|
+
position: relative;
|
|
179
|
+
width: 100%;
|
|
180
|
+
overflow: hidden;
|
|
181
|
+
aspect-ratio: 3 / 4;
|
|
182
|
+
border-radius: var(--r-inner);
|
|
183
|
+
/* Deliberately NOT a theme surface: this is the stage a video sits on, and it
|
|
184
|
+
stays dark in both themes so the preview does not flash white on light.
|
|
185
|
+
Its own `#ffffff` text below is paired with it, not with the theme. */
|
|
186
|
+
background: #111722;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* The design's small helper line, not Vuetify's `text-caption` /
|
|
190
|
+
`text-medium-emphasis` pair. */
|
|
191
|
+
.camera-dialog__hint {
|
|
192
|
+
margin-top: 12px;
|
|
193
|
+
font-family: var(--font-sans);
|
|
194
|
+
font-size: var(--fs-cell);
|
|
195
|
+
font-weight: 500;
|
|
196
|
+
color: var(--muted);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.camera-preview {
|
|
200
|
+
width: 100%;
|
|
201
|
+
height: 100%;
|
|
202
|
+
object-fit: cover;
|
|
203
|
+
transform: scaleX(-1);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.camera-state {
|
|
207
|
+
position: absolute;
|
|
208
|
+
inset: 0;
|
|
209
|
+
display: flex;
|
|
210
|
+
flex-direction: column;
|
|
211
|
+
align-items: center;
|
|
212
|
+
justify-content: center;
|
|
213
|
+
background: #111722;
|
|
214
|
+
color: #ffffff;
|
|
215
|
+
}
|
|
216
|
+
</style>
|
|
@@ -1,14 +1,31 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The gate that stands in for a whole screen when HID is not enabled for a site.
|
|
3
|
+
|
|
4
|
+
What it was: a raw `v-alert type="info" variant="tonal"` — Vuetify's own tonal
|
|
5
|
+
slab, at Vuetify's 4px radius, in Vuetify's font, on a Vuetify blue the theme
|
|
6
|
+
does not control. It is a full-screen state, not an inline warning.
|
|
7
|
+
|
|
8
|
+
DESIGN GAP, STATED: the handoff draws no "service not enabled" page. So this
|
|
9
|
+
is assembled from the established primitive rather than invented, exactly as
|
|
10
|
+
`PlaceholderComponent` was — `.screen-empty` (`assets/css/screens.css:149`) is
|
|
11
|
+
the design's centred, muted, 52px-padded block for "there is nothing to show
|
|
12
|
+
here", and the heading takes the `--fs-card-title` / `--fw-card-title` type
|
|
13
|
+
the design uses for every panel heading.
|
|
14
|
+
|
|
15
|
+
`.tone-info` sets `--tone-bg`; the icon's soft disc is the only thing that
|
|
16
|
+
paints with it, so the block keeps the informational colour without becoming
|
|
17
|
+
a coloured slab. Icons are translated centrally — no hand-mapping here.
|
|
18
|
+
-->
|
|
1
19
|
<template>
|
|
2
20
|
<slot v-if="hidEnabled" />
|
|
3
21
|
|
|
4
|
-
<v-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class="
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
/>
|
|
22
|
+
<div v-else class="screen-empty hid-gate">
|
|
23
|
+
<span class="hid-gate__icon tone-info">
|
|
24
|
+
<v-icon icon="mdi-information-outline" size="24" />
|
|
25
|
+
</span>
|
|
26
|
+
<h2 class="hid-gate__title">HID service is not enabled</h2>
|
|
27
|
+
<p class="hid-gate__body">{{ message }}</p>
|
|
28
|
+
</div>
|
|
12
29
|
</template>
|
|
13
30
|
|
|
14
31
|
<script setup lang="ts">
|
|
@@ -28,7 +45,11 @@ const props = withDefaults(
|
|
|
28
45
|
const { getSiteById } = useSiteSettings();
|
|
29
46
|
const { getHidServiceEnabled } = useOptionalServices();
|
|
30
47
|
|
|
31
|
-
|
|
48
|
+
// Do not await this request during route setup. Every HID page uses this gate;
|
|
49
|
+
// awaiting it makes Nuxt Suspense keep rendering the previous page until the
|
|
50
|
+
// site request finishes, so the URL changes while the visible module appears
|
|
51
|
+
// frozen. The lazy request updates `siteData` reactively after navigation.
|
|
52
|
+
const { data: siteData } = useLazyAsyncData(
|
|
32
53
|
"hid-enabled-gate-site-" + props.site,
|
|
33
54
|
() => getSiteById(props.site),
|
|
34
55
|
{
|
|
@@ -49,3 +70,40 @@ watchEffect(() => {
|
|
|
49
70
|
);
|
|
50
71
|
});
|
|
51
72
|
</script>
|
|
73
|
+
|
|
74
|
+
<style scoped>
|
|
75
|
+
/* It replaces a screen's whole body, so it holds the viewport rather than
|
|
76
|
+
collapsing to the height of three lines. Same reason as PlaceholderComponent. */
|
|
77
|
+
.hid-gate {
|
|
78
|
+
min-height: 40vh;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.hid-gate__icon {
|
|
82
|
+
display: inline-flex;
|
|
83
|
+
align-items: center;
|
|
84
|
+
justify-content: center;
|
|
85
|
+
width: 44px;
|
|
86
|
+
height: 44px;
|
|
87
|
+
border-radius: 50%;
|
|
88
|
+
background: var(--tone-bg);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* `.screen-empty .v-icon` paints `--muted`; inside the tone scope the icon is
|
|
92
|
+
the informational colour, so it has to win that one-class rule. */
|
|
93
|
+
.hid-gate .hid-gate__icon .v-icon {
|
|
94
|
+
color: var(--info);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.hid-gate__title {
|
|
98
|
+
margin: 0;
|
|
99
|
+
font-size: var(--fs-card-title);
|
|
100
|
+
font-weight: var(--fw-card-title);
|
|
101
|
+
color: var(--text);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.hid-gate__body {
|
|
105
|
+
max-width: 46ch;
|
|
106
|
+
margin: 0;
|
|
107
|
+
font-weight: var(--fw-cell);
|
|
108
|
+
}
|
|
109
|
+
</style>
|