@quvel-kit/core 1.1.0 → 1.3.0
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/package.json +2 -11
- package/dist/components/Common/TaskErrors.vue +0 -47
- package/dist/components/Inputs/BaseInput.vue +0 -88
- package/dist/components/Misc/ClientOnly.vue +0 -22
- package/dist/components/Transitions/FadeInOut.vue +0 -9
- package/dist/components/Transitions/SlowExpand.vue +0 -13
- package/dist/components/WebSocketChannelManager.vue +0 -634
- package/dist/components/index.d.ts +0 -12
- package/dist/components/index.d.ts.map +0 -1
- package/dist/components/index.js +0 -16
- package/dist/pages/ErrorNotFound.vue +0 -300
- package/dist/pages/index.d.ts +0 -7
- package/dist/pages/index.d.ts.map +0 -1
- package/dist/pages/index.js +0 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quvel-kit/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Core utilities for Quvel UI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -39,14 +39,6 @@
|
|
|
39
39
|
"import": "./dist/composables/index.js",
|
|
40
40
|
"types": "./dist/composables/index.d.ts"
|
|
41
41
|
},
|
|
42
|
-
"./components": {
|
|
43
|
-
"import": "./dist/components/index.js",
|
|
44
|
-
"types": "./dist/components/index.d.ts"
|
|
45
|
-
},
|
|
46
|
-
"./pages": {
|
|
47
|
-
"import": "./dist/pages/index.js",
|
|
48
|
-
"types": "./dist/pages/index.d.ts"
|
|
49
|
-
},
|
|
50
42
|
"./global": {
|
|
51
43
|
"types": "./global.d.ts"
|
|
52
44
|
}
|
|
@@ -57,8 +49,7 @@
|
|
|
57
49
|
"README.md"
|
|
58
50
|
],
|
|
59
51
|
"scripts": {
|
|
60
|
-
"build": "tsc && npm run copy-
|
|
61
|
-
"copy-vue": "rsync -a --include='*/' --include='*.vue' --exclude='*' src/ dist/",
|
|
52
|
+
"build": "tsc && npm run copy-ambient-types",
|
|
62
53
|
"copy-ambient-types": "rsync -a --include='*/' --include='vue.d.ts' --include='global.d.ts' --include='ssr.d.ts' --include='vue-shim.d.ts' --include='pinia.d.ts' --exclude='*' src/ dist/",
|
|
63
54
|
"dev": "tsc --watch",
|
|
64
55
|
"clean": "rm -rf dist",
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
/**
|
|
3
|
-
* TaskErrors.vue
|
|
4
|
-
*
|
|
5
|
-
* A component to display errors from a task.
|
|
6
|
-
*
|
|
7
|
-
* Props:
|
|
8
|
-
* - `taskErrors`: The errors from a task, including the main error and additional errors.
|
|
9
|
-
*/
|
|
10
|
-
import { computed } from 'vue';
|
|
11
|
-
import FadeInOut from '../Transitions/FadeInOut.vue';
|
|
12
|
-
import type { ErrorBag } from '../../types/laravel.types.js';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Props for the component.
|
|
16
|
-
*/
|
|
17
|
-
const props = defineProps({
|
|
18
|
-
taskErrors: {
|
|
19
|
-
type: Object as () => ErrorBag,
|
|
20
|
-
default: () => ({ message: '', errors: {} }),
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Extracts the most relevant error message.
|
|
26
|
-
* - If `message` is already inside `errors`, we ignore `message` to prevent duplication.
|
|
27
|
-
* - If `errors` exist, extract the first error.
|
|
28
|
-
* - Otherwise, fallback to `message`.
|
|
29
|
-
*/
|
|
30
|
-
const errorMessage = computed(() => {
|
|
31
|
-
const { taskErrors } = props;
|
|
32
|
-
|
|
33
|
-
// Get the first available error from `taskErrors`
|
|
34
|
-
const firstError = Array.from(taskErrors.values())[0];
|
|
35
|
-
|
|
36
|
-
// If firstError exists, use it. Otherwise, fallback to message.
|
|
37
|
-
return firstError || taskErrors.get('message') || '';
|
|
38
|
-
});
|
|
39
|
-
</script>
|
|
40
|
-
|
|
41
|
-
<template>
|
|
42
|
-
<FadeInOut>
|
|
43
|
-
<q-banner v-if="errorMessage" class="bg-negative text-white" dense rounded>
|
|
44
|
-
{{ errorMessage }}
|
|
45
|
-
</q-banner>
|
|
46
|
-
</FadeInOut>
|
|
47
|
-
</template>
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import { computed } from 'vue';
|
|
3
|
-
import type { ZodSchema } from 'zod/v4';
|
|
4
|
-
import { useQuvel } from '@quvel-kit/core/composables';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Props - Only custom props, everything else forwarded via $attrs
|
|
8
|
-
*/
|
|
9
|
-
const props = defineProps({
|
|
10
|
-
modelValue: {
|
|
11
|
-
type: String,
|
|
12
|
-
required: true,
|
|
13
|
-
},
|
|
14
|
-
schema: {
|
|
15
|
-
type: Object as () => ZodSchema<string> | undefined,
|
|
16
|
-
default: undefined,
|
|
17
|
-
},
|
|
18
|
-
rules: {
|
|
19
|
-
type: Array as () => ((val: string) => true | string)[],
|
|
20
|
-
default: () => [],
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Emits
|
|
26
|
-
*/
|
|
27
|
-
const emits = defineEmits(['update:modelValue']);
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Services
|
|
31
|
-
*/
|
|
32
|
-
const { validation } = useQuvel();
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Computed Property for Model Binding
|
|
36
|
-
*/
|
|
37
|
-
const inputValue = computed({
|
|
38
|
-
get: () => props.modelValue,
|
|
39
|
-
set: (value) => emits('update:modelValue', value),
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Computed Property for Validation Rules
|
|
44
|
-
* - If `schema` is provided, use Zod v4 validation with built-in locales
|
|
45
|
-
* - Otherwise, use the provided `rules` array
|
|
46
|
-
*/
|
|
47
|
-
const computedRules = computed(() => {
|
|
48
|
-
return props.schema
|
|
49
|
-
? [validation.createInputRule(props.schema)]
|
|
50
|
-
: props.rules;
|
|
51
|
-
});
|
|
52
|
-
</script>
|
|
53
|
-
|
|
54
|
-
<template>
|
|
55
|
-
<q-input
|
|
56
|
-
v-model="inputValue"
|
|
57
|
-
v-bind="$attrs"
|
|
58
|
-
lazy-rules
|
|
59
|
-
outlined
|
|
60
|
-
:rules="computedRules"
|
|
61
|
-
>
|
|
62
|
-
<!-- Forward all QInput slots -->
|
|
63
|
-
<template v-if="$slots.prepend" #prepend>
|
|
64
|
-
<slot name="prepend" />
|
|
65
|
-
</template>
|
|
66
|
-
<template v-if="$slots.append" #append>
|
|
67
|
-
<slot name="append" />
|
|
68
|
-
</template>
|
|
69
|
-
<template v-if="$slots.before" #before>
|
|
70
|
-
<slot name="before" />
|
|
71
|
-
</template>
|
|
72
|
-
<template v-if="$slots.after" #after>
|
|
73
|
-
<slot name="after" />
|
|
74
|
-
</template>
|
|
75
|
-
<template v-if="$slots.error" #error>
|
|
76
|
-
<slot name="error" />
|
|
77
|
-
</template>
|
|
78
|
-
<template v-if="$slots.hint" #hint>
|
|
79
|
-
<slot name="hint" />
|
|
80
|
-
</template>
|
|
81
|
-
<template v-if="$slots.counter" #counter>
|
|
82
|
-
<slot name="counter" />
|
|
83
|
-
</template>
|
|
84
|
-
<template v-if="$slots.loading" #loading>
|
|
85
|
-
<slot name="loading" />
|
|
86
|
-
</template>
|
|
87
|
-
</q-input>
|
|
88
|
-
</template>
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import { useClient } from '@quvel-kit/core/composables';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* ClientOnly component
|
|
6
|
-
*
|
|
7
|
-
* Renders its slot content only on the client-side after hydration.
|
|
8
|
-
* Prevents hydration mismatches for components that rely on browser-only APIs.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const { isClient } = useClient();
|
|
12
|
-
</script>
|
|
13
|
-
|
|
14
|
-
<template>
|
|
15
|
-
<template v-if="isClient">
|
|
16
|
-
<slot />
|
|
17
|
-
</template>
|
|
18
|
-
|
|
19
|
-
<template v-else>
|
|
20
|
-
<slot name="fallback" />
|
|
21
|
-
</template>
|
|
22
|
-
</template>
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<!--
|
|
3
|
-
This transition gives a "growing" effect to the parent container.
|
|
4
|
-
A great use case is dynamic form fields on a vertical form. The form doesn't
|
|
5
|
-
just flash into its new size, offering a more aesthetically pleasing effect.
|
|
6
|
-
-->
|
|
7
|
-
<transition
|
|
8
|
-
name="slow-expand"
|
|
9
|
-
appear
|
|
10
|
-
>
|
|
11
|
-
<slot />
|
|
12
|
-
</transition>
|
|
13
|
-
</template>
|
|
@@ -1,634 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { defineComponent, ref, computed, onBeforeUnmount, nextTick, onMounted } from 'vue';
|
|
3
|
-
import { useWebSockets } from '../composables/useWebSockets';
|
|
4
|
-
import { WebSocketChannelType, SubscribeOptions } from '../types/websocket.types';
|
|
5
|
-
import { PublicChannelType, PrivateChannelType, PresenceChannelType, EncryptedChannelType } from '../types/websocket.types';
|
|
6
|
-
import { QScrollArea } from 'quasar';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
type AnyChannel = PublicChannelType | PrivateChannelType | PresenceChannelType | EncryptedChannelType;
|
|
10
|
-
|
|
11
|
-
interface ChannelConfig {
|
|
12
|
-
name: string;
|
|
13
|
-
type: WebSocketChannelType;
|
|
14
|
-
event?: string | undefined;
|
|
15
|
-
channel: AnyChannel;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface MessageLog {
|
|
19
|
-
channelName: string;
|
|
20
|
-
channelType: WebSocketChannelType;
|
|
21
|
-
event: string;
|
|
22
|
-
data: unknown;
|
|
23
|
-
timestamp: Date;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export default defineComponent({
|
|
27
|
-
name: 'WebSocketChannelManager',
|
|
28
|
-
|
|
29
|
-
setup() {
|
|
30
|
-
// WebSocket connection management
|
|
31
|
-
const { subscribe, unsubscribe } = useWebSockets();
|
|
32
|
-
|
|
33
|
-
// Dialog visibility control
|
|
34
|
-
const isDialogOpen = ref(false);
|
|
35
|
-
const isVisible = computed(() => isDialogOpen.value);
|
|
36
|
-
|
|
37
|
-
// Selected channel for filtering messages
|
|
38
|
-
const selectedChannelIndex = ref<number | null>(null);
|
|
39
|
-
|
|
40
|
-
// Register global methods to show/hide the component
|
|
41
|
-
onMounted(() => {
|
|
42
|
-
(window as unknown as { showWebSocketManager: () => void }).showWebSocketManager = () => {
|
|
43
|
-
isDialogOpen.value = true;
|
|
44
|
-
|
|
45
|
-
console.log('WebSocket Inspector is now open');
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
(window as unknown as { hideWebSocketManager: () => void }).hideWebSocketManager = () => {
|
|
49
|
-
hideManager();
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// Log instructions to console
|
|
53
|
-
console.info(
|
|
54
|
-
'%cWebSocket Inspector available!',
|
|
55
|
-
'color: #4CAF50; font-weight: bold; font-size: 14px;'
|
|
56
|
-
);
|
|
57
|
-
console.info(
|
|
58
|
-
'%cUse window.showWebSocketManager() to show the inspector',
|
|
59
|
-
'color: #2196F3; font-size: 12px;'
|
|
60
|
-
);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// Hide the manager and clean up
|
|
64
|
-
const hideManager = () => {
|
|
65
|
-
isDialogOpen.value = false;
|
|
66
|
-
console.log('WebSocket Inspector is now closed');
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
// Select a channel to filter messages
|
|
70
|
-
const selectChannel = (index: number) => {
|
|
71
|
-
selectedChannelIndex.value = selectedChannelIndex.value === index ? null : index;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// Active channels
|
|
75
|
-
const activeChannels = ref<ChannelConfig[]>([]);
|
|
76
|
-
|
|
77
|
-
// Connection status
|
|
78
|
-
const connectionStatus = computed(() => {
|
|
79
|
-
const isConnected = activeChannels.value.length > 0;
|
|
80
|
-
return {
|
|
81
|
-
label: isConnected ? 'Connected' : 'Disconnected',
|
|
82
|
-
color: isConnected ? 'positive' : 'negative'
|
|
83
|
-
};
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
// Channel form
|
|
87
|
-
// Channel form with partial type to allow initialization without a channel
|
|
88
|
-
const newChannel = ref<Omit<ChannelConfig, 'channel'> & { channel?: AnyChannel }>({
|
|
89
|
-
name: '',
|
|
90
|
-
type: 'public',
|
|
91
|
-
event: ''
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
const isAddingChannel = ref(false);
|
|
95
|
-
|
|
96
|
-
// Available channel types
|
|
97
|
-
const channelTypes = [
|
|
98
|
-
{ label: 'Public', value: 'public' },
|
|
99
|
-
{ label: 'Private', value: 'private' },
|
|
100
|
-
{ label: 'Presence', value: 'presence' },
|
|
101
|
-
{ label: 'Encrypted', value: 'encrypted' },
|
|
102
|
-
{ label: 'Public Notification', value: 'publicNotification' },
|
|
103
|
-
{ label: 'Private Notification', value: 'privateNotification' }
|
|
104
|
-
];
|
|
105
|
-
|
|
106
|
-
// Message log
|
|
107
|
-
const messages = ref<MessageLog[]>([]);
|
|
108
|
-
const messageLogRef = ref<QScrollArea | null>(null);
|
|
109
|
-
|
|
110
|
-
// Filtered messages based on selected channel
|
|
111
|
-
const filteredMessages = computed(() => {
|
|
112
|
-
if (selectedChannelIndex.value === null) {
|
|
113
|
-
return messages.value;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const selectedChannel = activeChannels.value[selectedChannelIndex.value];
|
|
117
|
-
return messages.value.filter(msg =>
|
|
118
|
-
msg.channelName === selectedChannel?.name &&
|
|
119
|
-
msg.channelType === selectedChannel?.type
|
|
120
|
-
);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// Add a new channel
|
|
124
|
-
const addChannel = async () => {
|
|
125
|
-
try {
|
|
126
|
-
isAddingChannel.value = true;
|
|
127
|
-
|
|
128
|
-
// Create channel options
|
|
129
|
-
const options: SubscribeOptions<unknown> = {
|
|
130
|
-
channelName: newChannel.value.name,
|
|
131
|
-
type: newChannel.value.type,
|
|
132
|
-
// Only include event if it's defined
|
|
133
|
-
...(newChannel.value.event ? { event: newChannel.value.event } : {}),
|
|
134
|
-
callback: (data: unknown) => {
|
|
135
|
-
// Log the message
|
|
136
|
-
messages.value.push({
|
|
137
|
-
channelName: newChannel.value.name,
|
|
138
|
-
channelType: newChannel.value.type,
|
|
139
|
-
event: newChannel.value.event || 'notification',
|
|
140
|
-
data,
|
|
141
|
-
timestamp: new Date(),
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
// Scroll to bottom of message log
|
|
145
|
-
void nextTick(() => {
|
|
146
|
-
if (messageLogRef.value) {
|
|
147
|
-
messageLogRef.value.setScrollPosition('vertical', 999999);
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
},
|
|
151
|
-
presenceHandlers: {
|
|
152
|
-
onListening: {
|
|
153
|
-
event: 'listening',
|
|
154
|
-
callback: () => {
|
|
155
|
-
messages.value.push({
|
|
156
|
-
channelName: newChannel.value.name,
|
|
157
|
-
channelType: newChannel.value.type,
|
|
158
|
-
event: newChannel.value.event || 'notification',
|
|
159
|
-
data: 'Listening',
|
|
160
|
-
timestamp: new Date(),
|
|
161
|
-
});
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
onHere: (members: Record<string, unknown>) => {
|
|
165
|
-
messages.value.push({
|
|
166
|
-
channelName: newChannel.value.name,
|
|
167
|
-
channelType: newChannel.value.type,
|
|
168
|
-
event: newChannel.value.event || 'notification',
|
|
169
|
-
data: members,
|
|
170
|
-
timestamp: new Date(),
|
|
171
|
-
});
|
|
172
|
-
},
|
|
173
|
-
onJoining: (member: Record<string, unknown>) => {
|
|
174
|
-
messages.value.push({
|
|
175
|
-
channelName: newChannel.value.name,
|
|
176
|
-
channelType: newChannel.value.type,
|
|
177
|
-
event: newChannel.value.event || 'notification',
|
|
178
|
-
data: member,
|
|
179
|
-
timestamp: new Date(),
|
|
180
|
-
});
|
|
181
|
-
},
|
|
182
|
-
onLeaving: (member: Record<string, unknown>) => {
|
|
183
|
-
messages.value.push({
|
|
184
|
-
channelName: newChannel.value.name,
|
|
185
|
-
channelType: newChannel.value.type,
|
|
186
|
-
event: newChannel.value.event || 'notification',
|
|
187
|
-
data: member,
|
|
188
|
-
timestamp: new Date(),
|
|
189
|
-
});
|
|
190
|
-
},
|
|
191
|
-
},
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
// Subscribe to the channel
|
|
195
|
-
const channel = await subscribe(options);
|
|
196
|
-
|
|
197
|
-
// Add to active channels
|
|
198
|
-
activeChannels.value.push({
|
|
199
|
-
name: newChannel.value.name,
|
|
200
|
-
type: newChannel.value.type,
|
|
201
|
-
event: newChannel.value.event || undefined,
|
|
202
|
-
channel
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
// Reset form
|
|
206
|
-
newChannel.value = {
|
|
207
|
-
name: '',
|
|
208
|
-
type: 'public',
|
|
209
|
-
event: ''
|
|
210
|
-
};
|
|
211
|
-
} catch (error) {
|
|
212
|
-
console.error('Failed to add channel:', error);
|
|
213
|
-
} finally {
|
|
214
|
-
isAddingChannel.value = false;
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
// Remove a channel
|
|
219
|
-
const removeChannel = (index: number) => {
|
|
220
|
-
const channel = activeChannels.value[index];
|
|
221
|
-
if (channel?.channel) {
|
|
222
|
-
unsubscribe(channel.channel as AnyChannel);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
activeChannels.value.splice(index, 1);
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
// Clear message log
|
|
229
|
-
const clearMessages = () => {
|
|
230
|
-
messages.value = [];
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
// Download logs as JSON
|
|
234
|
-
const downloadLogs = () => {
|
|
235
|
-
const data = JSON.stringify(messages.value, null, 2);
|
|
236
|
-
const blob = new Blob([data], { type: 'application/json' });
|
|
237
|
-
const url = URL.createObjectURL(blob);
|
|
238
|
-
const a = document.createElement('a');
|
|
239
|
-
a.href = url;
|
|
240
|
-
a.download = `websocket-logs-${new Date().toISOString()}.json`;
|
|
241
|
-
document.body.appendChild(a);
|
|
242
|
-
a.click();
|
|
243
|
-
document.body.removeChild(a);
|
|
244
|
-
URL.revokeObjectURL(url);
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
// Format timestamp
|
|
248
|
-
const formatTimestamp = (date: Date) => {
|
|
249
|
-
return date.toLocaleTimeString();
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
// Format message data for display
|
|
253
|
-
const formatMessageData = (data: unknown) => {
|
|
254
|
-
try {
|
|
255
|
-
return JSON.stringify(data, null, 2);
|
|
256
|
-
} catch {
|
|
257
|
-
return String(data);
|
|
258
|
-
}
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
// Get color for channel type
|
|
262
|
-
const getChannelTypeColor = (type: WebSocketChannelType) => {
|
|
263
|
-
switch (type) {
|
|
264
|
-
case 'public':
|
|
265
|
-
case 'publicNotification':
|
|
266
|
-
return 'teal';
|
|
267
|
-
case 'private':
|
|
268
|
-
case 'privateNotification':
|
|
269
|
-
return 'blue';
|
|
270
|
-
case 'presence':
|
|
271
|
-
return 'purple';
|
|
272
|
-
case 'encrypted':
|
|
273
|
-
return 'deep-orange';
|
|
274
|
-
default:
|
|
275
|
-
return 'grey';
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
// Clean up all channels when component unmounts
|
|
280
|
-
onBeforeUnmount(() => {
|
|
281
|
-
activeChannels.value.forEach(channelConfig => {
|
|
282
|
-
unsubscribe(channelConfig.channel as AnyChannel);
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
activeChannels.value = [];
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
return {
|
|
289
|
-
// Visibility control
|
|
290
|
-
isVisible,
|
|
291
|
-
isDialogOpen,
|
|
292
|
-
hideManager,
|
|
293
|
-
|
|
294
|
-
// Connection
|
|
295
|
-
connectionStatus,
|
|
296
|
-
|
|
297
|
-
// Channel form
|
|
298
|
-
newChannel,
|
|
299
|
-
channelTypes,
|
|
300
|
-
isAddingChannel,
|
|
301
|
-
addChannel,
|
|
302
|
-
|
|
303
|
-
// Active channels
|
|
304
|
-
activeChannels,
|
|
305
|
-
removeChannel,
|
|
306
|
-
getChannelTypeColor,
|
|
307
|
-
selectedChannelIndex,
|
|
308
|
-
selectChannel,
|
|
309
|
-
|
|
310
|
-
// Message log
|
|
311
|
-
messages,
|
|
312
|
-
filteredMessages,
|
|
313
|
-
messageLogRef,
|
|
314
|
-
clearMessages,
|
|
315
|
-
downloadLogs,
|
|
316
|
-
formatTimestamp,
|
|
317
|
-
formatMessageData
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
</script>
|
|
322
|
-
|
|
323
|
-
<template>
|
|
324
|
-
<q-dialog
|
|
325
|
-
v-model="isDialogOpen"
|
|
326
|
-
persistent
|
|
327
|
-
maximized
|
|
328
|
-
transition-show="slide-up"
|
|
329
|
-
transition-hide="slide-down"
|
|
330
|
-
>
|
|
331
|
-
<q-card class="websocket-channel-manager">
|
|
332
|
-
<q-card-section class="bg-dark text-white q-py-sm">
|
|
333
|
-
<div class="flex items-center justify-between">
|
|
334
|
-
<div class="flex items-center">
|
|
335
|
-
<q-icon
|
|
336
|
-
name="eva-wifi-outline"
|
|
337
|
-
size="md"
|
|
338
|
-
class="q-mr-sm"
|
|
339
|
-
/>
|
|
340
|
-
<h5 class="text-h6 q-my-none">WebSocket Inspector</h5>
|
|
341
|
-
</div>
|
|
342
|
-
<q-chip
|
|
343
|
-
:color="connectionStatus.color"
|
|
344
|
-
text-color="white"
|
|
345
|
-
size="sm"
|
|
346
|
-
outline
|
|
347
|
-
>
|
|
348
|
-
{{ connectionStatus.label }}
|
|
349
|
-
</q-chip>
|
|
350
|
-
|
|
351
|
-
<q-btn
|
|
352
|
-
flat
|
|
353
|
-
round
|
|
354
|
-
color="grey-5"
|
|
355
|
-
icon="eva-close-outline"
|
|
356
|
-
@click="hideManager"
|
|
357
|
-
/>
|
|
358
|
-
</div>
|
|
359
|
-
</q-card-section>
|
|
360
|
-
|
|
361
|
-
<q-card-section class="q-pa-md bg-dark-subtle">
|
|
362
|
-
<q-form
|
|
363
|
-
@submit="addChannel"
|
|
364
|
-
class="row q-col-gutter-sm items-end"
|
|
365
|
-
>
|
|
366
|
-
<div class="col-12 col-sm-4">
|
|
367
|
-
<q-input
|
|
368
|
-
v-model="newChannel.name"
|
|
369
|
-
label="Channel Name"
|
|
370
|
-
dense
|
|
371
|
-
filled
|
|
372
|
-
dark
|
|
373
|
-
class="bg-dark-page"
|
|
374
|
-
:rules="[val => !!val || 'Required']"
|
|
375
|
-
>
|
|
376
|
-
<template v-slot:prepend>
|
|
377
|
-
<q-icon name="eva-hash-outline" />
|
|
378
|
-
</template>
|
|
379
|
-
</q-input>
|
|
380
|
-
</div>
|
|
381
|
-
<div class="col-12 col-sm-3">
|
|
382
|
-
<q-select
|
|
383
|
-
v-model="newChannel.type"
|
|
384
|
-
:options="channelTypes"
|
|
385
|
-
:emit-value="true"
|
|
386
|
-
label="Channel Type"
|
|
387
|
-
dense
|
|
388
|
-
filled
|
|
389
|
-
dark
|
|
390
|
-
class="bg-dark-page"
|
|
391
|
-
:rules="[val => !!val || 'Required']"
|
|
392
|
-
>
|
|
393
|
-
<template v-slot:prepend>
|
|
394
|
-
<q-icon name="eva-eye-outline" />
|
|
395
|
-
</template>
|
|
396
|
-
</q-select>
|
|
397
|
-
</div>
|
|
398
|
-
<div class="col-12 col-sm-3">
|
|
399
|
-
<q-input
|
|
400
|
-
v-model="newChannel.event"
|
|
401
|
-
label="Event Name"
|
|
402
|
-
dense
|
|
403
|
-
filled
|
|
404
|
-
dark
|
|
405
|
-
class="bg-dark-page"
|
|
406
|
-
:rules="[val => newChannel.type !== 'presence' ? !!val || 'Required' : true]"
|
|
407
|
-
:disable="newChannel.type === 'presence'"
|
|
408
|
-
>
|
|
409
|
-
<template v-slot:prepend>
|
|
410
|
-
<q-icon name="eva-bell-outline" />
|
|
411
|
-
</template>
|
|
412
|
-
</q-input>
|
|
413
|
-
</div>
|
|
414
|
-
<div class="col-12 col-sm-2">
|
|
415
|
-
<q-btn
|
|
416
|
-
type="submit"
|
|
417
|
-
color="primary"
|
|
418
|
-
icon="eva-plus-outline"
|
|
419
|
-
label="Subscribe"
|
|
420
|
-
no-caps
|
|
421
|
-
unelevated
|
|
422
|
-
class="full-width"
|
|
423
|
-
:loading="isAddingChannel"
|
|
424
|
-
/>
|
|
425
|
-
</div>
|
|
426
|
-
</q-form>
|
|
427
|
-
</q-card-section>
|
|
428
|
-
|
|
429
|
-
<q-separator dark />
|
|
430
|
-
|
|
431
|
-
<q-card-section class="q-pa-none">
|
|
432
|
-
<div class="row">
|
|
433
|
-
<div class="col-12 col-md-3 bg-dark-subtle">
|
|
434
|
-
<q-card-section class="q-py-sm">
|
|
435
|
-
<div class="text-subtitle1 text-weight-medium flex items-center">
|
|
436
|
-
<q-icon
|
|
437
|
-
name="eva-hash-outline"
|
|
438
|
-
class="q-mr-xs"
|
|
439
|
-
/>
|
|
440
|
-
Active Channels
|
|
441
|
-
<q-badge
|
|
442
|
-
color="primary"
|
|
443
|
-
class="q-ml-sm"
|
|
444
|
-
>{{ activeChannels.length }}</q-badge>
|
|
445
|
-
</div>
|
|
446
|
-
</q-card-section>
|
|
447
|
-
|
|
448
|
-
<q-separator dark />
|
|
449
|
-
|
|
450
|
-
<q-list
|
|
451
|
-
dark
|
|
452
|
-
dense
|
|
453
|
-
class="channel-list"
|
|
454
|
-
>
|
|
455
|
-
<q-item
|
|
456
|
-
v-if="activeChannels.length === 0"
|
|
457
|
-
class="text-grey-6"
|
|
458
|
-
>
|
|
459
|
-
<q-item-section>
|
|
460
|
-
<q-item-label>No active channels</q-item-label>
|
|
461
|
-
<q-item-label caption>Add a channel to start listening</q-item-label>
|
|
462
|
-
</q-item-section>
|
|
463
|
-
</q-item>
|
|
464
|
-
|
|
465
|
-
<q-item
|
|
466
|
-
v-for="(channel, index) in activeChannels"
|
|
467
|
-
:key="index"
|
|
468
|
-
clickable
|
|
469
|
-
active-class="bg-primary text-white"
|
|
470
|
-
:active="selectedChannelIndex === index"
|
|
471
|
-
@click="selectChannel(index)"
|
|
472
|
-
>
|
|
473
|
-
<q-item-section avatar>
|
|
474
|
-
<q-icon
|
|
475
|
-
:color="getChannelTypeColor(channel.type)"
|
|
476
|
-
name="eva-radio-outline"
|
|
477
|
-
/>
|
|
478
|
-
</q-item-section>
|
|
479
|
-
|
|
480
|
-
<q-item-section>
|
|
481
|
-
<q-item-label lines="1">{{ channel.name }}</q-item-label>
|
|
482
|
-
<q-item-label caption>
|
|
483
|
-
<q-badge
|
|
484
|
-
:color="getChannelTypeColor(channel.type)"
|
|
485
|
-
text-color="white"
|
|
486
|
-
size="xs"
|
|
487
|
-
>
|
|
488
|
-
{{ channel.type }}
|
|
489
|
-
</q-badge>
|
|
490
|
-
<span
|
|
491
|
-
v-if="channel.event"
|
|
492
|
-
class="q-ml-xs"
|
|
493
|
-
>{{ channel.event }}</span>
|
|
494
|
-
</q-item-label>
|
|
495
|
-
</q-item-section>
|
|
496
|
-
|
|
497
|
-
<q-item-section side>
|
|
498
|
-
<q-btn
|
|
499
|
-
flat
|
|
500
|
-
round
|
|
501
|
-
dense
|
|
502
|
-
color="negative"
|
|
503
|
-
icon="eva-close-outline"
|
|
504
|
-
@click.stop="removeChannel(index)"
|
|
505
|
-
/>
|
|
506
|
-
</q-item-section>
|
|
507
|
-
</q-item>
|
|
508
|
-
</q-list>
|
|
509
|
-
</div>
|
|
510
|
-
|
|
511
|
-
<div class="col-12 col-md-9">
|
|
512
|
-
<q-card-section class="q-py-sm bg-dark-subtle">
|
|
513
|
-
<div class="row items-center justify-between">
|
|
514
|
-
<div class="text-subtitle1 text-weight-medium flex items-center">
|
|
515
|
-
<q-icon
|
|
516
|
-
name="eva-message-square-outline"
|
|
517
|
-
class="q-mr-xs"
|
|
518
|
-
/>
|
|
519
|
-
Message Log
|
|
520
|
-
<q-badge
|
|
521
|
-
color="secondary"
|
|
522
|
-
class="q-ml-sm"
|
|
523
|
-
>{{ filteredMessages.length }}</q-badge>
|
|
524
|
-
</div>
|
|
525
|
-
|
|
526
|
-
<div>
|
|
527
|
-
<q-btn
|
|
528
|
-
flat
|
|
529
|
-
round
|
|
530
|
-
dense
|
|
531
|
-
color="grey"
|
|
532
|
-
icon="eva-refresh-outline"
|
|
533
|
-
@click="clearMessages"
|
|
534
|
-
class="q-mr-xs"
|
|
535
|
-
>
|
|
536
|
-
<q-tooltip>Clear Messages</q-tooltip>
|
|
537
|
-
</q-btn>
|
|
538
|
-
<q-btn
|
|
539
|
-
flat
|
|
540
|
-
round
|
|
541
|
-
dense
|
|
542
|
-
color="grey"
|
|
543
|
-
icon="eva-download-outline"
|
|
544
|
-
@click="downloadLogs"
|
|
545
|
-
>
|
|
546
|
-
<q-tooltip>Download Logs</q-tooltip>
|
|
547
|
-
</q-btn>
|
|
548
|
-
</div>
|
|
549
|
-
</div>
|
|
550
|
-
</q-card-section>
|
|
551
|
-
|
|
552
|
-
<q-separator dark />
|
|
553
|
-
|
|
554
|
-
<q-scroll-area
|
|
555
|
-
style="height: calc(100vh - 280px);"
|
|
556
|
-
ref="messageLogRef"
|
|
557
|
-
class="bg-dark-page"
|
|
558
|
-
>
|
|
559
|
-
<div
|
|
560
|
-
v-if="filteredMessages.length === 0"
|
|
561
|
-
class="text-center q-pa-md text-grey-7"
|
|
562
|
-
>
|
|
563
|
-
<q-icon
|
|
564
|
-
name="eva-message-square-outline"
|
|
565
|
-
size="2rem"
|
|
566
|
-
/>
|
|
567
|
-
<div class="q-mt-sm">No messages received yet.</div>
|
|
568
|
-
</div>
|
|
569
|
-
|
|
570
|
-
<div
|
|
571
|
-
v-for="(message, index) in filteredMessages"
|
|
572
|
-
:key="index"
|
|
573
|
-
class="message-item q-pa-md q-my-sm"
|
|
574
|
-
>
|
|
575
|
-
<div class="flex items-center justify-between">
|
|
576
|
-
<div class="flex items-center">
|
|
577
|
-
<q-badge
|
|
578
|
-
:color="getChannelTypeColor(message.channelType)"
|
|
579
|
-
class="q-mr-sm"
|
|
580
|
-
>{{ message.channelType
|
|
581
|
-
}}</q-badge>
|
|
582
|
-
<div class="text-weight-medium">{{ message.channelName }}</div>
|
|
583
|
-
</div>
|
|
584
|
-
<div class="text-grey-7 text-caption">{{ formatTimestamp(message.timestamp) }}</div>
|
|
585
|
-
</div>
|
|
586
|
-
|
|
587
|
-
<div class="q-mt-xs">
|
|
588
|
-
<q-chip
|
|
589
|
-
size="sm"
|
|
590
|
-
outline
|
|
591
|
-
color="secondary"
|
|
592
|
-
class="q-mr-sm"
|
|
593
|
-
>{{ message.event }}</q-chip>
|
|
594
|
-
</div>
|
|
595
|
-
|
|
596
|
-
<q-card
|
|
597
|
-
flat
|
|
598
|
-
bordered
|
|
599
|
-
class="q-mt-sm bg-dark-subtle"
|
|
600
|
-
>
|
|
601
|
-
<q-card-section class="q-pa-sm">
|
|
602
|
-
<pre class="message-content text-grey-4">{{ formatMessageData(message.data) }}</pre>
|
|
603
|
-
</q-card-section>
|
|
604
|
-
</q-card>
|
|
605
|
-
</div>
|
|
606
|
-
</q-scroll-area>
|
|
607
|
-
</div>
|
|
608
|
-
</div>
|
|
609
|
-
</q-card-section>
|
|
610
|
-
</q-card>
|
|
611
|
-
</q-dialog>
|
|
612
|
-
</template>
|
|
613
|
-
|
|
614
|
-
<style lang="scss">
|
|
615
|
-
.websocket-channel-manager {
|
|
616
|
-
width: 100%;
|
|
617
|
-
height: 100%;
|
|
618
|
-
display: flex;
|
|
619
|
-
flex-direction: column;
|
|
620
|
-
background-color: #1e1e1e;
|
|
621
|
-
color: #e0e0e0;
|
|
622
|
-
|
|
623
|
-
.channel-list {
|
|
624
|
-
max-height: 300px;
|
|
625
|
-
overflow-y: auto;
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
.message-content {
|
|
629
|
-
overflow-x: auto;
|
|
630
|
-
white-space: pre-wrap;
|
|
631
|
-
word-break: break-word;
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
</style>
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core Components
|
|
3
|
-
*
|
|
4
|
-
* Reusable Vue components for the Quvel UI framework
|
|
5
|
-
*/
|
|
6
|
-
export { default as BaseInput } from './Inputs/BaseInput.vue';
|
|
7
|
-
export { default as TaskErrors } from './Common/TaskErrors.vue';
|
|
8
|
-
export { default as ClientOnly } from './Misc/ClientOnly.vue';
|
|
9
|
-
export { default as FadeInOut } from './Transitions/FadeInOut.vue';
|
|
10
|
-
export { default as SlowExpand } from './Transitions/SlowExpand.vue';
|
|
11
|
-
export { default as WebSocketChannelManager } from './WebSocketChannelManager.vue';
|
|
12
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAG9D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAGhE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAG9D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAGrE,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,+BAA+B,CAAC"}
|
package/dist/components/index.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core Components
|
|
3
|
-
*
|
|
4
|
-
* Reusable Vue components for the Quvel UI framework
|
|
5
|
-
*/
|
|
6
|
-
// Inputs Components
|
|
7
|
-
export { default as BaseInput } from './Inputs/BaseInput.vue';
|
|
8
|
-
// Common Components
|
|
9
|
-
export { default as TaskErrors } from './Common/TaskErrors.vue';
|
|
10
|
-
// Misc Components
|
|
11
|
-
export { default as ClientOnly } from './Misc/ClientOnly.vue';
|
|
12
|
-
// Transitions
|
|
13
|
-
export { default as FadeInOut } from './Transitions/FadeInOut.vue';
|
|
14
|
-
export { default as SlowExpand } from './Transitions/SlowExpand.vue';
|
|
15
|
-
// WebSocket
|
|
16
|
-
export { default as WebSocketChannelManager } from './WebSocketChannelManager.vue';
|
|
@@ -1,300 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="ErrorNotFound">
|
|
3
|
-
<div class="ErrorNotFound-Container">
|
|
4
|
-
<div class="ErrorNotFound-Content">
|
|
5
|
-
<!-- Gradient Background Effect -->
|
|
6
|
-
<div class="ErrorNotFound-Glow"></div>
|
|
7
|
-
|
|
8
|
-
<!-- 404 Icon with Glow Effect -->
|
|
9
|
-
<div class="ErrorNotFound-IconContainer SmallGlow">
|
|
10
|
-
<q-icon
|
|
11
|
-
name="search"
|
|
12
|
-
size="80px"
|
|
13
|
-
class="ErrorNotFound-Icon"
|
|
14
|
-
/>
|
|
15
|
-
</div>
|
|
16
|
-
|
|
17
|
-
<!-- Error Code -->
|
|
18
|
-
<div class="ErrorNotFound-Code">
|
|
19
|
-
404
|
|
20
|
-
</div>
|
|
21
|
-
|
|
22
|
-
<!-- Message -->
|
|
23
|
-
<div class="ErrorNotFound-Title">
|
|
24
|
-
{{ $t('common.errors.notFound.title') }}
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
<div class="ErrorNotFound-Description">
|
|
28
|
-
{{ $t('common.errors.notFound.description') }}
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
<!-- Actions -->
|
|
32
|
-
<div class="ErrorNotFound-Actions">
|
|
33
|
-
<q-btn
|
|
34
|
-
unelevated
|
|
35
|
-
size="md"
|
|
36
|
-
:to="homeRoute"
|
|
37
|
-
class="PrimaryButton GenericBorder ErrorNotFound-HomeButton"
|
|
38
|
-
no-caps
|
|
39
|
-
>
|
|
40
|
-
<q-icon
|
|
41
|
-
name="home"
|
|
42
|
-
size="18px"
|
|
43
|
-
class="q-mr-xs"
|
|
44
|
-
/>
|
|
45
|
-
{{ $t('common.errors.notFound.actions.home') }}
|
|
46
|
-
</q-btn>
|
|
47
|
-
|
|
48
|
-
<q-btn
|
|
49
|
-
outline
|
|
50
|
-
size="md"
|
|
51
|
-
@click="goBack"
|
|
52
|
-
class="Button GenericBorder ErrorNotFound-BackButton"
|
|
53
|
-
no-caps
|
|
54
|
-
>
|
|
55
|
-
<q-icon
|
|
56
|
-
name="arrow_back"
|
|
57
|
-
size="18px"
|
|
58
|
-
class="q-mr-xs"
|
|
59
|
-
/>
|
|
60
|
-
{{ $t('common.errors.notFound.actions.back') }}
|
|
61
|
-
</q-btn>
|
|
62
|
-
</div>
|
|
63
|
-
|
|
64
|
-
<!-- Help Text -->
|
|
65
|
-
<div class="ErrorNotFound-Help">
|
|
66
|
-
<p class="ErrorNotFound-HelpText">
|
|
67
|
-
{{ $t('common.errors.notFound.help') }}
|
|
68
|
-
</p>
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
</div>
|
|
72
|
-
</div>
|
|
73
|
-
</template>
|
|
74
|
-
|
|
75
|
-
<script setup lang="ts">
|
|
76
|
-
import { computed } from 'vue';
|
|
77
|
-
import { useRouter } from 'vue-router';
|
|
78
|
-
import { useQuvel } from '../composables/useQuvel.js';
|
|
79
|
-
|
|
80
|
-
const router = useRouter();
|
|
81
|
-
const container = useQuvel();
|
|
82
|
-
|
|
83
|
-
// Get home route from config with default fallback
|
|
84
|
-
const homeRoute = computed(() => {
|
|
85
|
-
return container.config.routes?.home || '/' as const;
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
const goBack = () => {
|
|
89
|
-
if (window.history.length > 1) {
|
|
90
|
-
router.go(-1);
|
|
91
|
-
} else {
|
|
92
|
-
void router.push(homeRoute.value);
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
</script>
|
|
96
|
-
|
|
97
|
-
<style lang="scss" scoped>
|
|
98
|
-
.ErrorNotFound {
|
|
99
|
-
min-height: 100vh;
|
|
100
|
-
display: flex;
|
|
101
|
-
align-items: center;
|
|
102
|
-
justify-content: center;
|
|
103
|
-
position: relative;
|
|
104
|
-
background: linear-gradient(170deg, #f9fafb, #e6e7eb);
|
|
105
|
-
|
|
106
|
-
.dark & {
|
|
107
|
-
background: linear-gradient(150deg, #202b3b, #12171e);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
&-Container {
|
|
111
|
-
max-width: 32rem;
|
|
112
|
-
margin-left: auto;
|
|
113
|
-
margin-right: auto;
|
|
114
|
-
padding-left: 2rem;
|
|
115
|
-
padding-right: 2rem;
|
|
116
|
-
position: relative;
|
|
117
|
-
z-index: 10;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
&-Content {
|
|
121
|
-
text-align: center;
|
|
122
|
-
position: relative;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
&-Glow {
|
|
126
|
-
position: absolute;
|
|
127
|
-
top: 50%;
|
|
128
|
-
left: 50%;
|
|
129
|
-
width: 300px;
|
|
130
|
-
height: 300px;
|
|
131
|
-
transform: translate(-50%, -60%);
|
|
132
|
-
border-radius: 50%;
|
|
133
|
-
background: radial-gradient(circle,
|
|
134
|
-
rgba(59, 130, 246, 0.15) 0%,
|
|
135
|
-
rgba(243, 85, 44, 0.05) 40%,
|
|
136
|
-
rgba(255, 255, 255, 0) 70%);
|
|
137
|
-
opacity: 0.8;
|
|
138
|
-
z-index: -1;
|
|
139
|
-
|
|
140
|
-
.dark & {
|
|
141
|
-
background: radial-gradient(circle,
|
|
142
|
-
rgba(99, 102, 241, 0.2) 0%,
|
|
143
|
-
rgba(253, 106, 42, 0.1) 40%,
|
|
144
|
-
rgba(30, 30, 46, 0) 70%);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
&-IconContainer {
|
|
149
|
-
margin-bottom: 2rem;
|
|
150
|
-
display: inline-block;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
&-Icon {
|
|
154
|
-
color: #9ca3af;
|
|
155
|
-
|
|
156
|
-
.dark & {
|
|
157
|
-
color: #6b7280;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
&-Code {
|
|
162
|
-
font-size: 6rem;
|
|
163
|
-
line-height: 1;
|
|
164
|
-
font-weight: 700;
|
|
165
|
-
margin-bottom: 1.5rem;
|
|
166
|
-
font-family: system-ui, -apple-system, sans-serif;
|
|
167
|
-
background: linear-gradient(135deg,
|
|
168
|
-
rgba(59, 130, 246, 0.8) 0%,
|
|
169
|
-
rgba(243, 85, 44, 0.8) 50%,
|
|
170
|
-
rgba(234, 83, 1, 0.8) 100%);
|
|
171
|
-
background-clip: text;
|
|
172
|
-
-webkit-background-clip: text;
|
|
173
|
-
-webkit-text-fill-color: transparent;
|
|
174
|
-
text-shadow: 0 4px 20px rgba(59, 130, 246, 0.3);
|
|
175
|
-
|
|
176
|
-
.dark & {
|
|
177
|
-
background: linear-gradient(135deg,
|
|
178
|
-
rgba(139, 92, 246, 0.9) 0%,
|
|
179
|
-
rgba(99, 102, 241, 0.9) 50%,
|
|
180
|
-
rgba(59, 130, 246, 0.9) 100%);
|
|
181
|
-
background-clip: text;
|
|
182
|
-
-webkit-background-clip: text;
|
|
183
|
-
-webkit-text-fill-color: transparent;
|
|
184
|
-
text-shadow: 0 4px 20px rgba(139, 92, 246, 0.4);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
&-Title {
|
|
189
|
-
font-size: 1.5rem;
|
|
190
|
-
line-height: 2rem;
|
|
191
|
-
font-weight: 600;
|
|
192
|
-
color: #111827;
|
|
193
|
-
margin-bottom: 0.75rem;
|
|
194
|
-
|
|
195
|
-
.dark & {
|
|
196
|
-
color: #f3f4f6;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
&-Description {
|
|
201
|
-
color: #4b5563;
|
|
202
|
-
margin-bottom: 2.5rem;
|
|
203
|
-
line-height: 1.625;
|
|
204
|
-
max-width: 28rem;
|
|
205
|
-
margin-left: auto;
|
|
206
|
-
margin-right: auto;
|
|
207
|
-
|
|
208
|
-
.dark & {
|
|
209
|
-
color: #d1d5db;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
&-Actions {
|
|
214
|
-
display: flex;
|
|
215
|
-
flex-direction: column;
|
|
216
|
-
gap: 1rem;
|
|
217
|
-
justify-content: center;
|
|
218
|
-
margin-bottom: 2.5rem;
|
|
219
|
-
|
|
220
|
-
@media (min-width: 640px) {
|
|
221
|
-
flex-direction: row;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
&-HomeButton,
|
|
226
|
-
&-BackButton {
|
|
227
|
-
padding-left: 1.5rem;
|
|
228
|
-
padding-right: 1.5rem;
|
|
229
|
-
padding-top: 0.75rem;
|
|
230
|
-
padding-bottom: 0.75rem;
|
|
231
|
-
font-weight: 500;
|
|
232
|
-
transition-property: all;
|
|
233
|
-
transition-duration: 300ms;
|
|
234
|
-
min-width: 140px;
|
|
235
|
-
|
|
236
|
-
&:hover {
|
|
237
|
-
transform: translateY(-2px);
|
|
238
|
-
box-shadow: 0 8px 25px rgba(59, 130, 246, 0.25);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
&:active {
|
|
242
|
-
transform: translateY(0);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
&-BackButton {
|
|
247
|
-
&:hover {
|
|
248
|
-
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
|
249
|
-
|
|
250
|
-
.dark & {
|
|
251
|
-
box-shadow: 0 8px 25px rgba(255, 255, 255, 0.1);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
&-Help {
|
|
257
|
-
font-size: 0.875rem;
|
|
258
|
-
line-height: 1.25rem;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
&-HelpText {
|
|
262
|
-
color: #6b7280;
|
|
263
|
-
line-height: 1.625;
|
|
264
|
-
|
|
265
|
-
.dark & {
|
|
266
|
-
color: #9ca3af;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
@media (max-width: 640px) {
|
|
272
|
-
.ErrorNotFound {
|
|
273
|
-
&-Container {
|
|
274
|
-
padding-left: 1.5rem;
|
|
275
|
-
padding-right: 1.5rem;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
&-Code {
|
|
279
|
-
font-size: 3.75rem;
|
|
280
|
-
line-height: 1;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
&-Title {
|
|
284
|
-
font-size: 1.25rem;
|
|
285
|
-
line-height: 1.75rem;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
&-Actions {
|
|
289
|
-
.q-btn {
|
|
290
|
-
width: 100%;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
&-Glow {
|
|
295
|
-
width: 200px;
|
|
296
|
-
height: 200px;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
</style>
|
package/dist/pages/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pages/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
|