@@ -13,7 +13,7 @@ struct ClipboardMenuView: View {
1313 ClipboardItemView ( item: item)
1414 . frame ( width: 180 , height: 100 )
1515 . background ( Color ( NSColor . controlBackgroundColor) )
16- . cornerRadius ( 8 )
16+ . cornerRadius ( 30 )
1717 . shadow ( radius: 2 )
1818 . onHover { isHovered in
1919 hoveredItemId = isHovered ? item. id : nil
@@ -39,18 +39,190 @@ struct ClipboardItemView: View {
3939
4040 var body : some View {
4141 VStack {
42- if item. type == . text {
43- Text ( item. displayString)
44- . lineLimit ( 3 )
45- . font ( . system( size: 12 ) )
46- } else if item. type == . image,
47- let imageData = item. content as? Data ,
48- let nsImage = NSImage ( data: imageData) {
42+ switch item. type {
43+ case . text:
44+ textView
45+ case . image:
46+ imageView
47+ case . color:
48+ colorView
49+ case . code:
50+ codeView
51+ }
52+ }
53+ . frame ( width: 180 , height: 100 )
54+ . background ( backgroundForType)
55+ . cornerRadius ( 10 )
56+ . overlay (
57+ RoundedRectangle ( cornerRadius: 10 )
58+ . stroke ( Color . gray. opacity ( 0.3 ) , lineWidth: 1 )
59+ )
60+ }
61+
62+ private var textView : some View {
63+ Text ( item. displayString)
64+ . font ( . system( size: 12 ) )
65+ . padding ( 5 )
66+ . lineLimit ( 4 )
67+ }
68+
69+ private var imageView : some View {
70+ Group {
71+ if let imageData = item. content as? Data ,
72+ let nsImage = NSImage ( data: imageData) {
4973 Image ( nsImage: nsImage)
5074 . resizable ( )
5175 . aspectRatio ( contentMode: . fit)
76+ . frame ( width: 170 , height: 90 )
77+ } else {
78+ Text ( " Invalid Image " )
79+ . font ( . caption)
80+ . foregroundColor ( . red)
81+ }
82+ }
83+ }
84+
85+ private var colorView : some View {
86+ Group {
87+ if let colorString = item. content as? String ,
88+ let color = Color ( hex: colorString) {
89+ let textColor = color. contrastingTextColor ( _color: item. content as! String ) // Choose light or dark text based on background color
90+
91+ VStack {
92+ Rectangle ( )
93+ . fill ( color)
94+ . frame ( width: 170 , height: 70 )
95+ Text ( colorString)
96+ . font ( . caption)
97+ . foregroundColor ( textColor)
98+ . multilineTextAlignment ( . center) // Center the text
99+ }
100+ } else {
101+ Text ( " Invalid Color " )
102+ . font ( . caption)
103+ . foregroundColor ( . red)
104+ . multilineTextAlignment ( . center)
105+ }
106+ }
107+ . frame ( width: 180 , height: 100 )
108+ }
109+
110+ private var codeView : some View {
111+ VStack ( alignment: . leading, spacing: 0 ) {
112+ HStack {
113+ Circle ( )
114+ . fill ( Color . red)
115+ . frame ( width: 10 , height: 10 )
116+ Circle ( )
117+ . fill ( Color . yellow)
118+ . frame ( width: 10 , height: 10 )
119+ Circle ( )
120+ . fill ( Color . green)
121+ . frame ( width: 10 , height: 10 )
122+ Spacer ( )
123+ Text ( " Code Snippet " )
124+ . font ( . system( size: 10 ) )
125+ . foregroundColor ( . secondary)
126+ }
127+ . padding ( . horizontal, 8 )
128+ . padding ( . vertical, 4 )
129+ . background ( Color ( hex: " #2b2b2b " ) )
130+
131+ ScrollView {
132+ Text ( applySyntaxHighlighting ( to: item. displayString) )
133+ . font ( . system( size: 10 , design: . monospaced) )
134+ . padding ( 8 )
135+ . frame ( maxWidth: . infinity, alignment: . leading)
136+ }
137+ }
138+ . background ( Color ( hex: " #1e1e1e " ) )
139+ . cornerRadius ( 8 )
140+ }
141+
142+ private func applySyntaxHighlighting( to code: String ) -> AttributedString {
143+ var attributedString = AttributedString ( code)
144+
145+ let keywords = [ " func " , " var " , " let " , " if " , " else " , " for " , " while " , " return " , " class " , " struct " , " enum " ]
146+ let types = [ " String " , " Int " , " Double " , " Bool " , " Array " , " Dictionary " ]
147+
148+ for keyword in keywords {
149+ if let range = attributedString. range ( of: keyword) {
150+ attributedString [ range] . foregroundColor = . purple
151+ attributedString [ range] . font = . system( size: 10 , weight: . bold, design: . monospaced)
152+ }
153+ }
154+
155+ for type in types {
156+ if let range = attributedString. range ( of: type) {
157+ attributedString [ range] . foregroundColor = . blue
158+ }
159+ }
160+
161+ // Highlight string literals
162+ let stringPattern = " \" [^ \" ]* \" "
163+ if let regex = try ? NSRegularExpression ( pattern: stringPattern) {
164+ let nsRange = NSRange ( code. startIndex... , in: code)
165+ for match in regex. matches ( in: code, options: [ ] , range: nsRange) {
166+ if let range = Range ( match. range, in: code) {
167+ let matchedString = String ( code [ range] )
168+ if let attributedRange = attributedString. range ( of: matchedString) {
169+ attributedString [ attributedRange] . foregroundColor = . green
170+ }
171+ }
172+ }
173+ }
174+
175+ return attributedString
176+ }
177+
178+ private var backgroundForType : some View {
179+ Group {
180+ switch item. type {
181+ case . text:
182+ Color ( NSColor . textBackgroundColor)
183+ case . image:
184+ Color ( NSColor . windowBackgroundColor)
185+ case . color:
186+ Color ( NSColor . windowBackgroundColor)
187+ case . code:
188+ Color ( hex: " #1e1e1e " ) // Dark background for code
189+ }
52190 }
53191 }
54- . padding ( 5 )
192+ }
193+
194+ extension Color {
195+ init ? ( hex: String ) {
196+ var hexSanitized = hex. trimmingCharacters ( in: . whitespacesAndNewlines)
197+ hexSanitized = hexSanitized. replacingOccurrences ( of: " # " , with: " " )
198+
199+ var rgb : UInt64 = 0
200+
201+ guard Scanner ( string: hexSanitized) . scanHexInt64 ( & rgb) else { return nil }
202+
203+ self . init (
204+ red: Double ( ( rgb & 0xFF0000 ) >> 16 ) / 255.0 ,
205+ green: Double ( ( rgb & 0x00FF00 ) >> 8 ) / 255.0 ,
206+ blue: Double ( rgb & 0x0000FF ) / 255.0
207+ )
55208 }
209+ func luminance( _color: String ) -> Double {
210+ var red : CGFloat = 0
211+ var green : CGFloat = 0
212+ var blue : CGFloat = 0
213+
214+ if let cgColor = Color . init ( hex: _color) ? . cgColor? . components {
215+ red = cgColor [ 0 ]
216+ green = cgColor [ 1 ]
217+ blue = cgColor [ 2 ]
218+ }
219+
220+ // Luminance formula for sRGB colors
221+ return 0.299 * Double( red) + 0.587 * Double( green) + 0.114 * Double( blue)
222+ }
223+
224+ // Choose light or dark based on the luminance
225+ func contrastingTextColor( _color: String ) -> Color {
226+ return self . luminance ( _color: _color) > 0.5 ? . black : . white
227+ }
56228}
0 commit comments