@ouraihub/aether-ui 0.1.0 → 0.1.2
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 +3 -3
- package/src/chat/ApprovalCard.svelte +8 -2
- package/src/chat/ChatComposer.svelte +319 -0
- package/src/chat/ChatMessage.svelte +262 -0
- package/src/chat/ChatPanel.css +386 -0
- package/src/chat/ChatPanel.svelte +276 -1880
- package/src/chat/ChatPanelApprovals.svelte +28 -0
- package/src/chat/ChatPanelComposer.svelte +336 -0
- package/src/chat/ChatPanelDialogs.svelte +242 -0
- package/src/chat/ChatPanelHeader.svelte +108 -0
- package/src/chat/ChatPanelMessages.svelte +166 -0
- package/src/chat/ChatPanelMode.svelte +190 -0
- package/src/chat/ChatPanelState.svelte.ts +1 -0
- package/src/chat/ChatPanelToolbar.svelte +436 -0
- package/src/chat/ChatSurface.svelte +168 -0
- package/src/chat/ContextUsageStatus.svelte +97 -0
- package/src/chat/MessageItem.svelte +111 -214
- package/src/chat/ModelEffortPicker.svelte +326 -0
- package/src/chat/PickerEffort.svelte +71 -0
- package/src/chat/ReasoningControl.svelte +184 -0
- package/src/chat/ReasoningSlider.svelte +174 -0
- package/src/chat/SkillPicker.svelte +14 -6
- package/src/chat/UsageControl.svelte +223 -0
- package/src/chat/UsageDetails.svelte +44 -90
- package/src/chat/chat-attachments.svelte.ts +78 -0
- package/src/chat/chat-panel-history.svelte.ts +430 -0
- package/src/chat/chat-panel-models.svelte.ts +97 -0
- package/src/chat/chat-panel-props.ts +38 -0
- package/src/chat/context-status.ts +101 -0
- package/src/chat/icons/LICENSE-REMIX +186 -0
- package/src/chat/icons/LICENSE-SIMPLE-ICONS +30 -0
- package/src/chat/icons/PathIcon.svelte +8 -0
- package/src/chat/icons/effort-icons.ts +65 -0
- package/src/chat/icons/status-icons.ts +105 -0
- package/src/chat/index.ts +25 -1
- package/src/chat/model-effort.ts +177 -0
- package/src/chat/run-session-history.ts +56 -0
- package/src/chat/run-session-types.ts +69 -0
- package/src/chat/run-session.svelte.ts +73 -135
- package/src/chat/test-support/chat-fixture.ts +194 -0
- package/src/chat/test-support/conversation-fixtures.ts +32 -0
- package/src/chat/test-support/run-session-fixture.ts +112 -0
- package/src/dev/Demo.svelte +3 -1
- package/src/i18n/en-chat.d.ts +1 -0
- package/src/i18n/en-chat.js +201 -0
- package/src/i18n/en.ts +58 -180
- package/src/i18n/index.ts +7 -2
- package/src/i18n/zh-CN-chat.d.ts +1 -0
- package/src/i18n/zh-CN-chat.js +190 -0
- package/src/i18n/zh-CN.ts +8 -153
- package/src/logs/LogPanel.svelte +9 -3
- package/src/logs/LogSettings.svelte +3 -1
- package/src/mcp/McpClientEditor.svelte +204 -0
- package/src/mcp/McpClientSettings.svelte +57 -130
- package/src/mcp/McpServerSettings.svelte +47 -11
- package/src/mcp/input.ts +2 -1
- package/src/ports/contract.ts +11 -2
- package/src/ports/fake-optional.ts +81 -0
- package/src/ports/fake.ts +90 -86
- package/src/ports/search.ts +11 -2
- package/src/ports/test-support/fake-fixture.ts +63 -0
- package/src/providers/EndpointKeysDialog.svelte +27 -13
- package/src/providers/EndpointModels.svelte +311 -0
- package/src/providers/EndpointPanel.svelte +33 -258
- package/src/providers/ModelPickerDialog.svelte +59 -16
- package/src/providers/ModelPricing.svelte +125 -0
- package/src/providers/ModelSelect.svelte +22 -8
- package/src/providers/ModelSettingsDialog.svelte +61 -126
- package/src/providers/ProviderDialogs.svelte +120 -0
- package/src/providers/ProviderList.svelte +159 -0
- package/src/providers/ProvidersSettings.svelte +67 -207
- package/src/providers/RequestConfigDialog.svelte +40 -12
- package/src/providers/SecretInput.svelte +11 -3
- package/src/providers/draft.ts +39 -13
- package/src/providers/edit-session.ts +31 -7
- package/src/providers/reasoning.ts +18 -4
- package/src/providers/revision.svelte.ts +3 -1
- package/src/providers/test-support/providers-fixture.ts +120 -0
- package/src/search/SearchAdvancedTools.svelte +182 -0
- package/src/search/SearchProviderCard.svelte +195 -0
- package/src/search/SearchSettings.svelte +62 -265
- package/src/search/settings-flow.ts +8 -3
- package/src/skills/SkillAdd.svelte +51 -18
- package/src/skills/SkillAuthoring.svelte +69 -20
- package/src/skills/SkillEditor.svelte +13 -3
- package/src/skills/SkillPreviewDialog.svelte +19 -5
- package/src/skills/SkillsSettings.svelte +11 -4
- package/src/skills/test-support/skills-fixture.ts +139 -0
- package/src/tauri/index.ts +23 -7
- package/src/web/index.ts +90 -25
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Button } from '#lib/components/ui/button/index.js'
|
|
3
|
+
import * as Empty from '#lib/components/ui/empty/index.js'
|
|
4
|
+
import * as Alert from '#lib/components/ui/alert/index.js'
|
|
5
|
+
import type { ConversationClient, ImageRef, ModelOption, ModelRef } from '../ports'
|
|
6
|
+
import type { ChatTurn, RunSession } from './run-session.svelte'
|
|
7
|
+
import MessageItem from './MessageItem.svelte'
|
|
8
|
+
import type { KitI18n } from '../i18n'
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
i18n,
|
|
12
|
+
session,
|
|
13
|
+
groups,
|
|
14
|
+
purpose,
|
|
15
|
+
history,
|
|
16
|
+
restoreBlocked,
|
|
17
|
+
actionBusy,
|
|
18
|
+
modelOptions,
|
|
19
|
+
modelError,
|
|
20
|
+
capability,
|
|
21
|
+
noModels,
|
|
22
|
+
onRetryModels,
|
|
23
|
+
onOpenSettings,
|
|
24
|
+
onInsert,
|
|
25
|
+
onSaveNote,
|
|
26
|
+
onExportMarkdown,
|
|
27
|
+
sourceLabel,
|
|
28
|
+
sourceModel,
|
|
29
|
+
canEdit,
|
|
30
|
+
onRetry,
|
|
31
|
+
onEdit,
|
|
32
|
+
onBranch,
|
|
33
|
+
onCopyConversation,
|
|
34
|
+
onSwitchModel,
|
|
35
|
+
onTranslate,
|
|
36
|
+
onDelete,
|
|
37
|
+
onUseContext,
|
|
38
|
+
}: {
|
|
39
|
+
i18n: KitI18n
|
|
40
|
+
session: RunSession
|
|
41
|
+
groups: [string, ChatTurn[]][]
|
|
42
|
+
purpose: string
|
|
43
|
+
history: ConversationClient | undefined
|
|
44
|
+
restoreBlocked: boolean
|
|
45
|
+
actionBusy: boolean
|
|
46
|
+
modelOptions: ModelOption[] | null
|
|
47
|
+
modelError: string | null
|
|
48
|
+
noModels: boolean
|
|
49
|
+
capability: ModelOption | null
|
|
50
|
+
onRetryModels: () => void
|
|
51
|
+
onOpenSettings?: (() => void) | undefined
|
|
52
|
+
onInsert?: ((markdown: string) => void) | undefined
|
|
53
|
+
onSaveNote?: ((markdown: string, images: ImageRef[]) => Promise<void> | void) | undefined
|
|
54
|
+
onExportMarkdown?: ((markdown: string) => Promise<void> | void) | undefined
|
|
55
|
+
sourceLabel: (turn: ChatTurn) => string
|
|
56
|
+
sourceModel: (turn: ChatTurn) => ModelRef | null
|
|
57
|
+
canEdit: (turn: ChatTurn) => boolean
|
|
58
|
+
onRetry?: (turn: ChatTurn) => void
|
|
59
|
+
onEdit?: (turn: ChatTurn) => void
|
|
60
|
+
onBranch?: (turn: ChatTurn) => void
|
|
61
|
+
onCopyConversation?: (turn: ChatTurn) => void
|
|
62
|
+
onSwitchModel?: (turn: ChatTurn, model: ModelRef) => void
|
|
63
|
+
onTranslate?: (turn: ChatTurn) => void
|
|
64
|
+
onDelete?: (turn: ChatTurn) => void
|
|
65
|
+
onUseContext?: (turn: ChatTurn) => void
|
|
66
|
+
} = $props()
|
|
67
|
+
const t = $derived(i18n.t)
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
{#if session.turns.length > 0}
|
|
71
|
+
<ol class="turns">
|
|
72
|
+
{#each groups as [questionId, replies] (questionId)}
|
|
73
|
+
{@const candidates = replies.filter((reply) => reply.kind === 'reply').length > 1}
|
|
74
|
+
{#each replies as turn, i (turn.id)}
|
|
75
|
+
<MessageItem
|
|
76
|
+
{turn}
|
|
77
|
+
{onInsert}
|
|
78
|
+
{onSaveNote}
|
|
79
|
+
{onExportMarkdown}
|
|
80
|
+
latest={turn.id === session.turns.at(-1)?.id}
|
|
81
|
+
modelLabel={turn.kind === 'translation'
|
|
82
|
+
? `${t('chat.translationReply')} · ${sourceLabel(turn)}`
|
|
83
|
+
: sourceLabel(turn)}
|
|
84
|
+
showInput={i === 0 && turn.kind !== 'translation'}
|
|
85
|
+
chosen={candidates && session.selectedTurnId === turn.id}
|
|
86
|
+
busy={actionBusy}
|
|
87
|
+
editable={canEdit(turn)}
|
|
88
|
+
onRetry={purpose === 'chat' && (turn.persisted || capability !== null)
|
|
89
|
+
? () => onRetry?.(turn)
|
|
90
|
+
: undefined}
|
|
91
|
+
onEdit={purpose === 'chat' && history && session.conversationId && turn.persisted
|
|
92
|
+
? () => onEdit?.(turn)
|
|
93
|
+
: undefined}
|
|
94
|
+
onBranch={purpose === 'chat' && history && session.conversationId && turn.persisted
|
|
95
|
+
? () => onBranch?.(turn)
|
|
96
|
+
: undefined}
|
|
97
|
+
onCopyConversation={purpose === 'chat' &&
|
|
98
|
+
history &&
|
|
99
|
+
session.conversationId &&
|
|
100
|
+
turn.persisted
|
|
101
|
+
? () => onCopyConversation?.(turn)
|
|
102
|
+
: undefined}
|
|
103
|
+
onSwitchModel={purpose === 'chat' && history && session.conversationId && turn.persisted
|
|
104
|
+
? (picked: ModelRef) => onSwitchModel?.(turn, picked)
|
|
105
|
+
: undefined}
|
|
106
|
+
modelOptions={turn.images.length > 0
|
|
107
|
+
? (modelOptions?.filter((option) => option.canVision) ?? null)
|
|
108
|
+
: modelOptions}
|
|
109
|
+
sourceModel={sourceModel(turn)}
|
|
110
|
+
onTranslate={purpose === 'chat' && history && session.conversationId && turn.persisted
|
|
111
|
+
? () => onTranslate?.(turn)
|
|
112
|
+
: undefined}
|
|
113
|
+
onDelete={purpose === 'chat' && history && session.conversationId && turn.persisted
|
|
114
|
+
? () => onDelete?.(turn)
|
|
115
|
+
: undefined}
|
|
116
|
+
onUseContext={candidates &&
|
|
117
|
+
purpose === 'chat' &&
|
|
118
|
+
history &&
|
|
119
|
+
session.conversationId &&
|
|
120
|
+
turn.persisted
|
|
121
|
+
? () => onUseContext?.(turn)
|
|
122
|
+
: undefined}
|
|
123
|
+
/>
|
|
124
|
+
{/each}
|
|
125
|
+
{/each}
|
|
126
|
+
</ol>
|
|
127
|
+
{/if}
|
|
128
|
+
{#if modelError}
|
|
129
|
+
<Alert.Root variant="destructive">
|
|
130
|
+
<Alert.Title>{t('chat.modelsFailed')}</Alert.Title>
|
|
131
|
+
<Alert.Description
|
|
132
|
+
>{modelError}<Button variant="outline" size="sm" onclick={onRetryModels}
|
|
133
|
+
>{t('chat.retryModels')}</Button
|
|
134
|
+
></Alert.Description
|
|
135
|
+
>
|
|
136
|
+
</Alert.Root>
|
|
137
|
+
{:else if modelOptions === null}
|
|
138
|
+
<p class="empty-message" role="status">{t('chat.modelsLoading')}</p>
|
|
139
|
+
{:else if noModels}
|
|
140
|
+
<Empty.Root
|
|
141
|
+
><Empty.Description>{t('chat.noModels')}</Empty.Description>{#if onOpenSettings}<Button
|
|
142
|
+
variant="outline"
|
|
143
|
+
size="sm"
|
|
144
|
+
onclick={onOpenSettings}>{t('chat.openSettings')}</Button
|
|
145
|
+
>{/if}</Empty.Root
|
|
146
|
+
>
|
|
147
|
+
{:else if session.turns.length === 0 && !restoreBlocked}
|
|
148
|
+
<p class="empty-message">{t('chat.empty')}</p>
|
|
149
|
+
{/if}
|
|
150
|
+
|
|
151
|
+
<style>
|
|
152
|
+
.turns {
|
|
153
|
+
display: flex;
|
|
154
|
+
flex-direction: column;
|
|
155
|
+
gap: 1rem;
|
|
156
|
+
padding: 0;
|
|
157
|
+
margin: 0;
|
|
158
|
+
list-style: none;
|
|
159
|
+
}
|
|
160
|
+
.empty-message {
|
|
161
|
+
color: var(--color-muted-foreground);
|
|
162
|
+
text-align: center;
|
|
163
|
+
padding: 1.5rem 0.5rem;
|
|
164
|
+
margin: 0;
|
|
165
|
+
}
|
|
166
|
+
</style>
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import ChevronDownIcon from '@lucide/svelte/icons/chevron-down'
|
|
3
|
+
import CheckIcon from '@lucide/svelte/icons/check'
|
|
4
|
+
import ShieldIcon from '@lucide/svelte/icons/shield'
|
|
5
|
+
import HandIcon from '@lucide/svelte/icons/hand'
|
|
6
|
+
import RouteIcon from '@lucide/svelte/icons/route'
|
|
7
|
+
import FilePenIcon from '@lucide/svelte/icons/file-pen'
|
|
8
|
+
import ShieldCheckIcon from '@lucide/svelte/icons/shield-check'
|
|
9
|
+
import ShieldAlertIcon from '@lucide/svelte/icons/shield-alert'
|
|
10
|
+
import InfoIcon from '@lucide/svelte/icons/info'
|
|
11
|
+
import * as DropdownMenu from '#lib/components/ui/dropdown-menu/index.js'
|
|
12
|
+
import { Button } from '#lib/components/ui/button/index.js'
|
|
13
|
+
import type { KitI18n } from '../i18n'
|
|
14
|
+
import type { PermissionMode } from '../ports'
|
|
15
|
+
let {
|
|
16
|
+
i18n,
|
|
17
|
+
mode,
|
|
18
|
+
allowedModes,
|
|
19
|
+
running,
|
|
20
|
+
chooseMode,
|
|
21
|
+
}: {
|
|
22
|
+
i18n: KitI18n
|
|
23
|
+
mode: PermissionMode
|
|
24
|
+
allowedModes: PermissionMode[]
|
|
25
|
+
running: boolean
|
|
26
|
+
chooseMode: (mode: PermissionMode) => Promise<void>
|
|
27
|
+
} = $props()
|
|
28
|
+
const t = $derived(i18n.t)
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
{#if mode === 'plan'}<span class="plan-badge" role="status">{t('chat.mode.planBadge')}</span>{/if}
|
|
32
|
+
{#if allowedModes.length > 1 || allowedModes.includes('full_access')}
|
|
33
|
+
<DropdownMenu.Root>
|
|
34
|
+
<DropdownMenu.Trigger disabled={running}>
|
|
35
|
+
{#snippet child({ props })}<Button
|
|
36
|
+
{...props}
|
|
37
|
+
variant="ghost"
|
|
38
|
+
size="sm"
|
|
39
|
+
class={mode === 'full_access' ? 'mode-danger' : undefined}
|
|
40
|
+
aria-label={`${t('chat.mode.label')}: ${t(`chat.mode.${mode}`)}`}
|
|
41
|
+
><ShieldIcon data-icon="inline-start" /><span data-composer-mode-label>
|
|
42
|
+
{t(`chat.mode.${mode}`)}</span
|
|
43
|
+
><ChevronDownIcon data-composer-mode-label data-icon="inline-end" /></Button
|
|
44
|
+
>{/snippet}
|
|
45
|
+
</DropdownMenu.Trigger>
|
|
46
|
+
<DropdownMenu.Content side="top" align="end" class="mode-menu">
|
|
47
|
+
<DropdownMenu.Group aria-label={t('chat.mode.label')}>
|
|
48
|
+
{#each allowedModes as option (option)}
|
|
49
|
+
<DropdownMenu.Item
|
|
50
|
+
class={option === 'full_access' ? 'mode-option mode-danger' : 'mode-option'}
|
|
51
|
+
aria-current={option === mode ? 'true' : undefined}
|
|
52
|
+
onSelect={() => void chooseMode(option)}
|
|
53
|
+
>{#if option === 'default'}<HandIcon />
|
|
54
|
+
{:else if option === 'plan'}<RouteIcon />
|
|
55
|
+
{:else if option === 'accept_edits'}<FilePenIcon />
|
|
56
|
+
{:else if option === 'auto'}<ShieldCheckIcon />
|
|
57
|
+
{:else}<ShieldAlertIcon />{/if}
|
|
58
|
+
<span class="mode-name">{t(`chat.mode.${option}`)}</span>
|
|
59
|
+
<span class="mode-description">{t(`chat.mode.${option}Hint`)}</span>
|
|
60
|
+
<span class="mode-notice">
|
|
61
|
+
{#if option === 'auto' || option === 'full_access'}
|
|
62
|
+
<span
|
|
63
|
+
title={t(option === 'auto' ? 'chat.mode.ruleNotice' : 'chat.mode.fullAccessBody')}
|
|
64
|
+
>
|
|
65
|
+
<InfoIcon />
|
|
66
|
+
</span>
|
|
67
|
+
{/if}
|
|
68
|
+
</span>
|
|
69
|
+
<span class="mode-check"
|
|
70
|
+
>{#if option === mode}<CheckIcon />{/if}</span
|
|
71
|
+
></DropdownMenu.Item
|
|
72
|
+
>
|
|
73
|
+
{/each}
|
|
74
|
+
</DropdownMenu.Group>
|
|
75
|
+
<div class="mode-footer">
|
|
76
|
+
<span>{t('chat.mode.label')}</span>
|
|
77
|
+
<span class="mode-keys"
|
|
78
|
+
><kbd>↑↓</kbd>{t('chat.mode.navigate')}<kbd>↵</kbd>{t('chat.mode.confirm')}<kbd>Esc</kbd
|
|
79
|
+
>{t('chat.mode.close')}</span
|
|
80
|
+
>
|
|
81
|
+
</div>
|
|
82
|
+
</DropdownMenu.Content>
|
|
83
|
+
</DropdownMenu.Root>
|
|
84
|
+
{/if}
|
|
85
|
+
|
|
86
|
+
<style>
|
|
87
|
+
.plan-badge {
|
|
88
|
+
padding: 0.125rem 0.5rem;
|
|
89
|
+
border: 1px solid var(--color-border);
|
|
90
|
+
border-radius: 999px;
|
|
91
|
+
color: var(--color-muted-foreground);
|
|
92
|
+
font-size: var(--kit-font-size-sm, 0.8125rem);
|
|
93
|
+
white-space: nowrap;
|
|
94
|
+
}
|
|
95
|
+
:global(.mode-menu) {
|
|
96
|
+
width: min(35rem, calc(100vw - 1rem));
|
|
97
|
+
padding: 0.375rem;
|
|
98
|
+
border-radius: 0.75rem;
|
|
99
|
+
}
|
|
100
|
+
:global(.mode-option) {
|
|
101
|
+
display: grid;
|
|
102
|
+
grid-template-columns: 1rem 7.5rem minmax(0, 1fr) 1rem 0.875rem;
|
|
103
|
+
align-items: center;
|
|
104
|
+
column-gap: 0.5rem;
|
|
105
|
+
min-height: 2.125rem;
|
|
106
|
+
padding: 0.375rem 0.5rem;
|
|
107
|
+
border-radius: 0.5rem;
|
|
108
|
+
font-size: var(--kit-font-size-sm, 0.8125rem);
|
|
109
|
+
}
|
|
110
|
+
:global(.mode-option[aria-current='true']) {
|
|
111
|
+
background: var(--color-muted);
|
|
112
|
+
}
|
|
113
|
+
:global(.mode-option > svg) {
|
|
114
|
+
color: var(--color-muted-foreground);
|
|
115
|
+
width: 0.875rem;
|
|
116
|
+
height: 0.875rem;
|
|
117
|
+
}
|
|
118
|
+
.mode-name {
|
|
119
|
+
white-space: nowrap;
|
|
120
|
+
}
|
|
121
|
+
.mode-description {
|
|
122
|
+
color: var(--color-muted-foreground);
|
|
123
|
+
font-size: var(--kit-font-size-xs, 0.75rem);
|
|
124
|
+
text-align: right;
|
|
125
|
+
line-height: 1.5;
|
|
126
|
+
}
|
|
127
|
+
.mode-notice,
|
|
128
|
+
.mode-check {
|
|
129
|
+
display: flex;
|
|
130
|
+
align-items: center;
|
|
131
|
+
justify-content: center;
|
|
132
|
+
color: var(--color-muted-foreground);
|
|
133
|
+
}
|
|
134
|
+
.mode-notice {
|
|
135
|
+
color: var(--color-warning, var(--color-muted-foreground));
|
|
136
|
+
}
|
|
137
|
+
.mode-notice :global(svg),
|
|
138
|
+
.mode-check :global(svg) {
|
|
139
|
+
display: block;
|
|
140
|
+
width: 0.8125rem;
|
|
141
|
+
height: 0.8125rem;
|
|
142
|
+
}
|
|
143
|
+
:global(.mode-danger),
|
|
144
|
+
:global(.mode-danger) :is(.mode-name, .mode-description, .mode-notice),
|
|
145
|
+
:global(.mode-option.mode-danger > svg) {
|
|
146
|
+
color: var(--color-destructive);
|
|
147
|
+
}
|
|
148
|
+
.mode-footer {
|
|
149
|
+
display: flex;
|
|
150
|
+
justify-content: space-between;
|
|
151
|
+
align-items: center;
|
|
152
|
+
gap: 0.75rem;
|
|
153
|
+
padding: 0.625rem 0.375rem 0.125rem;
|
|
154
|
+
color: var(--color-muted-foreground);
|
|
155
|
+
font-size: var(--kit-font-size-xs, 0.75rem);
|
|
156
|
+
}
|
|
157
|
+
.mode-keys {
|
|
158
|
+
display: flex;
|
|
159
|
+
align-items: center;
|
|
160
|
+
gap: 0.25rem;
|
|
161
|
+
}
|
|
162
|
+
.mode-keys kbd {
|
|
163
|
+
padding: 0 0.25rem;
|
|
164
|
+
border-radius: 0.25rem;
|
|
165
|
+
background: var(--color-muted);
|
|
166
|
+
font: inherit;
|
|
167
|
+
}
|
|
168
|
+
.mode-keys kbd:not(:first-child) {
|
|
169
|
+
margin-left: 0.375rem;
|
|
170
|
+
}
|
|
171
|
+
@media (max-width: 480px) {
|
|
172
|
+
:global(.mode-option) {
|
|
173
|
+
grid-template-columns: 1rem minmax(0, 1fr) 1rem 0.875rem;
|
|
174
|
+
row-gap: 0.125rem;
|
|
175
|
+
}
|
|
176
|
+
.mode-description {
|
|
177
|
+
grid-column: 2;
|
|
178
|
+
grid-row: 2;
|
|
179
|
+
text-align: left;
|
|
180
|
+
}
|
|
181
|
+
.mode-notice {
|
|
182
|
+
grid-column: 3;
|
|
183
|
+
grid-row: 1;
|
|
184
|
+
}
|
|
185
|
+
.mode-check {
|
|
186
|
+
grid-column: 4;
|
|
187
|
+
grid-row: 1;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Chat panel state implementation.
|