@opencode-ai/ui 0.0.0-beta-202606251302
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/LICENSE +21 -0
- package/package.json +110 -0
- package/src/assets/audio/alert-01.aac +0 -0
- package/src/assets/audio/alert-01.mp3 +0 -0
- package/src/assets/audio/alert-02.aac +0 -0
- package/src/assets/audio/alert-02.mp3 +0 -0
- package/src/assets/audio/alert-03.aac +0 -0
- package/src/assets/audio/alert-03.mp3 +0 -0
- package/src/assets/audio/alert-04.aac +0 -0
- package/src/assets/audio/alert-04.mp3 +0 -0
- package/src/assets/audio/alert-05.aac +0 -0
- package/src/assets/audio/alert-05.mp3 +0 -0
- package/src/assets/audio/alert-06.aac +0 -0
- package/src/assets/audio/alert-06.mp3 +0 -0
- package/src/assets/audio/alert-07.aac +0 -0
- package/src/assets/audio/alert-07.mp3 +0 -0
- package/src/assets/audio/alert-08.aac +0 -0
- package/src/assets/audio/alert-08.mp3 +0 -0
- package/src/assets/audio/alert-09.aac +0 -0
- package/src/assets/audio/alert-09.mp3 +0 -0
- package/src/assets/audio/alert-10.aac +0 -0
- package/src/assets/audio/alert-10.mp3 +0 -0
- package/src/assets/audio/bip-bop-01.aac +0 -0
- package/src/assets/audio/bip-bop-01.mp3 +0 -0
- package/src/assets/audio/bip-bop-02.aac +0 -0
- package/src/assets/audio/bip-bop-02.mp3 +0 -0
- package/src/assets/audio/bip-bop-03.aac +0 -0
- package/src/assets/audio/bip-bop-03.mp3 +0 -0
- package/src/assets/audio/bip-bop-04.aac +0 -0
- package/src/assets/audio/bip-bop-04.mp3 +0 -0
- package/src/assets/audio/bip-bop-05.aac +0 -0
- package/src/assets/audio/bip-bop-05.mp3 +0 -0
- package/src/assets/audio/bip-bop-06.aac +0 -0
- package/src/assets/audio/bip-bop-06.mp3 +0 -0
- package/src/assets/audio/bip-bop-07.aac +0 -0
- package/src/assets/audio/bip-bop-07.mp3 +0 -0
- package/src/assets/audio/bip-bop-08.aac +0 -0
- package/src/assets/audio/bip-bop-08.mp3 +0 -0
- package/src/assets/audio/bip-bop-09.aac +0 -0
- package/src/assets/audio/bip-bop-09.mp3 +0 -0
- package/src/assets/audio/bip-bop-10.aac +0 -0
- package/src/assets/audio/bip-bop-10.mp3 +0 -0
- package/src/assets/audio/nope-01.aac +0 -0
- package/src/assets/audio/nope-01.mp3 +0 -0
- package/src/assets/audio/nope-02.aac +0 -0
- package/src/assets/audio/nope-02.mp3 +0 -0
- package/src/assets/audio/nope-03.aac +0 -0
- package/src/assets/audio/nope-03.mp3 +0 -0
- package/src/assets/audio/nope-04.aac +0 -0
- package/src/assets/audio/nope-04.mp3 +0 -0
- package/src/assets/audio/nope-05.aac +0 -0
- package/src/assets/audio/nope-05.mp3 +0 -0
- package/src/assets/audio/nope-06.aac +0 -0
- package/src/assets/audio/nope-06.mp3 +0 -0
- package/src/assets/audio/nope-07.aac +0 -0
- package/src/assets/audio/nope-07.mp3 +0 -0
- package/src/assets/audio/nope-08.aac +0 -0
- package/src/assets/audio/nope-08.mp3 +0 -0
- package/src/assets/audio/nope-09.aac +0 -0
- package/src/assets/audio/nope-09.mp3 +0 -0
- package/src/assets/audio/nope-10.aac +0 -0
- package/src/assets/audio/nope-10.mp3 +0 -0
- package/src/assets/audio/nope-11.aac +0 -0
- package/src/assets/audio/nope-11.mp3 +0 -0
- package/src/assets/audio/nope-12.aac +0 -0
- package/src/assets/audio/nope-12.mp3 +0 -0
- package/src/assets/audio/staplebops-01.aac +0 -0
- package/src/assets/audio/staplebops-01.mp3 +0 -0
- package/src/assets/audio/staplebops-02.aac +0 -0
- package/src/assets/audio/staplebops-02.mp3 +0 -0
- package/src/assets/audio/staplebops-03.aac +0 -0
- package/src/assets/audio/staplebops-03.mp3 +0 -0
- package/src/assets/audio/staplebops-04.aac +0 -0
- package/src/assets/audio/staplebops-04.mp3 +0 -0
- package/src/assets/audio/staplebops-05.aac +0 -0
- package/src/assets/audio/staplebops-05.mp3 +0 -0
- package/src/assets/audio/staplebops-06.aac +0 -0
- package/src/assets/audio/staplebops-06.mp3 +0 -0
- package/src/assets/audio/staplebops-07.aac +0 -0
- package/src/assets/audio/staplebops-07.mp3 +0 -0
- package/src/assets/audio/yup-01.aac +0 -0
- package/src/assets/audio/yup-01.mp3 +0 -0
- package/src/assets/audio/yup-02.aac +0 -0
- package/src/assets/audio/yup-02.mp3 +0 -0
- package/src/assets/audio/yup-03.aac +0 -0
- package/src/assets/audio/yup-03.mp3 +0 -0
- package/src/assets/audio/yup-04.aac +0 -0
- package/src/assets/audio/yup-04.mp3 +0 -0
- package/src/assets/audio/yup-05.aac +0 -0
- package/src/assets/audio/yup-05.mp3 +0 -0
- package/src/assets/audio/yup-06.aac +0 -0
- package/src/assets/audio/yup-06.mp3 +0 -0
- package/src/assets/fonts/Inter.ttf +0 -0
- package/src/assets/fonts/JetBrainsMonoNerdFontMono-Regular.woff2 +0 -0
- package/src/assets/icons/app/android-studio.svg +369 -0
- package/src/assets/icons/app/antigravity.svg +97 -0
- package/src/assets/icons/app/cursor.svg +16 -0
- package/src/assets/icons/app/file-explorer.svg +20 -0
- package/src/assets/icons/app/finder.png +0 -0
- package/src/assets/icons/app/ghostty.svg +13 -0
- package/src/assets/icons/app/iterm2.svg +13 -0
- package/src/assets/icons/app/powershell.svg +14 -0
- package/src/assets/icons/app/sublimetext.svg +17 -0
- package/src/assets/icons/app/terminal.png +0 -0
- package/src/assets/icons/app/textmate.png +0 -0
- package/src/assets/icons/app/vscode.svg +39 -0
- package/src/assets/icons/app/warp.png +0 -0
- package/src/assets/icons/app/xcode.png +0 -0
- package/src/assets/icons/app/zed-dark.svg +15 -0
- package/src/assets/icons/app/zed.svg +15 -0
- package/src/components/accordion.css +123 -0
- package/src/components/accordion.tsx +92 -0
- package/src/components/animated-number.css +75 -0
- package/src/components/animated-number.tsx +109 -0
- package/src/components/app-icon.css +5 -0
- package/src/components/app-icon.tsx +85 -0
- package/src/components/app-icons/sprite.svg +114 -0
- package/src/components/app-icons/types.ts +21 -0
- package/src/components/avatar.css +49 -0
- package/src/components/avatar.tsx +55 -0
- package/src/components/button.css +194 -0
- package/src/components/button.tsx +33 -0
- package/src/components/card.css +94 -0
- package/src/components/card.tsx +123 -0
- package/src/components/checkbox.css +131 -0
- package/src/components/checkbox.tsx +43 -0
- package/src/components/collapsible.css +148 -0
- package/src/components/collapsible.tsx +48 -0
- package/src/components/context-menu.css +134 -0
- package/src/components/context-menu.tsx +308 -0
- package/src/components/dialog.css +181 -0
- package/src/components/dialog.tsx +72 -0
- package/src/components/diff-changes.css +42 -0
- package/src/components/diff-changes.tsx +115 -0
- package/src/components/dock-surface.css +23 -0
- package/src/components/dock-surface.tsx +54 -0
- package/src/components/dropdown-menu.css +135 -0
- package/src/components/dropdown-menu.tsx +308 -0
- package/src/components/favicon.tsx +13 -0
- package/src/components/file-icon.css +26 -0
- package/src/components/file-icon.tsx +588 -0
- package/src/components/file-icons/sprite.svg +11707 -0
- package/src/components/file-icons/types.ts +1095 -0
- package/src/components/font.tsx +1 -0
- package/src/components/hover-card.css +61 -0
- package/src/components/hover-card.tsx +32 -0
- package/src/components/icon-button.css +181 -0
- package/src/components/icon-button.tsx +29 -0
- package/src/components/icon.css +34 -0
- package/src/components/icon.tsx +169 -0
- package/src/components/image-preview.css +63 -0
- package/src/components/image-preview.tsx +32 -0
- package/src/components/inline-input.css +17 -0
- package/src/components/inline-input.tsx +22 -0
- package/src/components/keybind.css +18 -0
- package/src/components/keybind.tsx +20 -0
- package/src/components/list.css +331 -0
- package/src/components/list.tsx +394 -0
- package/src/components/logo.css +4 -0
- package/src/components/logo.tsx +62 -0
- package/src/components/motion-spring.tsx +58 -0
- package/src/components/popover.css +98 -0
- package/src/components/popover.tsx +153 -0
- package/src/components/progress-circle.css +12 -0
- package/src/components/progress-circle.tsx +57 -0
- package/src/components/progress.css +63 -0
- package/src/components/progress.tsx +39 -0
- package/src/components/provider-icon.css +5 -0
- package/src/components/provider-icon.tsx +25 -0
- package/src/components/provider-icons/sprite.svg +1135 -0
- package/src/components/provider-icons/types.ts +105 -0
- package/src/components/radio-group.css +187 -0
- package/src/components/radio-group.tsx +83 -0
- package/src/components/resize-handle.css +58 -0
- package/src/components/resize-handle.tsx +82 -0
- package/src/components/scroll-view.css +66 -0
- package/src/components/scroll-view.tsx +250 -0
- package/src/components/select.css +202 -0
- package/src/components/select.tsx +174 -0
- package/src/components/spinner.css +6 -0
- package/src/components/spinner.tsx +52 -0
- package/src/components/sticky-accordion-header.css +6 -0
- package/src/components/sticky-accordion-header.tsx +18 -0
- package/src/components/switch.css +132 -0
- package/src/components/switch.tsx +29 -0
- package/src/components/tabs.css +635 -0
- package/src/components/tabs.tsx +125 -0
- package/src/components/tag.css +37 -0
- package/src/components/tag.tsx +22 -0
- package/src/components/text-field.css +134 -0
- package/src/components/text-field.tsx +128 -0
- package/src/components/text-reveal.css +150 -0
- package/src/components/text-reveal.tsx +143 -0
- package/src/components/text-shimmer.css +119 -0
- package/src/components/text-shimmer.tsx +62 -0
- package/src/components/text-strikethrough.css +27 -0
- package/src/components/text-strikethrough.tsx +84 -0
- package/src/components/toast.css +236 -0
- package/src/components/toast.tsx +185 -0
- package/src/components/tooltip.css +74 -0
- package/src/components/tooltip.tsx +161 -0
- package/src/components/typewriter.css +14 -0
- package/src/components/typewriter.tsx +55 -0
- package/src/context/dialog.tsx +197 -0
- package/src/context/file.tsx +10 -0
- package/src/context/helper.tsx +38 -0
- package/src/context/i18n.tsx +38 -0
- package/src/context/index.ts +4 -0
- package/src/context/marked.tsx +522 -0
- package/src/context/worker-pool.tsx +20 -0
- package/src/custom-elements.d.ts +17 -0
- package/src/hooks/create-auto-scroll.tsx +237 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/use-filtered-list.tsx +134 -0
- package/src/i18n/ar.ts +168 -0
- package/src/i18n/br.ts +168 -0
- package/src/i18n/bs.ts +172 -0
- package/src/i18n/da.ts +167 -0
- package/src/i18n/de.ts +173 -0
- package/src/i18n/en.ts +176 -0
- package/src/i18n/es.ts +168 -0
- package/src/i18n/fr.ts +168 -0
- package/src/i18n/ja.ts +167 -0
- package/src/i18n/ko.ts +168 -0
- package/src/i18n/no.ts +171 -0
- package/src/i18n/pl.ts +167 -0
- package/src/i18n/ru.ts +167 -0
- package/src/i18n/th.ts +169 -0
- package/src/i18n/tr.ts +174 -0
- package/src/i18n/uk.ts +167 -0
- package/src/i18n/zh.ts +171 -0
- package/src/i18n/zht.ts +171 -0
- package/src/storybook/fixtures.ts +51 -0
- package/src/storybook/scaffold.tsx +62 -0
- package/src/styles/animations.css +141 -0
- package/src/styles/base.css +404 -0
- package/src/styles/colors.css +772 -0
- package/src/styles/index.css +53 -0
- package/src/styles/tailwind/colors.css +285 -0
- package/src/styles/tailwind/index.css +78 -0
- package/src/styles/tailwind/utilities.css +131 -0
- package/src/styles/theme.css +609 -0
- package/src/styles/utilities.css +118 -0
- package/src/theme/color.ts +299 -0
- package/src/theme/context.tsx +370 -0
- package/src/theme/default-themes.ts +116 -0
- package/src/theme/index.ts +78 -0
- package/src/theme/loader.ts +112 -0
- package/src/theme/resolve.ts +540 -0
- package/src/theme/themes/amoled.json +49 -0
- package/src/theme/themes/aura.json +51 -0
- package/src/theme/themes/ayu.json +51 -0
- package/src/theme/themes/carbonfox.json +53 -0
- package/src/theme/themes/catppuccin-frappe.json +85 -0
- package/src/theme/themes/catppuccin-macchiato.json +85 -0
- package/src/theme/themes/catppuccin.json +45 -0
- package/src/theme/themes/cobalt2.json +87 -0
- package/src/theme/themes/cursor.json +91 -0
- package/src/theme/themes/dracula.json +49 -0
- package/src/theme/themes/everforest.json +89 -0
- package/src/theme/themes/flexoki.json +86 -0
- package/src/theme/themes/github.json +85 -0
- package/src/theme/themes/gruvbox.json +45 -0
- package/src/theme/themes/kanagawa.json +89 -0
- package/src/theme/themes/lucent-orng.json +87 -0
- package/src/theme/themes/material.json +87 -0
- package/src/theme/themes/matrix.json +113 -0
- package/src/theme/themes/mercury.json +86 -0
- package/src/theme/themes/monokai.json +49 -0
- package/src/theme/themes/nightowl.json +46 -0
- package/src/theme/themes/nord.json +46 -0
- package/src/theme/themes/oc-2.json +468 -0
- package/src/theme/themes/one-dark.json +89 -0
- package/src/theme/themes/onedarkpro.json +45 -0
- package/src/theme/themes/opencode.json +89 -0
- package/src/theme/themes/orng.json +87 -0
- package/src/theme/themes/osaka-jade.json +88 -0
- package/src/theme/themes/palenight.json +85 -0
- package/src/theme/themes/rosepine.json +85 -0
- package/src/theme/themes/shadesofpurple.json +51 -0
- package/src/theme/themes/solarized.json +49 -0
- package/src/theme/themes/synthwave84.json +87 -0
- package/src/theme/themes/tokyonight.json +47 -0
- package/src/theme/themes/vercel.json +90 -0
- package/src/theme/themes/vesper.json +51 -0
- package/src/theme/themes/zenburn.json +87 -0
- package/src/theme/types.ts +75 -0
- package/src/theme/v2/avatar.ts +48 -0
- package/src/theme/v2/default-primitives.ts +114 -0
- package/src/theme/v2/foreground.ts +60 -0
- package/src/theme/v2/mapping.ts +138 -0
- package/src/theme/v2/resolve.ts +153 -0
- package/src/v2/components/accordion-v2.css +139 -0
- package/src/v2/components/accordion-v2.tsx +86 -0
- package/src/v2/components/avatar-v2.css +70 -0
- package/src/v2/components/avatar-v2.tsx +59 -0
- package/src/v2/components/badge-v2.css +27 -0
- package/src/v2/components/badge-v2.tsx +20 -0
- package/src/v2/components/button-v2.css +186 -0
- package/src/v2/components/button-v2.tsx +35 -0
- package/src/v2/components/checkbox-v2.css +184 -0
- package/src/v2/components/checkbox-v2.tsx +65 -0
- package/src/v2/components/dialog-v2.css +150 -0
- package/src/v2/components/dialog-v2.tsx +93 -0
- package/src/v2/components/diff-changes-v2.css +24 -0
- package/src/v2/components/diff-changes-v2.tsx +28 -0
- package/src/v2/components/field-v2.css +94 -0
- package/src/v2/components/field-v2.tsx +265 -0
- package/src/v2/components/icon-button-v2.css +155 -0
- package/src/v2/components/icon-button-v2.tsx +37 -0
- package/src/v2/components/icon.tsx +129 -0
- package/src/v2/components/inline-input-v2.css +218 -0
- package/src/v2/components/inline-input-v2.tsx +90 -0
- package/src/v2/components/keybind-v2.css +76 -0
- package/src/v2/components/keybind-v2.tsx +30 -0
- package/src/v2/components/line-comment-v2.css +204 -0
- package/src/v2/components/line-comment-v2.tsx +155 -0
- package/src/v2/components/menu-v2.css +190 -0
- package/src/v2/components/menu-v2.tsx +225 -0
- package/src/v2/components/project-avatar-v2.css +126 -0
- package/src/v2/components/project-avatar-v2.tsx +64 -0
- package/src/v2/components/radio-v2.css +202 -0
- package/src/v2/components/radio-v2.tsx +72 -0
- package/src/v2/components/segmented-control-v2.css +80 -0
- package/src/v2/components/segmented-control-v2.tsx +208 -0
- package/src/v2/components/select-v2.css +285 -0
- package/src/v2/components/select-v2.tsx +208 -0
- package/src/v2/components/switch-v2.css +154 -0
- package/src/v2/components/switch-v2.tsx +28 -0
- package/src/v2/components/tab-state-indicator.tsx +37 -0
- package/src/v2/components/tabs-v2.css +225 -0
- package/src/v2/components/tabs-v2.tsx +147 -0
- package/src/v2/components/text-input-v2.css +145 -0
- package/src/v2/components/text-input-v2.tsx +67 -0
- package/src/v2/components/text-shimmer-v2.css +125 -0
- package/src/v2/components/text-shimmer-v2.tsx +63 -0
- package/src/v2/components/textarea-v2.css +78 -0
- package/src/v2/components/textarea-v2.tsx +31 -0
- package/src/v2/components/toast-v2.css +215 -0
- package/src/v2/components/toast-v2.tsx +144 -0
- package/src/v2/components/tooltip-v2.css +53 -0
- package/src/v2/components/tooltip-v2.tsx +146 -0
- package/src/v2/components/wordmark-v2.tsx +92 -0
- package/src/v2/styles/colors.css +172 -0
- package/src/v2/styles/tailwind.css +2 -0
- package/src/v2/styles/theme.css +441 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { createEffect, on, onCleanup } from "solid-js"
|
|
2
|
+
import { createStore } from "solid-js/store"
|
|
3
|
+
import { createEventListener } from "@solid-primitives/event-listener"
|
|
4
|
+
import { createResizeObserver } from "@solid-primitives/resize-observer"
|
|
5
|
+
|
|
6
|
+
export interface AutoScrollOptions {
|
|
7
|
+
working: () => boolean
|
|
8
|
+
onUserInteracted?: () => void
|
|
9
|
+
overflowAnchor?: "none" | "auto" | "dynamic"
|
|
10
|
+
bottomThreshold?: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createAutoScroll(options: AutoScrollOptions) {
|
|
14
|
+
let settling = false
|
|
15
|
+
let settleTimer: ReturnType<typeof setTimeout> | undefined
|
|
16
|
+
let autoTimer: ReturnType<typeof setTimeout> | undefined
|
|
17
|
+
let auto: { top: number; time: number } | undefined
|
|
18
|
+
|
|
19
|
+
const threshold = () => options.bottomThreshold ?? 10
|
|
20
|
+
|
|
21
|
+
const [store, setStore] = createStore({
|
|
22
|
+
contentRef: undefined as HTMLElement | undefined,
|
|
23
|
+
scrollRef: undefined as HTMLElement | undefined,
|
|
24
|
+
userScrolled: false,
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const active = () => options.working() || settling
|
|
28
|
+
|
|
29
|
+
const distanceFromBottom = (el: HTMLElement) => {
|
|
30
|
+
return el.scrollHeight - el.clientHeight - el.scrollTop
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const canScroll = (el: HTMLElement) => {
|
|
34
|
+
return el.scrollHeight - el.clientHeight > 1
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Browsers can dispatch scroll events asynchronously. If new content arrives
|
|
38
|
+
// between us calling `scrollTo()` and the subsequent `scroll` event firing,
|
|
39
|
+
// the handler can see a non-zero `distanceFromBottom` and incorrectly assume
|
|
40
|
+
// the user scrolled.
|
|
41
|
+
const markAuto = (el: HTMLElement) => {
|
|
42
|
+
auto = {
|
|
43
|
+
top: Math.max(0, el.scrollHeight - el.clientHeight),
|
|
44
|
+
time: Date.now(),
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (autoTimer) clearTimeout(autoTimer)
|
|
48
|
+
autoTimer = setTimeout(() => {
|
|
49
|
+
auto = undefined
|
|
50
|
+
autoTimer = undefined
|
|
51
|
+
}, 1500)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const isAuto = (el: HTMLElement) => {
|
|
55
|
+
const a = auto
|
|
56
|
+
if (!a) return false
|
|
57
|
+
|
|
58
|
+
if (Date.now() - a.time > 1500) {
|
|
59
|
+
auto = undefined
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return Math.abs(el.scrollTop - a.top) < 2
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const scrollToBottomNow = (behavior: ScrollBehavior) => {
|
|
67
|
+
const el = store.scrollRef
|
|
68
|
+
if (!el) return
|
|
69
|
+
markAuto(el)
|
|
70
|
+
if (behavior === "smooth") {
|
|
71
|
+
el.scrollTo({ top: el.scrollHeight, behavior })
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// `scrollTop` assignment bypasses any CSS `scroll-behavior: smooth`.
|
|
76
|
+
el.scrollTop = el.scrollHeight
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const scrollToBottom = (force: boolean) => {
|
|
80
|
+
if (!force && !active()) return
|
|
81
|
+
|
|
82
|
+
if (force && store.userScrolled) setStore("userScrolled", false)
|
|
83
|
+
|
|
84
|
+
const el = store.scrollRef
|
|
85
|
+
if (!el) return
|
|
86
|
+
|
|
87
|
+
if (!force && store.userScrolled) return
|
|
88
|
+
|
|
89
|
+
const distance = distanceFromBottom(el)
|
|
90
|
+
if (distance < 2) {
|
|
91
|
+
markAuto(el)
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// For auto-following content we prefer immediate updates to avoid
|
|
96
|
+
// visible "catch up" animations while content is still settling.
|
|
97
|
+
scrollToBottomNow("auto")
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const stop = () => {
|
|
101
|
+
const el = store.scrollRef
|
|
102
|
+
if (!el) return
|
|
103
|
+
if (!canScroll(el)) {
|
|
104
|
+
if (store.userScrolled) setStore("userScrolled", false)
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
if (store.userScrolled) return
|
|
108
|
+
|
|
109
|
+
setStore("userScrolled", true)
|
|
110
|
+
options.onUserInteracted?.()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const handleWheel = (e: WheelEvent) => {
|
|
114
|
+
if (e.deltaY >= 0) return
|
|
115
|
+
// If the user is scrolling within a nested scrollable region (tool output,
|
|
116
|
+
// code block, etc), don't treat it as leaving the "follow bottom" mode.
|
|
117
|
+
// Those regions opt in via `data-scrollable`.
|
|
118
|
+
const el = store.scrollRef
|
|
119
|
+
const target = e.target instanceof Element ? e.target : undefined
|
|
120
|
+
const nested = target?.closest("[data-scrollable]")
|
|
121
|
+
if (el && nested && nested !== el) return
|
|
122
|
+
stop()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const handleScroll = () => {
|
|
126
|
+
const el = store.scrollRef
|
|
127
|
+
if (!el) return
|
|
128
|
+
|
|
129
|
+
if (!canScroll(el)) {
|
|
130
|
+
if (store.userScrolled) setStore("userScrolled", false)
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (distanceFromBottom(el) < threshold()) {
|
|
135
|
+
if (store.userScrolled) setStore("userScrolled", false)
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Ignore scroll events triggered by our own scrollToBottom calls.
|
|
140
|
+
if (!store.userScrolled && isAuto(el)) {
|
|
141
|
+
scrollToBottom(false)
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
stop()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const handleInteraction = () => {
|
|
149
|
+
if (!active()) return
|
|
150
|
+
const selection = window.getSelection()
|
|
151
|
+
if (selection && selection.toString().length > 0) {
|
|
152
|
+
stop()
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const updateOverflowAnchor = (el: HTMLElement) => {
|
|
157
|
+
const mode = options.overflowAnchor ?? "dynamic"
|
|
158
|
+
|
|
159
|
+
if (mode === "none") {
|
|
160
|
+
el.style.overflowAnchor = "none"
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (mode === "auto") {
|
|
165
|
+
el.style.overflowAnchor = "auto"
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
el.style.overflowAnchor = store.userScrolled ? "auto" : "none"
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
createResizeObserver(
|
|
173
|
+
() => store.contentRef,
|
|
174
|
+
() => {
|
|
175
|
+
const el = store.scrollRef
|
|
176
|
+
if (el && !canScroll(el)) {
|
|
177
|
+
if (store.userScrolled) setStore("userScrolled", false)
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
if (!active()) return
|
|
181
|
+
if (store.userScrolled) return
|
|
182
|
+
// ResizeObserver fires after layout, before paint.
|
|
183
|
+
// Keep the bottom locked in the same frame to avoid visible
|
|
184
|
+
// "jump up then catch up" artifacts while streaming content.
|
|
185
|
+
scrollToBottom(false)
|
|
186
|
+
},
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
createEffect(
|
|
190
|
+
on(options.working, (working: boolean) => {
|
|
191
|
+
settling = false
|
|
192
|
+
if (settleTimer) clearTimeout(settleTimer)
|
|
193
|
+
settleTimer = undefined
|
|
194
|
+
|
|
195
|
+
if (working) {
|
|
196
|
+
if (!store.userScrolled) scrollToBottom(true)
|
|
197
|
+
return
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
settling = true
|
|
201
|
+
settleTimer = setTimeout(() => {
|
|
202
|
+
settling = false
|
|
203
|
+
}, 300)
|
|
204
|
+
}),
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
createEffect(() => {
|
|
208
|
+
// Track `userScrolled` even before `scrollRef` is attached, so we can
|
|
209
|
+
// update overflow anchoring once the element exists.
|
|
210
|
+
store.userScrolled
|
|
211
|
+
const el = store.scrollRef
|
|
212
|
+
if (!el) return
|
|
213
|
+
updateOverflowAnchor(el)
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
createEventListener(() => store.scrollRef, "wheel", handleWheel, { passive: true })
|
|
217
|
+
|
|
218
|
+
onCleanup(() => {
|
|
219
|
+
if (settleTimer) clearTimeout(settleTimer)
|
|
220
|
+
if (autoTimer) clearTimeout(autoTimer)
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
scrollRef: (el: HTMLElement | undefined) => setStore("scrollRef", el),
|
|
225
|
+
contentRef: (el: HTMLElement | undefined) => setStore("contentRef", el),
|
|
226
|
+
handleScroll,
|
|
227
|
+
handleInteraction,
|
|
228
|
+
pause: stop,
|
|
229
|
+
resume: () => {
|
|
230
|
+
if (store.userScrolled) setStore("userScrolled", false)
|
|
231
|
+
scrollToBottom(true)
|
|
232
|
+
},
|
|
233
|
+
scrollToBottom: () => scrollToBottom(false),
|
|
234
|
+
forceScrollToBottom: () => scrollToBottom(true),
|
|
235
|
+
userScrolled: () => store.userScrolled,
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import fuzzysort from "fuzzysort"
|
|
2
|
+
import { entries, flatMap, groupBy, map, pipe } from "remeda"
|
|
3
|
+
import { createEffect, createMemo, createResource, on } from "solid-js"
|
|
4
|
+
import { createStore } from "solid-js/store"
|
|
5
|
+
import { createList } from "solid-list"
|
|
6
|
+
|
|
7
|
+
export interface FilteredListProps<T> {
|
|
8
|
+
items: T[] | ((filter: string) => T[] | Promise<T[]>)
|
|
9
|
+
key: (item: T) => string
|
|
10
|
+
filterKeys?: string[]
|
|
11
|
+
current?: T
|
|
12
|
+
groupBy?: (x: T) => string
|
|
13
|
+
sortBy?: (a: T, b: T) => number
|
|
14
|
+
sortGroupsBy?: (a: { category: string; items: T[] }, b: { category: string; items: T[] }) => number
|
|
15
|
+
skipFilter?: (item: T) => boolean
|
|
16
|
+
onSelect?: (value: T | undefined, index: number) => void
|
|
17
|
+
noInitialSelection?: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function useFilteredList<T>(props: FilteredListProps<T>) {
|
|
21
|
+
const [store, setStore] = createStore<{ filter: string }>({ filter: "" })
|
|
22
|
+
|
|
23
|
+
type Group = { category: string; items: [T, ...T[]] }
|
|
24
|
+
const empty: Group[] = []
|
|
25
|
+
|
|
26
|
+
const [grouped, { refetch }] = createResource(
|
|
27
|
+
() => ({
|
|
28
|
+
filter: store.filter,
|
|
29
|
+
items: typeof props.items === "function" ? props.items(store.filter) : props.items,
|
|
30
|
+
}),
|
|
31
|
+
async ({ filter, items }) => {
|
|
32
|
+
const query = filter ?? ""
|
|
33
|
+
const needle = query.toLowerCase()
|
|
34
|
+
const all = (await Promise.resolve(items)) || []
|
|
35
|
+
const result = pipe(
|
|
36
|
+
all,
|
|
37
|
+
(x) => {
|
|
38
|
+
if (!needle) return x
|
|
39
|
+
const skipFilter = props.skipFilter
|
|
40
|
+
const filterable = skipFilter ? x.filter((item) => !skipFilter(item)) : x
|
|
41
|
+
const skipped = skipFilter ? x.filter(skipFilter) : []
|
|
42
|
+
const filtered =
|
|
43
|
+
!props.filterKeys && Array.isArray(filterable) && filterable.every((e) => typeof e === "string")
|
|
44
|
+
? (fuzzysort.go(needle, filterable).map((x) => x.target) as T[])
|
|
45
|
+
: fuzzysort.go(needle, filterable, { keys: props.filterKeys! }).map((x) => x.obj)
|
|
46
|
+
return skipped.length ? [...filtered, ...skipped] : filtered
|
|
47
|
+
},
|
|
48
|
+
groupBy((x) => (props.groupBy ? props.groupBy(x) : "")),
|
|
49
|
+
entries(),
|
|
50
|
+
map(([k, v]) => ({ category: k, items: props.sortBy ? v.sort(props.sortBy) : v })),
|
|
51
|
+
(groups) => (props.sortGroupsBy ? groups.sort(props.sortGroupsBy) : groups),
|
|
52
|
+
)
|
|
53
|
+
return result
|
|
54
|
+
},
|
|
55
|
+
{ initialValue: empty },
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
const flat = createMemo(() => {
|
|
59
|
+
return pipe(
|
|
60
|
+
grouped.latest || [],
|
|
61
|
+
flatMap((x) => x.items),
|
|
62
|
+
)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
function initialActive() {
|
|
66
|
+
if (props.noInitialSelection) return ""
|
|
67
|
+
if (props.current) return props.key(props.current)
|
|
68
|
+
|
|
69
|
+
const items = flat()
|
|
70
|
+
if (items.length === 0) return ""
|
|
71
|
+
return props.key(items[0])
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const list = createList({
|
|
75
|
+
items: () => flat().map(props.key),
|
|
76
|
+
initialActive: initialActive(),
|
|
77
|
+
loop: true,
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
const reset = () => {
|
|
81
|
+
if (props.noInitialSelection) {
|
|
82
|
+
list.setActive("")
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
const all = flat()
|
|
86
|
+
if (all.length === 0) return
|
|
87
|
+
list.setActive(props.key(all[0]))
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const onKeyDown = (event: KeyboardEvent) => {
|
|
91
|
+
if (event.key === "Enter" && !event.isComposing) {
|
|
92
|
+
event.preventDefault()
|
|
93
|
+
const selectedIndex = flat().findIndex((x) => props.key(x) === list.active())
|
|
94
|
+
const selected = flat()[selectedIndex]
|
|
95
|
+
if (selected) props.onSelect?.(selected, selectedIndex)
|
|
96
|
+
} else if (event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) {
|
|
97
|
+
if (event.key === "n" || event.key === "p") {
|
|
98
|
+
event.preventDefault()
|
|
99
|
+
const navEvent = new KeyboardEvent("keydown", {
|
|
100
|
+
key: event.key === "n" ? "ArrowDown" : "ArrowUp",
|
|
101
|
+
bubbles: true,
|
|
102
|
+
})
|
|
103
|
+
list.onKeyDown(navEvent)
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
// Skip list navigation for text editing shortcuts (e.g., Option+Arrow, Option+Backspace on macOS)
|
|
107
|
+
if (event.altKey || event.metaKey) return
|
|
108
|
+
list.onKeyDown(event)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
createEffect(
|
|
113
|
+
on(grouped, () => {
|
|
114
|
+
reset()
|
|
115
|
+
}),
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
const onInput = (value: string) => {
|
|
119
|
+
setStore("filter", value)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
grouped,
|
|
124
|
+
filter: () => store.filter,
|
|
125
|
+
flat,
|
|
126
|
+
reset,
|
|
127
|
+
refetch,
|
|
128
|
+
clear: () => setStore("filter", ""),
|
|
129
|
+
onKeyDown,
|
|
130
|
+
onInput,
|
|
131
|
+
active: list.active,
|
|
132
|
+
setActive: list.setActive,
|
|
133
|
+
}
|
|
134
|
+
}
|
package/src/i18n/ar.ts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
export const dict = {
|
|
2
|
+
"ui.sessionReview.title": "تغييرات الجلسة",
|
|
3
|
+
"ui.sessionReview.title.lastTurn": "تغييرات آخر دور",
|
|
4
|
+
"ui.sessionReview.diffStyle.unified": "موحد",
|
|
5
|
+
"ui.sessionReview.diffStyle.split": "منقسم",
|
|
6
|
+
"ui.sessionReview.openFile": "فتح ملف",
|
|
7
|
+
"ui.sessionReview.selection.line": "سطر {{line}}",
|
|
8
|
+
"ui.sessionReview.selection.lines": "الأسطر {{start}}-{{end}}",
|
|
9
|
+
"ui.sessionReview.expandAll": "توسيع الكل",
|
|
10
|
+
"ui.sessionReview.collapseAll": "طي الكل",
|
|
11
|
+
"ui.sessionReview.change.added": "مضاف",
|
|
12
|
+
"ui.sessionReview.change.removed": "محذوف",
|
|
13
|
+
"ui.sessionReview.change.modified": "معدل",
|
|
14
|
+
"ui.sessionReview.image.loading": "جار التحميل...",
|
|
15
|
+
"ui.sessionReview.image.placeholder": "صورة",
|
|
16
|
+
"ui.sessionReview.largeDiff.title": "Diff كبير جدا لعرضه",
|
|
17
|
+
"ui.sessionReview.largeDiff.meta": "الحد: {{limit}} سطرًا متغيرًا. الحالي: {{current}} سطرًا متغيرًا.",
|
|
18
|
+
"ui.sessionReview.largeDiff.renderAnyway": "اعرض على أي حال",
|
|
19
|
+
"ui.fileMedia.kind.image": "صورة",
|
|
20
|
+
"ui.fileMedia.kind.audio": "صوت",
|
|
21
|
+
"ui.fileMedia.state.removed": "تمت إزالة {{kind}}",
|
|
22
|
+
"ui.fileMedia.state.loading": "جاري تحميل {{kind}}...",
|
|
23
|
+
"ui.fileMedia.state.error": "خطأ في تحميل {{kind}}",
|
|
24
|
+
"ui.fileMedia.state.unavailable": "{{kind}} غير متوفر",
|
|
25
|
+
"ui.fileMedia.binary.title": "ملف ثنائي",
|
|
26
|
+
"ui.fileMedia.binary.description.path": "{{path}} عبارة عن ملف ثنائي ولا يمكن عرضه.",
|
|
27
|
+
"ui.fileMedia.binary.description.default": "هذا ملف ثنائي ولا يمكن عرضه.",
|
|
28
|
+
|
|
29
|
+
"ui.lineComment.label.prefix": "تعليق على ",
|
|
30
|
+
"ui.lineComment.label.suffix": "",
|
|
31
|
+
"ui.lineComment.editorLabel.prefix": "جارٍ التعليق على ",
|
|
32
|
+
"ui.lineComment.editorLabel.suffix": "",
|
|
33
|
+
"ui.lineComment.placeholder": "أضف تعليقًا",
|
|
34
|
+
"ui.lineComment.submit": "تعليق",
|
|
35
|
+
|
|
36
|
+
"ui.sessionTurn.steps.show": "إظهار الخطوات",
|
|
37
|
+
"ui.sessionTurn.steps.hide": "إخفاء الخطوات",
|
|
38
|
+
"ui.sessionTurn.summary.response": "استجابة",
|
|
39
|
+
"ui.sessionTurn.diff.showMore": "إظهار المزيد من التغييرات ({{count}})",
|
|
40
|
+
|
|
41
|
+
"ui.sessionTurn.retry.retrying": "إعادة المحاولة",
|
|
42
|
+
"ui.sessionTurn.retry.inSeconds": "خلال {{seconds}} ثواني",
|
|
43
|
+
"ui.sessionTurn.retry.attempt": "المحاولة رقم {{attempt}}",
|
|
44
|
+
"ui.sessionTurn.retry.attemptLine": "{{line}} - المحاولة رقم {{attempt}}",
|
|
45
|
+
"ui.sessionTurn.retry.geminiHot": "gemini مزدحم حاليا",
|
|
46
|
+
"ui.sessionTurn.error.freeUsageExceeded": "تم تجاوز حد الاستخدام المجاني",
|
|
47
|
+
"ui.sessionTurn.error.addCredits": "إضافة رصيد",
|
|
48
|
+
|
|
49
|
+
"dialog.usageExceeded.freeTier.title": "تم الوصول إلى الحد المجاني",
|
|
50
|
+
"dialog.usageExceeded.freeTier.description":
|
|
51
|
+
"اشترك في OpenCode Go للحصول على وصول موثوق إلى أفضل النماذج مفتوحة المصدر، ابتداءً من $5/شهر.",
|
|
52
|
+
"dialog.usageExceeded.freeTier.actionLabel": "اشترك",
|
|
53
|
+
"dialog.usageExceeded.accountRateLimit.title": "تم الوصول إلى حد Go",
|
|
54
|
+
"dialog.usageExceeded.accountRateLimit.description":
|
|
55
|
+
"تم الوصول إلى حد الاستخدام. لمتابعة استخدام هذا النموذج الآن، قم بتفعيل الاستخدام من رصيدك المتاح",
|
|
56
|
+
"dialog.usageExceeded.accountRateLimit.actionLabel": "فتح الإعدادات",
|
|
57
|
+
|
|
58
|
+
"ui.sessionTurn.status.delegating": "تفويض العمل",
|
|
59
|
+
"ui.sessionTurn.status.planning": "تخطيط الخطوات التالية",
|
|
60
|
+
"ui.sessionTurn.status.gatheringContext": "استكشاف",
|
|
61
|
+
"ui.sessionTurn.status.gatheredContext": "تم الاستكشاف",
|
|
62
|
+
"ui.sessionTurn.status.searchingCodebase": "البحث في قاعدة التعليمات البرمجية",
|
|
63
|
+
"ui.sessionTurn.status.searchingWeb": "البحث في الويب",
|
|
64
|
+
"ui.sessionTurn.status.makingEdits": "إجراء تعديلات",
|
|
65
|
+
"ui.sessionTurn.status.runningCommands": "تشغيل الأوامر",
|
|
66
|
+
"ui.sessionTurn.status.thinking": "تفكير",
|
|
67
|
+
"ui.sessionTurn.status.thinkingWithTopic": "تفكير - {{topic}}",
|
|
68
|
+
"ui.sessionTurn.status.gatheringThoughts": "جمع الأفكار",
|
|
69
|
+
"ui.sessionTurn.status.consideringNextSteps": "النظر في الخطوات التالية",
|
|
70
|
+
|
|
71
|
+
"ui.messagePart.questions.dismissed": "تم رفض الأسئلة",
|
|
72
|
+
"ui.messagePart.compaction": "تم ضغط الجلسة",
|
|
73
|
+
"ui.messagePart.context.read.one": "{{count}} قراءة",
|
|
74
|
+
"ui.messagePart.context.read.other": "{{count}} قراءات",
|
|
75
|
+
"ui.messagePart.context.search.one": "{{count}} بحث",
|
|
76
|
+
"ui.messagePart.context.search.other": "{{count}} عمليات بحث",
|
|
77
|
+
"ui.messagePart.context.list.one": "{{count}} قائمة",
|
|
78
|
+
"ui.messagePart.context.list.other": "{{count}} قوائم",
|
|
79
|
+
"ui.messagePart.diagnostic.error": "خطأ",
|
|
80
|
+
"ui.messagePart.title.edit": "تحرير",
|
|
81
|
+
"ui.messagePart.title.write": "كتابة",
|
|
82
|
+
"ui.messagePart.option.typeOwnAnswer": "اكتب إجابتك الخاصة",
|
|
83
|
+
"ui.messagePart.review.title": "مراجعة إجاباتك",
|
|
84
|
+
|
|
85
|
+
"ui.list.loading": "جارٍ التحميل",
|
|
86
|
+
"ui.list.empty": "لا توجد نتائج",
|
|
87
|
+
"ui.list.clearFilter": "مسح عامل التصفية",
|
|
88
|
+
"ui.list.emptyWithFilter.prefix": "لا توجد نتائج لـ",
|
|
89
|
+
"ui.list.emptyWithFilter.suffix": "",
|
|
90
|
+
|
|
91
|
+
"ui.messageNav.newMessage": "رسالة جديدة",
|
|
92
|
+
|
|
93
|
+
"ui.textField.copyToClipboard": "نسخ إلى الحافظة",
|
|
94
|
+
"ui.textField.copyLink": "نسخ الرابط",
|
|
95
|
+
"ui.textField.copied": "تم النسخ",
|
|
96
|
+
|
|
97
|
+
"ui.imagePreview.alt": "معاينة الصورة",
|
|
98
|
+
"ui.scrollView.ariaLabel": "محتوى قابل للتمرير",
|
|
99
|
+
|
|
100
|
+
"ui.tool.read": "قراءة",
|
|
101
|
+
"ui.tool.loaded": "تم التحميل",
|
|
102
|
+
"ui.tool.list": "قائمة",
|
|
103
|
+
"ui.tool.glob": "Glob",
|
|
104
|
+
"ui.tool.grep": "Grep",
|
|
105
|
+
"ui.tool.webfetch": "جلب الويب",
|
|
106
|
+
"ui.tool.websearch": "بحث الويب",
|
|
107
|
+
"ui.tool.shell": "Shell",
|
|
108
|
+
"ui.tool.patch": "تصحيح",
|
|
109
|
+
"ui.tool.todos": "المهام",
|
|
110
|
+
"ui.tool.todos.read": "قراءة المهام",
|
|
111
|
+
"ui.tool.questions": "أسئلة",
|
|
112
|
+
"ui.tool.agent": "وكيل {{type}}",
|
|
113
|
+
"ui.tool.agent.default": "وكيل",
|
|
114
|
+
|
|
115
|
+
"ui.common.file.one": "ملف",
|
|
116
|
+
"ui.common.file.other": "ملفات",
|
|
117
|
+
"ui.common.question.one": "سؤال",
|
|
118
|
+
"ui.common.question.other": "أسئلة",
|
|
119
|
+
|
|
120
|
+
"ui.common.add": "إضافة",
|
|
121
|
+
"ui.common.back": "رجوع",
|
|
122
|
+
"ui.common.cancel": "إلغاء",
|
|
123
|
+
"ui.common.confirm": "تأكيد",
|
|
124
|
+
"ui.common.dismiss": "رفض",
|
|
125
|
+
"ui.common.close": "إغلاق",
|
|
126
|
+
"ui.common.next": "التالي",
|
|
127
|
+
"ui.common.submit": "إرسال",
|
|
128
|
+
|
|
129
|
+
"ui.permission.deny": "رفض",
|
|
130
|
+
"ui.permission.allowAlways": "السماح دائمًا",
|
|
131
|
+
"ui.permission.allowOnce": "السماح مرة واحدة",
|
|
132
|
+
|
|
133
|
+
"ui.message.expand": "توسيع الرسالة",
|
|
134
|
+
"ui.message.collapse": "طي الرسالة",
|
|
135
|
+
"ui.message.copy": "نسخ",
|
|
136
|
+
"ui.message.copyMessage": "نسخ الرسالة",
|
|
137
|
+
"ui.message.forkMessage": "تشعب إلى جلسة جديدة",
|
|
138
|
+
"ui.message.revertMessage": "إعادة التعيين إلى هذه النقطة",
|
|
139
|
+
"ui.message.copyResponse": "نسخ الرد",
|
|
140
|
+
"ui.message.copied": "تم النسخ!",
|
|
141
|
+
"ui.message.interrupted": "تمت المقاطعة",
|
|
142
|
+
"ui.message.queued": "في الانتظار",
|
|
143
|
+
"ui.message.attachment.alt": "مرفق",
|
|
144
|
+
|
|
145
|
+
"ui.patch.action.deleted": "محذوف",
|
|
146
|
+
"ui.patch.action.created": "تم الإنشاء",
|
|
147
|
+
"ui.patch.action.moved": "منقول",
|
|
148
|
+
"ui.patch.action.patched": "مصحح",
|
|
149
|
+
|
|
150
|
+
"ui.question.subtitle.answered": "{{count}} أجيب",
|
|
151
|
+
"ui.question.answer.none": "(لا توجد إجابة)",
|
|
152
|
+
"ui.question.review.notAnswered": "(لم يتم الرد)",
|
|
153
|
+
"ui.question.multiHint": "حدد كل ما ينطبق",
|
|
154
|
+
"ui.question.singleHint": "حدد إجابة واحدة",
|
|
155
|
+
"ui.question.custom.placeholder": "اكتب إجابتك...",
|
|
156
|
+
|
|
157
|
+
"ui.fileSearch.placeholder": "بحث",
|
|
158
|
+
"ui.fileSearch.previousMatch": "المطابقة السابقة",
|
|
159
|
+
"ui.fileSearch.nextMatch": "المطابقة التالية",
|
|
160
|
+
"ui.fileSearch.close": "إغلاق البحث",
|
|
161
|
+
"ui.tool.task": "مهمة",
|
|
162
|
+
"ui.tool.skill": "مهارة",
|
|
163
|
+
"ui.basicTool.called": "تم استدعاء `{{tool}}`",
|
|
164
|
+
"ui.toolErrorCard.failed": "فشل",
|
|
165
|
+
"ui.toolErrorCard.copyError": "نسخ الخطأ",
|
|
166
|
+
"ui.message.duration.seconds": "{{count}}ث",
|
|
167
|
+
"ui.message.duration.minutesSeconds": "{{minutes}}د {{seconds}}ث",
|
|
168
|
+
}
|