dsh-ide-git 0.5.3 → 0.5.5
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/dsh.plugin.json +1 -1
- package/package.json +1 -1
- package/src/client.js +191 -51
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-ide-git",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"description": "IDE 级 Git 操作面板:分支树 + 提交图谱 + 变更/暂存/提交 + 提交详情。装了 dsh-better-sidebar 时挂成它的原生 tab(右侧栏 + 底部工作台);没装时直接挂 DSH 原生右侧栏,单独安装即可用。JetBrains 风格 Git 工具窗口 for DeepSeek Harness.",
|
|
6
6
|
"engines": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-ide-git",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"description": "DSH plugin: an IDE-grade Git tool window as a native dsh-better-sidebar tab — branch tree, commit graph, changes, commit details, JetBrains-style actions, in the right sidebar and the bottom panel. | DSH 插件:IDE 级 Git 工具窗口,以 dsh-better-sidebar 原生 Tab 挂载——分支树 / 提交图谱 / 变更与提交详情 / JetBrains 风格操作,右侧栏与底部面板双布局自适应。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
package/src/client.js
CHANGED
|
@@ -34,6 +34,10 @@ window.__ModuleLoader__.load({
|
|
|
34
34
|
locale registry. */
|
|
35
35
|
const LOCALE_NS = 'dsh-ide-git'
|
|
36
36
|
const LANE_WIDTH = 14
|
|
37
|
+
/* Hard cap on the drawn lane columns. Lanes beyond the cap collapse into
|
|
38
|
+
the last column: without the cap a branchy repository pushed the graph
|
|
39
|
+
wider than the panel and shoved the subject column out of view. */
|
|
40
|
+
const GRAPH_MAX_LANES = 7
|
|
37
41
|
const LANE_COLORS = ['#4d6bfe', '#e2a03f', '#3fb950', '#d2679b', '#59b0d6', '#b083f0', '#d2694a', '#8a9aa8']
|
|
38
42
|
const AUTO_REFRESH_MS = 12000
|
|
39
43
|
const REPO_KEY = 'dsh-ide-git.repo.v1'
|
|
@@ -3521,7 +3525,23 @@ window.__ModuleLoader__.load({
|
|
|
3521
3525
|
/* ============================== commit graph ============================== */
|
|
3522
3526
|
|
|
3523
3527
|
function buildRows(commits) {
|
|
3528
|
+
/* The log is a WINDOW: the oldest visible commits usually have parents
|
|
3529
|
+
that were never loaded. A parent outside the window must not park its
|
|
3530
|
+
hash on a lane — the lane would stay occupied for the rest of the
|
|
3531
|
+
page (the hash can never be consumed), every later branch tip would
|
|
3532
|
+
claim yet another fresh lane, and the drawing degenerated into a
|
|
3533
|
+
bundle of independent parallel lines that pushed the subjects out of
|
|
3534
|
+
the panel. So the pass first learns which hashes are actually on the
|
|
3535
|
+
board, and an edge to anything else simply ends at its commit. */
|
|
3536
|
+
const present = new Set()
|
|
3537
|
+
for (const commit of commits) present.add(commit.hash)
|
|
3524
3538
|
const lanes = []
|
|
3539
|
+
/* The current branch keeps the LEFTMOST column whenever it is on the
|
|
3540
|
+
board: pre-seeding its hash makes that commit claim lane 0 when its
|
|
3541
|
+
row arrives, so HEAD's line never drifts to the right of a side
|
|
3542
|
+
branch (the rest of the lanes fill newest-first, see below). */
|
|
3543
|
+
const headCommit = commits.find((commit) => Array.isArray(commit.refs) && commit.refs.some((ref) => String(ref).indexOf('HEAD') >= 0))
|
|
3544
|
+
if (headCommit !== undefined) lanes.push(headCommit.hash)
|
|
3525
3545
|
const rows = []
|
|
3526
3546
|
for (const commit of commits) {
|
|
3527
3547
|
const before = lanes.slice()
|
|
@@ -3538,24 +3558,30 @@ window.__ModuleLoader__.load({
|
|
|
3538
3558
|
a branch that merged back into a lane to its left kept a stub of its
|
|
3539
3559
|
own colour running on above the junction — a fork that never
|
|
3540
3560
|
happened. Only a parent that is not on the board yet inherits the
|
|
3541
|
-
lane,
|
|
3561
|
+
lane, and (v0.5.4) only a parent that is on the board at all: a
|
|
3562
|
+
parent past the loaded window ends the lane at this row instead of
|
|
3563
|
+
holding it for a commit that will never arrive. */
|
|
3542
3564
|
if (parents.length > 0) {
|
|
3543
3565
|
const first = lanes.indexOf(parents[0])
|
|
3544
3566
|
if (first !== -1 && first !== lane) {
|
|
3545
3567
|
lanes[lane] = null
|
|
3546
3568
|
parentLanes.push(first)
|
|
3547
|
-
} else {
|
|
3569
|
+
} else if (present.has(parents[0])) {
|
|
3548
3570
|
lanes[lane] = parents[0]
|
|
3571
|
+
} else {
|
|
3572
|
+
lanes[lane] = null
|
|
3549
3573
|
}
|
|
3550
3574
|
} else {
|
|
3551
3575
|
lanes[lane] = null
|
|
3552
3576
|
}
|
|
3553
3577
|
for (let index = 1; index < parents.length; index += 1) {
|
|
3554
|
-
|
|
3578
|
+
const parent = parents[index]
|
|
3579
|
+
if (!present.has(parent)) continue
|
|
3580
|
+
let slot = lanes.indexOf(parent)
|
|
3555
3581
|
if (slot === -1) {
|
|
3556
3582
|
slot = lanes.indexOf(null)
|
|
3557
|
-
if (slot === -1) { lanes.push(
|
|
3558
|
-
else lanes[slot] =
|
|
3583
|
+
if (slot === -1) { lanes.push(parent); slot = lanes.length - 1 }
|
|
3584
|
+
else lanes[slot] = parent
|
|
3559
3585
|
}
|
|
3560
3586
|
parentLanes.push(slot)
|
|
3561
3587
|
}
|
|
@@ -3573,28 +3599,46 @@ window.__ModuleLoader__.load({
|
|
|
3573
3599
|
centre where the lane genuinely starts (a branch tip) or ends (a root).
|
|
3574
3600
|
v0.1.7 started every non-own lane at 0 and every own lane at height/2, which
|
|
3575
3601
|
left a visible gap between two consecutive commits on the same lane. */
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3602
|
+
/* Vertical lane segments for one row. A lane that this row OPENS through an
|
|
3603
|
+
edge curve (it was empty above, and the curve lands at the row bottom) must
|
|
3604
|
+
NOT also get a vertical segment from the row centre: the two overlapped and
|
|
3605
|
+
left a floating hook where the line visibly started in mid-air — reported
|
|
3606
|
+
twice by the user as "断开的线/无端点的分叉". The curve alone carries the
|
|
3607
|
+
connection, and the next row's segment starts at its top edge. */
|
|
3608
|
+
function laneSegments(row, height) {
|
|
3580
3609
|
const middle = height / 2
|
|
3581
|
-
const children = []
|
|
3582
|
-
const x = (lane) => 8 + lane * LANE_WIDTH
|
|
3583
|
-
const color = (lane) => LANE_COLORS[lane % LANE_COLORS.length]
|
|
3584
3610
|
const depth = Math.max(row.before.length, row.after.length)
|
|
3611
|
+
const segments = []
|
|
3585
3612
|
for (let lane = 0; lane < depth; lane += 1) {
|
|
3586
3613
|
const above = lane < row.before.length ? row.before[lane] : null
|
|
3587
3614
|
const below = lane < row.after.length ? row.after[lane] : null
|
|
3588
3615
|
const hasTop = above !== null && above !== undefined
|
|
3589
3616
|
const hasBottom = below !== null && below !== undefined
|
|
3590
3617
|
if (hasTop === false && hasBottom === false) continue
|
|
3618
|
+
if (hasTop === false && row.parentLanes.indexOf(lane) >= 0) continue
|
|
3591
3619
|
const y1 = hasTop ? 0 : middle
|
|
3592
3620
|
const y2 = hasBottom ? height : middle
|
|
3593
3621
|
if (y1 === y2) continue
|
|
3622
|
+
segments.push({ lane: lane, y1: y1, y2: y2 })
|
|
3623
|
+
}
|
|
3624
|
+
return segments
|
|
3625
|
+
}
|
|
3626
|
+
|
|
3627
|
+
function GraphCell(props) {
|
|
3628
|
+
const row = props.row
|
|
3629
|
+
const height = props.height
|
|
3630
|
+
const width = Math.min(Math.max(1, row.width), GRAPH_MAX_LANES) * LANE_WIDTH + 8
|
|
3631
|
+
const middle = height / 2
|
|
3632
|
+
const children = []
|
|
3633
|
+
/* Lanes beyond the cap share the last column: the geometry stays bounded
|
|
3634
|
+
and the subject column keeps its room. */
|
|
3635
|
+
const x = (lane) => 8 + Math.min(lane, GRAPH_MAX_LANES - 1) * LANE_WIDTH
|
|
3636
|
+
const color = (lane) => LANE_COLORS[lane % LANE_COLORS.length]
|
|
3637
|
+
for (const segment of laneSegments(row, height)) {
|
|
3594
3638
|
children.push(E('line', {
|
|
3595
|
-
key: 'lane-' + lane,
|
|
3596
|
-
x1: x(lane), y1: y1, x2: x(lane), y2: y2,
|
|
3597
|
-
stroke: color(lane), strokeWidth: 2, strokeLinecap: 'round',
|
|
3639
|
+
key: 'lane-' + segment.lane,
|
|
3640
|
+
x1: x(segment.lane), y1: segment.y1, x2: x(segment.lane), y2: segment.y2,
|
|
3641
|
+
stroke: color(segment.lane), strokeWidth: 2, strokeLinecap: 'round',
|
|
3598
3642
|
}))
|
|
3599
3643
|
}
|
|
3600
3644
|
for (const parentLane of row.parentLanes) {
|
|
@@ -3898,20 +3942,56 @@ window.__ModuleLoader__.load({
|
|
|
3898
3942
|
|
|
3899
3943
|
function RepoSelect(props) {
|
|
3900
3944
|
const t = props.t
|
|
3945
|
+
/* While the workspace is still being scanned the panel used to print "no
|
|
3946
|
+
repository found" — a verdict nobody had reached yet. A deep workspace
|
|
3947
|
+
scan takes seconds, so that premature verdict sat on screen long enough
|
|
3948
|
+
to look like the final answer. Loading shows loading; "not found" only
|
|
3949
|
+
shows once the scan came back empty. */
|
|
3950
|
+
if (props.loading === true) {
|
|
3951
|
+
return E('span', { className: 'dig-repo-static' },
|
|
3952
|
+
E(Icon, { name: 'folder', size: 12 }),
|
|
3953
|
+
E('span', { className: 'dig-repo-name' }, t('status.loading')))
|
|
3954
|
+
}
|
|
3901
3955
|
if (props.repos.length <= 1) {
|
|
3902
3956
|
const only = props.repos.length === 1 ? props.repos[0] : null
|
|
3903
3957
|
return E('span', { className: 'dig-repo-static', title: only === null ? '' : only.path },
|
|
3904
3958
|
E(Icon, { name: 'folder', size: 12 }),
|
|
3905
3959
|
E('span', { className: 'dig-repo-name' }, only === null ? t('repo.empty') : only.name))
|
|
3906
3960
|
}
|
|
3961
|
+
/* The switcher is a button over a panel-internal menu, not a native
|
|
3962
|
+
<select>: the OS-drawn popup ignores the panel theme entirely (light
|
|
3963
|
+
system colours over a dark translucent panel) and was unreadable. */
|
|
3964
|
+
let current = null
|
|
3965
|
+
for (const repo of props.repos) { if (repo.path === props.value) { current = repo; break } }
|
|
3907
3966
|
return E('span', { className: 'dig-select-wrap', title: t('repo.switch') },
|
|
3908
3967
|
E(Icon, { name: 'folder', size: 12 }),
|
|
3909
|
-
E('
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
},
|
|
3914
|
-
|
|
3968
|
+
E('button', {
|
|
3969
|
+
type: 'button',
|
|
3970
|
+
className: 'dig-select dig-select-btn dig-select-repo',
|
|
3971
|
+
onClick: props.onOpenMenu,
|
|
3972
|
+
},
|
|
3973
|
+
E('span', { className: 'dig-repo-name' },
|
|
3974
|
+
current === null ? t('repo.pick') : current.name + (current.branch === null || current.branch === undefined ? '' : ' · ' + current.branch)),
|
|
3975
|
+
E(Icon, { name: 'chevron', size: 12 })))
|
|
3976
|
+
}
|
|
3977
|
+
|
|
3978
|
+
/* The history filters were the LAST native <select>s: their popup is drawn
|
|
3979
|
+
by the OS, so a dark translucent panel still got a light system list —
|
|
3980
|
+
reported on v0.5.4 ("only the one at the top was replaced"). Same
|
|
3981
|
+
treatment as the header switchers: a button over a panel-internal menu. */
|
|
3982
|
+
function FilterSelect(props) {
|
|
3983
|
+
const options = Array.isArray(props.options) ? props.options : []
|
|
3984
|
+
let current = options[0]
|
|
3985
|
+
for (const option of options) { if (option.value === props.value) { current = option; break } }
|
|
3986
|
+
const label = props.label + ': ' + (current === undefined ? '' : current.label)
|
|
3987
|
+
return E('button', {
|
|
3988
|
+
type: 'button',
|
|
3989
|
+
className: 'dig-filter-select' + (props.value === '' ? '' : ' dig-filter-on'),
|
|
3990
|
+
title: props.hint === undefined ? label : props.hint,
|
|
3991
|
+
onClick: (event) => { if (props.onOpenMenu !== undefined) props.onOpenMenu(event, options) },
|
|
3992
|
+
},
|
|
3993
|
+
E('span', { className: 'dig-filter-label' }, label),
|
|
3994
|
+
E(Icon, { name: 'chevron', size: 11 }))
|
|
3915
3995
|
}
|
|
3916
3996
|
|
|
3917
3997
|
function RepoPicker(props) {
|
|
@@ -4336,31 +4416,45 @@ window.__ModuleLoader__.load({
|
|
|
4336
4416
|
applyPath('')
|
|
4337
4417
|
}
|
|
4338
4418
|
|
|
4339
|
-
|
|
4419
|
+
/* Every filter opens the same in-panel menu; a checked row marks the active
|
|
4420
|
+
value, so the button never has to spell the whole list out. */
|
|
4421
|
+
const openFilterMenu = (event, options, currentValue, onPick) => {
|
|
4422
|
+
if (props.openMenuAt === undefined) return
|
|
4423
|
+
props.openMenuAt(event, options.map((option) => ({
|
|
4424
|
+
id: 'filter:' + String(option.value),
|
|
4425
|
+
icon: option.value === '' ? 'filter' : 'check',
|
|
4426
|
+
tone: option.value === '' ? 'secondary' : 'accent',
|
|
4427
|
+
label: option.label,
|
|
4428
|
+
active: option.value === currentValue,
|
|
4429
|
+
run: () => onPick(option.value),
|
|
4430
|
+
})))
|
|
4431
|
+
}
|
|
4432
|
+
const allOption = { value: '', label: t('filter.all') }
|
|
4433
|
+
const filterBar = props.hideSearch === true ? null : E('div', { className: 'dig-filters' },
|
|
4340
4434
|
E('input', {
|
|
4341
4435
|
className: 'dig-input dig-input-compact dig-filter-text', value: text, spellCheck: false,
|
|
4342
4436
|
placeholder: t('history.filter'),
|
|
4343
4437
|
onChange: (event) => setText(event.target.value),
|
|
4344
4438
|
}),
|
|
4345
|
-
E(
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
E(
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
E(
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4439
|
+
E(FilterSelect, {
|
|
4440
|
+
label: t('filter.branch'), value: refName, hint: t('filter.branch'),
|
|
4441
|
+
options: [allOption].concat(refOptions.map((name) => ({ value: name, label: name }))),
|
|
4442
|
+
onOpenMenu: (event, options) => openFilterMenu(event, options, refName, setRefName),
|
|
4443
|
+
}),
|
|
4444
|
+
E(FilterSelect, {
|
|
4445
|
+
label: t('filter.user'), value: author, hint: t('filter.user'),
|
|
4446
|
+
options: [allOption].concat(authors.map((name) => ({ value: name, label: name }))),
|
|
4447
|
+
onOpenMenu: (event, options) => openFilterMenu(event, options, author, setAuthor),
|
|
4448
|
+
}),
|
|
4449
|
+
E(FilterSelect, {
|
|
4450
|
+
label: t('filter.date'), value: since, hint: t('filter.date'),
|
|
4451
|
+
options: [allOption,
|
|
4452
|
+
{ value: 'today', label: t('filter.today') },
|
|
4453
|
+
{ value: 'week', label: t('filter.week') },
|
|
4454
|
+
{ value: 'month', label: t('filter.month') },
|
|
4455
|
+
{ value: 'year', label: t('filter.year') }],
|
|
4456
|
+
onOpenMenu: (event, options) => openFilterMenu(event, options, since, setSince),
|
|
4457
|
+
}),
|
|
4364
4458
|
E('form', {
|
|
4365
4459
|
className: 'dig-filter-path',
|
|
4366
4460
|
onSubmit: (event) => { event.preventDefault(); applyPath(pathDraft.trim()) },
|
|
@@ -4550,7 +4644,10 @@ window.__ModuleLoader__.load({
|
|
|
4550
4644
|
}, [repoRoot])
|
|
4551
4645
|
|
|
4552
4646
|
useEffect(() => {
|
|
4553
|
-
|
|
4647
|
+
/* No workspace attached: there is nothing to scan, so land the empty
|
|
4648
|
+
result straight away instead of leaving repoState null (which reads
|
|
4649
|
+
as "still loading" and would spin forever). */
|
|
4650
|
+
if (cwd === undefined) { setRepoState({ repos: [], isRepo: false }); return undefined }
|
|
4554
4651
|
let cancelled = false
|
|
4555
4652
|
void (async () => {
|
|
4556
4653
|
try {
|
|
@@ -4860,15 +4957,47 @@ window.__ModuleLoader__.load({
|
|
|
4860
4957
|
const repoOptions = repoState === null ? [] : repoState.repos
|
|
4861
4958
|
const dirty = summary === null ? 0 : summary.changes.staged.length + summary.changes.unstaged.length + summary.changes.untracked.length + summary.changes.conflicted.length
|
|
4862
4959
|
|
|
4960
|
+
/* Both header switchers are menu-driven now (see RepoSelect): the
|
|
4961
|
+
popovers reuse openMenuAt, so they clamp to the panel box and share
|
|
4962
|
+
the opaque, frosted menu surface instead of the OS select popup. */
|
|
4963
|
+
const openRepoMenu = useCallback((event) => {
|
|
4964
|
+
openMenuAt(event, repoOptions.map((repo) => ({
|
|
4965
|
+
id: 'repo:' + repo.path,
|
|
4966
|
+
icon: 'folder',
|
|
4967
|
+
tone: 'accent',
|
|
4968
|
+
label: repo.name + (repo.branch === null || repo.branch === undefined ? '' : ' · ' + repo.branch),
|
|
4969
|
+
active: repo.path === repoRoot,
|
|
4970
|
+
run: () => { if (repo.path !== repoRoot) pickRepo(repo.path) },
|
|
4971
|
+
})))
|
|
4972
|
+
}, [openMenuAt, repoOptions, repoRoot, pickRepo])
|
|
4973
|
+
|
|
4974
|
+
const openBranchSwitchMenu = useCallback((event) => {
|
|
4975
|
+
const local = branches === null ? [] : branches.local
|
|
4976
|
+
openMenuAt(event, local.map((entry) => ({
|
|
4977
|
+
id: 'switch:' + entry.name,
|
|
4978
|
+
icon: entry.head === true ? 'star' : 'branch',
|
|
4979
|
+
tone: entry.head === true ? 'warn' : 'accent',
|
|
4980
|
+
label: entry.name,
|
|
4981
|
+
active: entry.head === true,
|
|
4982
|
+
run: () => { if (entry.head !== true) void checkout(entry) },
|
|
4983
|
+
})))
|
|
4984
|
+
}, [openMenuAt, branches, checkout])
|
|
4985
|
+
|
|
4863
4986
|
const topBar = E('div', { className: 'dig-topbar' },
|
|
4864
|
-
E(RepoSelect, {
|
|
4987
|
+
E(RepoSelect, {
|
|
4988
|
+
t: t, repos: repoOptions, value: repoRoot,
|
|
4989
|
+
loading: repoState === null,
|
|
4990
|
+
onOpenMenu: openRepoMenu,
|
|
4991
|
+
}),
|
|
4865
4992
|
branches === null || branches.local.length === 0 ? null : E('span', { className: 'dig-select-wrap', title: t('branch.switch') },
|
|
4866
4993
|
E(Icon, { name: 'branch', size: 12 }),
|
|
4867
|
-
E('
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
},
|
|
4994
|
+
E('button', {
|
|
4995
|
+
type: 'button',
|
|
4996
|
+
className: 'dig-select dig-select-btn dig-select-branch',
|
|
4997
|
+
onClick: openBranchSwitchMenu,
|
|
4998
|
+
},
|
|
4999
|
+
E('span', { className: 'dig-repo-name' }, branches.branch),
|
|
5000
|
+
E(Icon, { name: 'chevron', size: 12 }))),
|
|
4872
5001
|
summary === null || summary.upstream === null ? null : E('span', { className: 'dig-track' },
|
|
4873
5002
|
(summary.ahead > 0 ? '↑' + summary.ahead : '') + (summary.behind > 0 ? ' ↓' + summary.behind : '')),
|
|
4874
5003
|
operation === null ? null : E('span', { className: 'dig-opchip', title: t('operation.hint') }, t('operation.' + operation)),
|
|
@@ -4918,7 +5047,7 @@ window.__ModuleLoader__.load({
|
|
|
4918
5047
|
})
|
|
4919
5048
|
: E(HistoryList, {
|
|
4920
5049
|
t: t, commits: commits, hasMore: hasMore, busy: busy, selectedHash: selectedHash,
|
|
4921
|
-
hideSearch: compact, pathFilter: pathFilter,
|
|
5050
|
+
hideSearch: compact, pathFilter: pathFilter, openMenuAt: openMenuAt,
|
|
4922
5051
|
onPathFilter: (value) => setPathFilter(value),
|
|
4923
5052
|
onSelect: (commit) => { void selectCommit(commit) },
|
|
4924
5053
|
onMenu: commitMenu,
|
|
@@ -5098,7 +5227,12 @@ window.__ModuleLoader__.load({
|
|
|
5098
5227
|
/* ---------- body per chrome ---------- */
|
|
5099
5228
|
|
|
5100
5229
|
let body
|
|
5101
|
-
if (
|
|
5230
|
+
if (repoState === null) {
|
|
5231
|
+
/* The scan is still running: a neutral loading state, never the
|
|
5232
|
+
"no repository found" verdict (that text is reserved for a scan
|
|
5233
|
+
that actually came back empty). */
|
|
5234
|
+
body = E('div', { className: 'dig-body' }, E('div', { className: 'dig-empty' }, t('status.loading')))
|
|
5235
|
+
} else if (repoRoot === null) {
|
|
5102
5236
|
body = E('div', { className: 'dig-body' }, E(RepoPicker, {
|
|
5103
5237
|
t: t, cwd: cwd === undefined ? '' : cwd, repos: repoOptions, onPick: pickRepo,
|
|
5104
5238
|
}))
|
|
@@ -5282,7 +5416,10 @@ window.__ModuleLoader__.load({
|
|
|
5282
5416
|
'.dig-select{appearance:none;-webkit-appearance:none;background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;color:var(--dsw-alias-label-primary);font:inherit;font-weight:500;padding:1px 6px;height:22px;max-width:190px;min-width:0;cursor:pointer;text-overflow:ellipsis}',
|
|
5283
5417
|
'.dig-select:hover{background:var(--dsw-alias-interactive-bg-hover)}',
|
|
5284
5418
|
'.dig-select:focus{outline:1px solid var(--dsw-alias-brand-primary);outline-offset:-1px}',
|
|
5419
|
+
'.dig-select-btn{display:inline-flex;align-items:center;gap:4px;text-align:left;white-space:nowrap;overflow:hidden}',
|
|
5420
|
+
'.dig-select-btn .dig-repo-name{flex:1;min-width:0;max-width:none}',
|
|
5285
5421
|
'.dig-select-repo{max-width:200px}',
|
|
5422
|
+
'.dig-select option,.dig-filter-select option{background:var(--dsw-alias-bg-layer-1,#22262e);color:var(--dsw-alias-label-primary,#e6e8ee)}',
|
|
5286
5423
|
'.dig-select-branch{max-width:150px}',
|
|
5287
5424
|
'.dig-repo-static{display:inline-flex;align-items:center;gap:5px;min-width:0;color:var(--dsw-alias-label-secondary)}',
|
|
5288
5425
|
'.dig-repo-name{color:var(--dsw-alias-label-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:200px}',
|
|
@@ -5415,6 +5552,9 @@ window.__ModuleLoader__.load({
|
|
|
5415
5552
|
'.dig-filter-text{flex:1 1 90px;min-width:80px;width:auto}',
|
|
5416
5553
|
'.dig-filter-select{flex:none;max-width:118px;appearance:none;-webkit-appearance:none;background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;color:var(--dsw-alias-label-secondary);font:inherit;font-weight:500;height:22px;padding:0 4px;cursor:pointer;text-overflow:ellipsis}',
|
|
5417
5554
|
'.dig-filter-select:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}',
|
|
5555
|
+
'.dig-filter-select{display:inline-flex;align-items:center;gap:3px}',
|
|
5556
|
+
'.dig-filter-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:96px}',
|
|
5557
|
+
'.dig-filter-on{color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}',
|
|
5418
5558
|
'.dig-filter-path{flex:0 1 112px;min-width:70px;display:flex}',
|
|
5419
5559
|
'.dig-load-more{margin:6px auto;display:block;padding:3px 12px;border-radius:6px;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer}',
|
|
5420
5560
|
'.dig-load-more:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}',
|
|
@@ -5478,7 +5618,7 @@ window.__ModuleLoader__.load({
|
|
|
5478
5618
|
'.dig-dialog-text{color:var(--dsw-alias-label-secondary);white-space:pre-wrap}',
|
|
5479
5619
|
'.dig-dialog-actions{display:flex;justify-content:flex-end;gap:8px}',
|
|
5480
5620
|
'.dig-dialog-actions .dig-btn-primary{margin-left:0}',
|
|
5481
|
-
'.dig-menu{position:absolute;z-index:70;min-width:200px;max-width:calc(100% - 8px);max-height:calc(100% - 8px);overflow:auto;overscroll-behavior:contain;padding:4px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-layer-1));border:1px solid var(--dsw-alias-border-l2);box-shadow:0 10px 28px rgba(0,0,0,.35);display:flex;flex-direction:column}',
|
|
5621
|
+
'.dig-menu{position:absolute;z-index:70;min-width:200px;max-width:calc(100% - 8px);max-height:calc(100% - 8px);overflow:auto;overscroll-behavior:contain;padding:4px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-layer-1));-webkit-backdrop-filter:var(--dsh-any-blur-card-panels,blur(14px) saturate(1.2));backdrop-filter:var(--dsh-any-blur-card-panels,blur(14px) saturate(1.2));border:1px solid var(--dsw-alias-border-l2);box-shadow:0 10px 28px rgba(0,0,0,.35);display:flex;flex-direction:column}',
|
|
5482
5622
|
'.dig-menu-item{display:flex;align-items:center;gap:8px;padding:4px 8px;border:none;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-weight:500;text-align:left;border-radius:5px;cursor:pointer;white-space:nowrap;overflow:hidden}',
|
|
5483
5623
|
'.dig-menu-icon{display:inline-flex;flex:none}',
|
|
5484
5624
|
'.dig-menu-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}',
|