@lark-apaas/coding-registry-buildless 0.1.1 → 0.1.2-beta.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/components/android-frame.jsx +0 -1
- package/components/animations.jsx +179 -86
- package/components/browser-window.jsx +1 -1
- package/components/design-canvas.jsx +221 -97
- package/components/ios-frame.jsx +5 -5
- package/components/macos-window.jsx +1 -1
- package/components/tweaks-panel.jsx +7 -0
- package/package.json +14 -3
- package/scripts/deck-stage.js +563 -371
|
@@ -123,7 +123,6 @@ function AndroidDevice({
|
|
|
123
123
|
width, height, borderRadius: 18, overflow: 'hidden',
|
|
124
124
|
background: dark ? '#1d1b20' : MD_C.surface,
|
|
125
125
|
border: `8px solid ${MD_C.frameBorder}`,
|
|
126
|
-
boxShadow: '0 30px 80px rgba(0,0,0,0.25)',
|
|
127
126
|
display: 'flex', flexDirection: 'column', boxSizing: 'border-box',
|
|
128
127
|
}}>
|
|
129
128
|
<AndroidStatusBar dark={dark} />
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
//
|
|
13
13
|
// <Stage> auto-scales to the viewport and provides the scrubber, play/pause,
|
|
14
14
|
// ←/→ seek, space, and 0-to-reset controls, and persists the playhead.
|
|
15
|
+
// Set the optional `poster` prop (seconds) to the moment your opening scene is
|
|
16
|
+
// fully composed — the product thumbnail freezes on that frame (default ~1s).
|
|
15
17
|
// Inside <Stage>, any child can call useTime() to read the current
|
|
16
18
|
// playhead (seconds). Or wrap content in <Sprite start={1} end={4}>...</Sprite>
|
|
17
19
|
// to only render during that window -- children receive a `localTime` and
|
|
@@ -335,17 +337,24 @@ function Stage({
|
|
|
335
337
|
fps = 60,
|
|
336
338
|
loop = true,
|
|
337
339
|
autoplay = true,
|
|
340
|
+
poster = null,
|
|
338
341
|
persistKey = 'animstage',
|
|
339
342
|
children,
|
|
340
343
|
}) {
|
|
344
|
+
// Thumbnail capture mode: the host appends ?thumbnail=1 before screenshotting.
|
|
345
|
+
// Freeze on a representative still — the author-declared `poster` second, or
|
|
346
|
+
// ~1s as a fallback — paused, with the playback bar hidden, so the product
|
|
347
|
+
// thumbnail is a deterministic frame of the first composed scene.
|
|
348
|
+
const captureMode = typeof location !== 'undefined' && /[?&]thumbnail=/.test(location.search || '');
|
|
349
|
+
|
|
341
350
|
const [time, setTime] = React.useState(() => {
|
|
351
|
+
if (captureMode) return clamp(poster == null ? 1 : poster, 0, duration);
|
|
342
352
|
try {
|
|
343
353
|
const v = parseFloat(localStorage.getItem(persistKey + ':t') || '0');
|
|
344
354
|
return isFinite(v) ? clamp(v, 0, duration) : 0;
|
|
345
355
|
} catch { return 0; }
|
|
346
356
|
});
|
|
347
|
-
const [playing, setPlaying] = React.useState(autoplay);
|
|
348
|
-
const [hoverTime, setHoverTime] = React.useState(null);
|
|
357
|
+
const [playing, setPlaying] = React.useState(captureMode ? false : autoplay);
|
|
349
358
|
const [scale, setScale] = React.useState(1);
|
|
350
359
|
|
|
351
360
|
const stageRef = React.useRef(null);
|
|
@@ -363,7 +372,7 @@ function Stage({
|
|
|
363
372
|
if (!stageRef.current) return;
|
|
364
373
|
const el = stageRef.current;
|
|
365
374
|
const measure = () => {
|
|
366
|
-
const barH = 44; // playback bar height
|
|
375
|
+
const barH = captureMode ? 0 : 44; // playback bar height (hidden in capture mode)
|
|
367
376
|
const s = Math.min(
|
|
368
377
|
el.clientWidth / width,
|
|
369
378
|
(el.clientHeight - barH) / height
|
|
@@ -426,11 +435,9 @@ function Stage({
|
|
|
426
435
|
return () => window.removeEventListener('keydown', onKey);
|
|
427
436
|
}, [duration]);
|
|
428
437
|
|
|
429
|
-
const displayTime = hoverTime != null ? hoverTime : time;
|
|
430
|
-
|
|
431
438
|
const ctxValue = React.useMemo(
|
|
432
|
-
() => ({ time
|
|
433
|
-
[
|
|
439
|
+
() => ({ time, duration, playing, setTime, setPlaying }),
|
|
440
|
+
[time, duration, playing]
|
|
434
441
|
);
|
|
435
442
|
|
|
436
443
|
return (
|
|
@@ -471,17 +478,18 @@ function Stage({
|
|
|
471
478
|
</div>
|
|
472
479
|
</div>
|
|
473
480
|
|
|
474
|
-
{/* Playback bar — stacked below canvas, never overlapping
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
481
|
+
{/* Playback bar — stacked below canvas, never overlapping. Hidden in
|
|
482
|
+
capture mode so the thumbnail is just the frame, no chrome. */}
|
|
483
|
+
{!captureMode && (
|
|
484
|
+
<PlaybackBar
|
|
485
|
+
time={time}
|
|
486
|
+
duration={duration}
|
|
487
|
+
playing={playing}
|
|
488
|
+
onPlayPause={() => setPlaying(p => !p)}
|
|
489
|
+
onReset={() => { setTime(0); }}
|
|
490
|
+
onSeek={(t) => setTime(t)}
|
|
491
|
+
/>
|
|
492
|
+
)}
|
|
485
493
|
</div>
|
|
486
494
|
);
|
|
487
495
|
}
|
|
@@ -490,43 +498,56 @@ function Stage({
|
|
|
490
498
|
// Play/pause, return-to-begin, scrub track, time display.
|
|
491
499
|
// Uses fixed-width time fields so layout doesn't thrash.
|
|
492
500
|
|
|
493
|
-
function PlaybackBar({ time, duration, playing, onPlayPause, onReset, onSeek
|
|
501
|
+
function PlaybackBar({ time, duration, playing, onPlayPause, onReset, onSeek }) {
|
|
494
502
|
const trackRef = React.useRef(null);
|
|
495
503
|
const [dragging, setDragging] = React.useState(false);
|
|
504
|
+
const [trackHover, setTrackHover] = React.useState(null); // { x, t } — px within track + hovered time
|
|
496
505
|
|
|
497
|
-
const
|
|
506
|
+
const posFromEvent = React.useCallback((e) => {
|
|
498
507
|
const rect = trackRef.current.getBoundingClientRect();
|
|
499
|
-
const x = clamp(
|
|
500
|
-
|
|
508
|
+
const x = clamp(e.clientX - rect.left, 0, rect.width);
|
|
509
|
+
const t = rect.width > 0 ? (x / rect.width) * duration : 0;
|
|
510
|
+
return { x, t };
|
|
501
511
|
}, [duration]);
|
|
502
512
|
|
|
503
513
|
const onTrackMove = (e) => {
|
|
504
514
|
if (!trackRef.current) return;
|
|
505
|
-
const t =
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
} else {
|
|
509
|
-
onHover(t);
|
|
510
|
-
}
|
|
515
|
+
const { x, t } = posFromEvent(e);
|
|
516
|
+
setTrackHover({ x, t });
|
|
517
|
+
if (dragging) onSeek(t);
|
|
511
518
|
};
|
|
512
519
|
|
|
513
520
|
const onTrackLeave = () => {
|
|
514
|
-
if (!dragging)
|
|
521
|
+
if (!dragging) setTrackHover(null);
|
|
515
522
|
};
|
|
516
523
|
|
|
517
524
|
const onTrackDown = (e) => {
|
|
525
|
+
const { x, t } = posFromEvent(e);
|
|
518
526
|
setDragging(true);
|
|
519
|
-
|
|
527
|
+
setTrackHover({ x, t });
|
|
520
528
|
onSeek(t);
|
|
521
|
-
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
// Grab the knob in place: begin dragging without seeking (no jump).
|
|
532
|
+
// stopPropagation keeps the track's click-to-seek from also firing.
|
|
533
|
+
const onBallDown = (e) => {
|
|
534
|
+
e.stopPropagation();
|
|
535
|
+
setDragging(true);
|
|
536
|
+
setTrackHover(posFromEvent(e));
|
|
522
537
|
};
|
|
523
538
|
|
|
524
539
|
React.useEffect(() => {
|
|
525
540
|
if (!dragging) return;
|
|
526
|
-
const
|
|
541
|
+
const prevCursor = document.body.style.cursor;
|
|
542
|
+
document.body.style.cursor = 'grabbing'; // stays grabbing even if the pointer leaves the knob mid-drag
|
|
543
|
+
const onUp = () => {
|
|
544
|
+
setDragging(false);
|
|
545
|
+
setTrackHover(null);
|
|
546
|
+
};
|
|
527
547
|
const onMove = (e) => {
|
|
528
548
|
if (!trackRef.current) return;
|
|
529
|
-
const t =
|
|
549
|
+
const { x, t } = posFromEvent(e);
|
|
550
|
+
setTrackHover({ x, t });
|
|
530
551
|
onSeek(t);
|
|
531
552
|
};
|
|
532
553
|
window.addEventListener('mouseup', onUp);
|
|
@@ -534,66 +555,60 @@ function PlaybackBar({ time, duration, playing, onPlayPause, onReset, onSeek, on
|
|
|
534
555
|
return () => {
|
|
535
556
|
window.removeEventListener('mouseup', onUp);
|
|
536
557
|
window.removeEventListener('mousemove', onMove);
|
|
558
|
+
document.body.style.cursor = prevCursor;
|
|
537
559
|
};
|
|
538
|
-
}, [dragging,
|
|
560
|
+
}, [dragging, posFromEvent, onSeek]);
|
|
539
561
|
|
|
540
562
|
const pct = duration > 0 ? (time / duration) * 100 : 0;
|
|
541
563
|
const fmt = (t) => {
|
|
542
564
|
const total = Math.max(0, t);
|
|
543
565
|
const m = Math.floor(total / 60);
|
|
544
566
|
const s = Math.floor(total % 60);
|
|
545
|
-
|
|
546
|
-
return `${String(m).padStart(1, '0')}:${String(s).padStart(2, '0')}.${String(cs).padStart(2, '0')}`;
|
|
567
|
+
return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
|
|
547
568
|
};
|
|
548
569
|
|
|
549
|
-
const
|
|
570
|
+
const numFont = '"PingFang SC", -apple-system, BlinkMacSystemFont, system-ui, sans-serif';
|
|
550
571
|
|
|
551
572
|
return (
|
|
552
573
|
<div style={{
|
|
553
574
|
display: 'flex', alignItems: 'center', gap: 12,
|
|
554
|
-
padding: '
|
|
555
|
-
background: 'rgba(
|
|
556
|
-
borderTop: '1px solid rgba(255,255,255,0.08)',
|
|
575
|
+
padding: '12px',
|
|
576
|
+
background: 'linear-gradient(0deg, rgba(0, 0, 0, 0.30) 0%, rgba(0, 0, 0, 0.00) 100%)',
|
|
557
577
|
width: '100%',
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
borderRadius: 8,
|
|
562
|
-
color: '#f6f4ef',
|
|
563
|
-
fontFamily: 'Inter, system-ui, sans-serif',
|
|
578
|
+
color: '#fff',
|
|
579
|
+
fontFamily: numFont,
|
|
564
580
|
userSelect: 'none',
|
|
565
581
|
flexShrink: 0,
|
|
582
|
+
boxSizing: 'border-box',
|
|
566
583
|
}}>
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
<path d="M3 2v10M12 2L5 7l7 5V2z" stroke="currentColor" strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="round"/>
|
|
570
|
-
</svg>
|
|
571
|
-
</IconButton>
|
|
572
|
-
<IconButton onClick={onPlayPause} title="Play/pause (space)">
|
|
584
|
+
{/* Play / pause — bare white triangle, no button chrome */}
|
|
585
|
+
<IconButton onClick={onPlayPause} tooltip={playing ? '暂停' : '播放'}>
|
|
573
586
|
{playing ? (
|
|
574
|
-
<svg width="
|
|
575
|
-
<
|
|
576
|
-
<
|
|
587
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
588
|
+
<path d="M3.33333 1.33398C2.59695 1.33398 2 1.93094 2 2.66732V13.334C2 14.0704 2.59695 14.6673 3.33333 14.6673H4.66667C5.40305 14.6673 6 14.0704 6 13.334V2.66732C6 1.93094 5.40305 1.33398 4.66667 1.33398H3.33333Z" fill="currentColor"/>
|
|
589
|
+
<path d="M11.3333 1.33398C10.597 1.33398 10 1.93094 10 2.66732V13.334C10 14.0704 10.597 14.6673 11.3333 14.6673H12.6667C13.403 14.6673 14 14.0704 14 13.334V2.66732C14 1.93094 13.403 1.33398 12.6667 1.33398H11.3333Z" fill="currentColor"/>
|
|
577
590
|
</svg>
|
|
578
591
|
) : (
|
|
579
|
-
<svg width="
|
|
580
|
-
<path d="
|
|
592
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
593
|
+
<path d="M14.0489 9.13127C14.873 8.60116 14.873 7.39754 14.0489 6.86743L4.74461 0.882617C3.84764 0.305661 2.66699 0.948902 2.66699 2.01454V13.9842C2.66699 15.0498 3.84764 15.693 4.74461 15.1161L14.0489 9.13127Z" fill="currentColor"/>
|
|
581
594
|
</svg>
|
|
582
595
|
)}
|
|
583
596
|
</IconButton>
|
|
584
597
|
|
|
585
|
-
{/* Current time
|
|
598
|
+
{/* Current time */}
|
|
586
599
|
<div style={{
|
|
587
|
-
fontFamily:
|
|
588
|
-
fontSize:
|
|
600
|
+
fontFamily: numFont,
|
|
601
|
+
fontSize: 14,
|
|
602
|
+
fontWeight: 400,
|
|
589
603
|
fontVariantNumeric: 'tabular-nums',
|
|
590
|
-
|
|
591
|
-
|
|
604
|
+
color: '#fff',
|
|
605
|
+
minWidth: 40,
|
|
606
|
+
textAlign: 'center'
|
|
592
607
|
}}>
|
|
593
608
|
{fmt(time)}
|
|
594
609
|
</div>
|
|
595
610
|
|
|
596
|
-
{/* Scrub track */}
|
|
611
|
+
{/* Scrub track — white fill on translucent-white rail + draggable knob */}
|
|
597
612
|
<div
|
|
598
613
|
ref={trackRef}
|
|
599
614
|
onMouseMove={onTrackMove}
|
|
@@ -601,7 +616,7 @@ function PlaybackBar({ time, duration, playing, onPlayPause, onReset, onSeek, on
|
|
|
601
616
|
onMouseDown={onTrackDown}
|
|
602
617
|
style={{
|
|
603
618
|
flex: 1,
|
|
604
|
-
height:
|
|
619
|
+
height: 20,
|
|
605
620
|
position: 'relative',
|
|
606
621
|
cursor: 'pointer',
|
|
607
622
|
display: 'flex', alignItems: 'center',
|
|
@@ -610,33 +625,62 @@ function PlaybackBar({ time, duration, playing, onPlayPause, onReset, onSeek, on
|
|
|
610
625
|
<div style={{
|
|
611
626
|
position: 'absolute',
|
|
612
627
|
left: 0, right: 0, height: 4,
|
|
613
|
-
background: 'rgba(255,255,255,0.
|
|
628
|
+
background: 'rgba(255,255,255,0.6)',
|
|
614
629
|
borderRadius: 2,
|
|
615
630
|
}}/>
|
|
616
631
|
<div style={{
|
|
617
632
|
position: 'absolute',
|
|
618
633
|
left: 0, width: `${pct}%`, height: 4,
|
|
619
|
-
background: '
|
|
634
|
+
background: 'rgba(255,255,255,0.9)',
|
|
620
635
|
borderRadius: 2,
|
|
621
636
|
}}/>
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
637
|
+
{/* Progress knob — outer div is an enlarged transparent hit area for easier grabbing */}
|
|
638
|
+
<div
|
|
639
|
+
onMouseDown={onBallDown}
|
|
640
|
+
style={{
|
|
641
|
+
position: 'absolute',
|
|
642
|
+
left: `${pct}%`, top: '50%',
|
|
643
|
+
transform: 'translate(-50%, -50%)',
|
|
644
|
+
width: 20, height: 20,
|
|
645
|
+
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
646
|
+
cursor: dragging ? 'grabbing' : 'grab',
|
|
647
|
+
zIndex: 5,
|
|
648
|
+
}}
|
|
649
|
+
>
|
|
650
|
+
<div style={{
|
|
651
|
+
width: dragging ? 14 : 12,
|
|
652
|
+
height: dragging ? 14 : 12,
|
|
653
|
+
background: '#fff',
|
|
654
|
+
borderRadius: '50%',
|
|
655
|
+
border: '0.5px solid #D2D5D8',
|
|
656
|
+
boxShadow: '0 2px 6px rgba(0,0,0,0.35)',
|
|
657
|
+
transition: 'width 100ms, height 100ms',
|
|
658
|
+
}}/>
|
|
659
|
+
</div>
|
|
660
|
+
{trackHover && (
|
|
661
|
+
<div style={{
|
|
662
|
+
position: 'absolute',
|
|
663
|
+
left: trackHover.x,
|
|
664
|
+
bottom: '100%',
|
|
665
|
+
transform: 'translateX(-50%)',
|
|
666
|
+
marginBottom: 2,
|
|
667
|
+
pointerEvents: 'none',
|
|
668
|
+
zIndex: 10,
|
|
669
|
+
}}>
|
|
670
|
+
<TooltipBubble text={fmt(trackHover.t)} />
|
|
671
|
+
</div>
|
|
672
|
+
)}
|
|
631
673
|
</div>
|
|
632
674
|
|
|
633
|
-
{/* Duration
|
|
675
|
+
{/* Duration — dimmed */}
|
|
634
676
|
<div style={{
|
|
635
|
-
fontFamily:
|
|
636
|
-
fontSize:
|
|
677
|
+
fontFamily: numFont,
|
|
678
|
+
fontSize: 14,
|
|
679
|
+
fontWeight: 400,
|
|
637
680
|
fontVariantNumeric: 'tabular-nums',
|
|
638
|
-
|
|
639
|
-
|
|
681
|
+
color: 'rgba(255,255,255,0.6)',
|
|
682
|
+
minWidth: 40,
|
|
683
|
+
textAlign: 'center',
|
|
640
684
|
}}>
|
|
641
685
|
{fmt(duration)}
|
|
642
686
|
</div>
|
|
@@ -644,31 +688,80 @@ function PlaybackBar({ time, duration, playing, onPlayPause, onReset, onSeek, on
|
|
|
644
688
|
);
|
|
645
689
|
}
|
|
646
690
|
|
|
647
|
-
|
|
691
|
+
|
|
692
|
+
function IconButton({ children, onClick, tooltip }) {
|
|
648
693
|
const [hover, setHover] = React.useState(false);
|
|
649
694
|
return (
|
|
650
695
|
<button
|
|
651
696
|
onClick={onClick}
|
|
652
|
-
|
|
697
|
+
aria-label={tooltip}
|
|
653
698
|
onMouseEnter={() => setHover(true)}
|
|
654
699
|
onMouseLeave={() => setHover(false)}
|
|
655
700
|
style={{
|
|
656
|
-
|
|
701
|
+
position: 'relative',
|
|
702
|
+
width: 24, height: 24,
|
|
657
703
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
658
|
-
background: hover ? 'rgba(255,255,255,0.
|
|
659
|
-
border: '
|
|
704
|
+
background: hover ? 'rgba(255,255,255,0.1)' : 'transparent',
|
|
705
|
+
border: 'none',
|
|
660
706
|
borderRadius: 6,
|
|
661
|
-
color: '#
|
|
707
|
+
color: '#fff',
|
|
662
708
|
cursor: 'pointer',
|
|
663
709
|
padding: 0,
|
|
664
710
|
transition: 'background 120ms',
|
|
665
711
|
}}
|
|
666
712
|
>
|
|
667
713
|
{children}
|
|
714
|
+
{tooltip && (
|
|
715
|
+
<div style={{
|
|
716
|
+
position: 'absolute',
|
|
717
|
+
bottom: '100%',
|
|
718
|
+
left: '50%',
|
|
719
|
+
transform: 'translateX(-50%)',
|
|
720
|
+
marginBottom: 8,
|
|
721
|
+
pointerEvents: 'none',
|
|
722
|
+
opacity: hover ? 1 : 0,
|
|
723
|
+
transition: 'opacity 120ms',
|
|
724
|
+
zIndex: 10,
|
|
725
|
+
}}>
|
|
726
|
+
<TooltipBubble text={tooltip} />
|
|
727
|
+
</div>
|
|
728
|
+
)}
|
|
668
729
|
</button>
|
|
669
730
|
);
|
|
670
731
|
}
|
|
671
732
|
|
|
733
|
+
// ── Tooltip bubble ────────────────────────────────────────────────────────────
|
|
734
|
+
// Dark rounded bubble with a downward tail. Positioning is up to the caller.
|
|
735
|
+
function TooltipBubble({ text }) {
|
|
736
|
+
return (
|
|
737
|
+
<div style={{ position: 'relative', display: 'inline-block' }}>
|
|
738
|
+
<div style={{
|
|
739
|
+
background: '#1F2329',
|
|
740
|
+
color: '#fff',
|
|
741
|
+
fontSize: 12,
|
|
742
|
+
lineHeight: '16px',
|
|
743
|
+
padding: '6px 12px',
|
|
744
|
+
borderRadius: 6,
|
|
745
|
+
whiteSpace: 'nowrap',
|
|
746
|
+
fontFamily: '"PingFang SC", -apple-system, BlinkMacSystemFont, system-ui, sans-serif',
|
|
747
|
+
fontVariantNumeric: 'tabular-nums',
|
|
748
|
+
boxShadow: '0 4px 8px -8px rgba(0, 0, 0, 0.06), 0 6px 12px 0 rgba(0, 0, 0, 0.04), 0 8px 24px 8px rgba(0, 0, 0, 0.04)',
|
|
749
|
+
}}>
|
|
750
|
+
{text}
|
|
751
|
+
</div>
|
|
752
|
+
<div style={{
|
|
753
|
+
position: 'absolute',
|
|
754
|
+
top: '100%',
|
|
755
|
+
left: '50%',
|
|
756
|
+
transform: 'translate(-50%, -50%) rotate(45deg)',
|
|
757
|
+
width: 9, height: 9,
|
|
758
|
+
borderRadius: '0 0 3px 0',
|
|
759
|
+
background: '#1F2329',
|
|
760
|
+
}}/>
|
|
761
|
+
</div>
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
|
|
672
765
|
|
|
673
766
|
Object.assign(window, {
|
|
674
767
|
Easing, interpolate, animate, clamp,
|
|
@@ -105,7 +105,7 @@ function ChromeWindow({
|
|
|
105
105
|
return (
|
|
106
106
|
<div style={{
|
|
107
107
|
width, height, borderRadius: 10, overflow: 'hidden',
|
|
108
|
-
|
|
108
|
+
border: '1px solid #DEE0E3',
|
|
109
109
|
display: 'flex', flexDirection: 'column', background: CHROME_C.tabBg,
|
|
110
110
|
}}>
|
|
111
111
|
<ChromeTabBar tabs={tabs} activeIndex={activeIndex} />
|