File tree Expand file tree Collapse file tree 6 files changed +146
-2
lines changed
.kiro/specs/min-stack-visualizer Expand file tree Collapse file tree 6 files changed +146
-2
lines changed Original file line number Diff line number Diff line change 159159 - ** Property 7: 播放控制状态一致性**
160160 - ** Validates: Requirements 7.3, 7.5, 7.9, 7.15**
161161
162- - [ ] 13 . UI 组件开发 - FloatingBall
163- - [ ] 13.1 实现 FloatingBall 组件
162+ - [x ] 13 . UI 组件开发 - FloatingBall
163+ - [x ] 13.1 实现 FloatingBall 组件
164164 - 创建 components/FloatingBall/FloatingBall.tsx 和样式文件
165165 - 右下角悬浮球(微信群图标样式)
166166 - 悬停显示二维码
Original file line number Diff line number Diff line change @@ -5,6 +5,7 @@ import { InputPanel } from './components/InputPanel';
55import { CodePanel } from './components/CodePanel/CodePanel' ;
66import { Canvas } from './components/Canvas' ;
77import { ControlPanel } from './components/ControlPanel' ;
8+ import { FloatingBall } from './components/FloatingBall' ;
89import type { Operation , Language , AlgorithmStep } from './types' ;
910import { generateSteps } from './services/stepGenerator' ;
1011import {
@@ -189,6 +190,9 @@ function App() {
189190 />
190191 ) }
191192 </ main >
193+
194+ { /* 技术交流群悬浮球 */ }
195+ < FloatingBall />
192196 </ div >
193197 ) ;
194198}
Original file line number Diff line number Diff line change 1+ .floating-ball-container {
2+ position : fixed;
3+ bottom : 24px ;
4+ right : 24px ;
5+ z-index : 1000 ;
6+ }
7+
8+ .floating-ball {
9+ display : flex;
10+ flex-direction : column;
11+ align-items : center;
12+ justify-content : center;
13+ width : 60px ;
14+ height : 60px ;
15+ background : linear-gradient (135deg , # 07c160 0% , # 06ad56 100% );
16+ border-radius : 50% ;
17+ cursor : pointer;
18+ box-shadow : 0 4px 12px rgba (7 , 193 , 96 , 0.4 );
19+ transition : all 0.3s ease;
20+ }
21+
22+ .floating-ball : hover {
23+ transform : scale (1.1 );
24+ box-shadow : 0 6px 16px rgba (7 , 193 , 96 , 0.5 );
25+ }
26+
27+ .wechat-group-icon {
28+ width : 24px ;
29+ height : 24px ;
30+ color : white;
31+ }
32+
33+ .ball-text {
34+ font-size : 10px ;
35+ color : white;
36+ margin-top : 2px ;
37+ font-weight : 500 ;
38+ }
39+
40+ .qrcode-popup {
41+ position : absolute;
42+ bottom : 70px ;
43+ right : 0 ;
44+ background : white;
45+ border-radius : 12px ;
46+ box-shadow : 0 8px 24px rgba (0 , 0 , 0 , 0.15 );
47+ padding : 16px ;
48+ animation : fadeIn 0.2s ease;
49+ }
50+
51+ .qrcode-popup ::after {
52+ content : '' ;
53+ position : absolute;
54+ bottom : -8px ;
55+ right : 20px ;
56+ width : 0 ;
57+ height : 0 ;
58+ border-left : 8px solid transparent;
59+ border-right : 8px solid transparent;
60+ border-top : 8px solid white;
61+ }
62+
63+ .qrcode-content {
64+ display : flex;
65+ flex-direction : column;
66+ align-items : center;
67+ }
68+
69+ .qrcode-image {
70+ width : 200px ;
71+ height : auto;
72+ border-radius : 8px ;
73+ }
74+
75+ .qrcode-tip {
76+ margin-top : 12px ;
77+ font-size : 13px ;
78+ color : # 333 ;
79+ text-align : center;
80+ line-height : 1.5 ;
81+ }
82+
83+ .qrcode-tip strong {
84+ color : # 07c160 ;
85+ }
86+
87+ @keyframes fadeIn {
88+ from {
89+ opacity : 0 ;
90+ transform : translateY (10px );
91+ }
92+ to {
93+ opacity : 1 ;
94+ transform : translateY (0 );
95+ }
96+ }
Original file line number Diff line number Diff line change 1+ import { useState } from 'react' ;
2+ import './FloatingBall.css' ;
3+ import qrcodeImage from '/wechat-qrcode.png' ;
4+
5+ export function FloatingBall ( ) {
6+ const [ isHovered , setIsHovered ] = useState ( false ) ;
7+
8+ return (
9+ < div className = "floating-ball-container" >
10+ < div
11+ className = "floating-ball"
12+ onMouseEnter = { ( ) => setIsHovered ( true ) }
13+ onMouseLeave = { ( ) => setIsHovered ( false ) }
14+ >
15+ < svg
16+ className = "wechat-group-icon"
17+ viewBox = "0 0 24 24"
18+ fill = "currentColor"
19+ >
20+ < path d = "M8.5 11.5a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm4 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2z" />
21+ < path d = "M9 2C4.58 2 1 5.58 1 10c0 1.5.4 2.9 1.1 4.1L1 18l3.9-1.1c1.2.7 2.6 1.1 4.1 1.1 4.42 0 8-3.58 8-8s-3.58-8-8-8zm0 14c-1.3 0-2.5-.3-3.6-.9l-.4-.2-2.5.7.7-2.5-.2-.4C2.3 11.5 2 10.3 2 9c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7z" />
22+ < path d = "M19 10c0-1.3-.3-2.5-.9-3.6l.9-3.4-3.4.9C14.5 3.3 13.3 3 12 3c-.5 0-1 .05-1.5.13C12.3 2.4 14.6 2 17 2c4.42 0 8 3.58 8 8 0 1.5-.4 2.9-1.1 4.1L25 18l-3.9-1.1c-1.2.7-2.6 1.1-4.1 1.1-.5 0-1-.05-1.5-.13.8.08 1.6.13 2.5.13 1.3 0 2.5-.3 3.6-.9l.4-.2 2.5.7-.7-2.5.2-.4c.6-1.1.9-2.3.9-3.6z" />
23+ </ svg >
24+ < span className = "ball-text" > 交流群</ span >
25+ </ div >
26+
27+ { isHovered && (
28+ < div className = "qrcode-popup" >
29+ < div className = "qrcode-content" >
30+ < img
31+ src = { qrcodeImage }
32+ alt = "微信二维码"
33+ className = "qrcode-image"
34+ />
35+ < p className = "qrcode-tip" >
36+ 微信扫码发送 < strong > "leetcode"</ strong > 加入算法交流群
37+ </ p >
38+ </ div >
39+ </ div >
40+ ) }
41+ </ div >
42+ ) ;
43+ }
Original file line number Diff line number Diff line change 1+ export { FloatingBall } from './FloatingBall' ;
You can’t perform that action at this time.
0 commit comments