rails_error_dashboard 0.1.28 → 0.1.30

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +50 -6
  3. data/app/controllers/rails_error_dashboard/errors_controller.rb +22 -0
  4. data/app/helpers/rails_error_dashboard/application_helper.rb +79 -7
  5. data/app/helpers/rails_error_dashboard/backtrace_helper.rb +149 -0
  6. data/app/models/rails_error_dashboard/application.rb +1 -1
  7. data/app/models/rails_error_dashboard/error_log.rb +44 -16
  8. data/app/views/layouts/rails_error_dashboard.html.erb +71 -1237
  9. data/app/views/rails_error_dashboard/errors/_error_row.html.erb +10 -2
  10. data/app/views/rails_error_dashboard/errors/_source_code.html.erb +76 -0
  11. data/app/views/rails_error_dashboard/errors/_timeline.html.erb +18 -82
  12. data/app/views/rails_error_dashboard/errors/_user_errors_table.html.erb +70 -0
  13. data/app/views/rails_error_dashboard/errors/analytics.html.erb +9 -37
  14. data/app/views/rails_error_dashboard/errors/correlation.html.erb +11 -37
  15. data/app/views/rails_error_dashboard/errors/index.html.erb +64 -31
  16. data/app/views/rails_error_dashboard/errors/overview.html.erb +181 -3
  17. data/app/views/rails_error_dashboard/errors/platform_comparison.html.erb +2 -1
  18. data/app/views/rails_error_dashboard/errors/settings/_value_badge.html.erb +286 -0
  19. data/app/views/rails_error_dashboard/errors/settings.html.erb +146 -480
  20. data/app/views/rails_error_dashboard/errors/show.html.erb +102 -76
  21. data/db/migrate/20251223000000_create_rails_error_dashboard_complete_schema.rb +188 -0
  22. data/db/migrate/20251224000001_create_rails_error_dashboard_error_logs.rb +5 -0
  23. data/db/migrate/20251224081522_add_better_tracking_to_error_logs.rb +3 -0
  24. data/db/migrate/20251224101217_add_controller_action_to_error_logs.rb +3 -0
  25. data/db/migrate/20251225071314_add_optimized_indexes_to_error_logs.rb +4 -0
  26. data/db/migrate/20251225074653_remove_environment_from_error_logs.rb +3 -0
  27. data/db/migrate/20251225085859_add_enhanced_metrics_to_error_logs.rb +3 -0
  28. data/db/migrate/20251225093603_add_similarity_tracking_to_error_logs.rb +3 -0
  29. data/db/migrate/20251225100236_create_error_occurrences.rb +3 -0
  30. data/db/migrate/20251225101920_create_cascade_patterns.rb +3 -0
  31. data/db/migrate/20251225102500_create_error_baselines.rb +3 -0
  32. data/db/migrate/20251226020000_add_workflow_fields_to_error_logs.rb +3 -0
  33. data/db/migrate/20251226020100_create_error_comments.rb +3 -0
  34. data/db/migrate/20251229111223_add_additional_performance_indexes.rb +4 -0
  35. data/db/migrate/20260106094220_create_rails_error_dashboard_applications.rb +3 -0
  36. data/db/migrate/20260106094233_add_application_to_error_logs.rb +3 -0
  37. data/db/migrate/20260106094318_finalize_application_foreign_key.rb +5 -0
  38. data/lib/generators/rails_error_dashboard/install/install_generator.rb +32 -0
  39. data/lib/generators/rails_error_dashboard/install/templates/initializer.rb +37 -4
  40. data/lib/rails_error_dashboard/configuration.rb +160 -3
  41. data/lib/rails_error_dashboard/configuration_error.rb +24 -0
  42. data/lib/rails_error_dashboard/engine.rb +17 -0
  43. data/lib/rails_error_dashboard/helpers/user_model_detector.rb +138 -0
  44. data/lib/rails_error_dashboard/queries/analytics_stats.rb +1 -2
  45. data/lib/rails_error_dashboard/queries/dashboard_stats.rb +19 -4
  46. data/lib/rails_error_dashboard/queries/errors_list.rb +27 -8
  47. data/lib/rails_error_dashboard/services/error_normalizer.rb +143 -0
  48. data/lib/rails_error_dashboard/services/git_blame_reader.rb +195 -0
  49. data/lib/rails_error_dashboard/services/github_link_generator.rb +159 -0
  50. data/lib/rails_error_dashboard/services/source_code_reader.rb +214 -0
  51. data/lib/rails_error_dashboard/version.rb +1 -1
  52. data/lib/rails_error_dashboard.rb +6 -0
  53. metadata +14 -10
  54. data/app/assets/stylesheets/rails_error_dashboard/_catppuccin_mocha.scss +0 -107
  55. data/app/assets/stylesheets/rails_error_dashboard/_components.scss +0 -625
  56. data/app/assets/stylesheets/rails_error_dashboard/_layout.scss +0 -257
  57. data/app/assets/stylesheets/rails_error_dashboard/_theme_variables.scss +0 -203
  58. data/app/assets/stylesheets/rails_error_dashboard/application.css +0 -15
  59. data/app/assets/stylesheets/rails_error_dashboard/application.css.map +0 -7
  60. data/app/assets/stylesheets/rails_error_dashboard/application.scss +0 -61
  61. data/app/views/layouts/rails_error_dashboard/application.html.erb +0 -55
@@ -0,0 +1,214 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsErrorDashboard
4
+ module Services
5
+ # Reads source code files from disk with security validation
6
+ # and context lines around a target line number
7
+ #
8
+ # @example
9
+ # reader = SourceCodeReader.new("/path/to/app/models/user.rb", 42)
10
+ # lines = reader.read_lines(context: 5)
11
+ # # Returns array of hashes with line numbers and content
12
+ class SourceCodeReader
13
+ MAX_FILE_SIZE = 10 * 1024 * 1024 # 10 MB
14
+ MAX_CONTEXT_LINES = 50
15
+
16
+ attr_reader :file_path, :line_number, :error
17
+
18
+ # Initialize a new source code reader
19
+ #
20
+ # @param file_path [String] Path to the source file
21
+ # @param line_number [Integer] Target line number
22
+ def initialize(file_path, line_number)
23
+ @file_path = file_path
24
+ @line_number = line_number.to_i
25
+ @error = nil
26
+ end
27
+
28
+ # Read source code lines with context around the target line
29
+ #
30
+ # @param context [Integer] Number of lines before and after target line
31
+ # @return [Array<Hash>, nil] Array of line data hashes or nil if unavailable
32
+ def read_lines(context: 5)
33
+ context = [ [ context, MAX_CONTEXT_LINES ].min, 1 ].max
34
+
35
+ # Validate and resolve path
36
+ absolute_path = resolve_absolute_path
37
+ return nil unless absolute_path
38
+
39
+ # Validate path is safe
40
+ unless validate_path!(absolute_path)
41
+ @error = "Invalid or unsafe file path"
42
+ return nil
43
+ end
44
+
45
+ # Check file exists and is readable
46
+ unless File.exist?(absolute_path) && File.readable?(absolute_path)
47
+ @error = "File not found or not readable"
48
+ return nil
49
+ end
50
+
51
+ # Check file size
52
+ file_size = File.size(absolute_path)
53
+ if file_size > MAX_FILE_SIZE
54
+ @error = "File too large (#{file_size} bytes, max #{MAX_FILE_SIZE})"
55
+ return nil
56
+ end
57
+
58
+ # Check if file is binary
59
+ if binary_file?(absolute_path)
60
+ @error = "Binary file cannot be displayed"
61
+ return nil
62
+ end
63
+
64
+ # Read the specific lines
65
+ read_specific_lines(absolute_path, line_number - context, line_number + context)
66
+ rescue StandardError => e
67
+ @error = "Error reading file: #{e.message}"
68
+ RailsErrorDashboard::Logger.error("SourceCodeReader error for #{file_path}:#{line_number} - #{e.message}")
69
+ nil
70
+ end
71
+
72
+ # Check if file exists on disk
73
+ #
74
+ # @return [Boolean]
75
+ def file_exists?
76
+ absolute_path = resolve_absolute_path
77
+ return false unless absolute_path
78
+
79
+ File.exist?(absolute_path) && File.readable?(absolute_path)
80
+ rescue StandardError
81
+ false
82
+ end
83
+
84
+ private
85
+
86
+ # Resolve file path to absolute path within Rails.root
87
+ #
88
+ # @return [String, nil] Absolute path or nil if invalid
89
+ def resolve_absolute_path
90
+ return nil if file_path.blank?
91
+
92
+ # Handle relative paths from backtrace
93
+ if file_path.start_with?(Rails.root.to_s)
94
+ # Already absolute
95
+ file_path
96
+ elsif file_path.start_with?("/")
97
+ # Absolute but might be from different root (deployed location)
98
+ # Try to find relative to Rails.root
99
+ relative = file_path.sub(%r{^.*/}, "")
100
+ File.join(Rails.root, relative)
101
+ else
102
+ # Relative path
103
+ File.join(Rails.root, file_path)
104
+ end
105
+ end
106
+
107
+ # Validate path is safe to read (security check)
108
+ #
109
+ # @param path [String] Absolute path to validate
110
+ # @return [Boolean]
111
+ # @raise [SecurityError] if path is unsafe
112
+ def validate_path!(path)
113
+ # Normalize path
114
+ normalized = File.expand_path(path)
115
+ rails_root = File.expand_path(Rails.root)
116
+
117
+ # Must be within Rails.root
118
+ unless normalized.start_with?(rails_root)
119
+ RailsErrorDashboard::Logger.warn("Path outside Rails.root: #{normalized}")
120
+ return false
121
+ end
122
+
123
+ # Prevent directory traversal
124
+ if path.include?("..") || normalized.include?("..")
125
+ RailsErrorDashboard::Logger.warn("Directory traversal attempt: #{path}")
126
+ return false
127
+ end
128
+
129
+ # Check against sensitive file patterns
130
+ sensitive_patterns = [
131
+ /\.env/i,
132
+ /secrets\.yml$/i,
133
+ /credentials\.yml/i,
134
+ /database\.yml$/i,
135
+ /master\.key$/i,
136
+ /private_key/i,
137
+ /\.pem$/i,
138
+ /\.key$/i
139
+ ]
140
+
141
+ if sensitive_patterns.any? { |pattern| normalized.match?(pattern) }
142
+ RailsErrorDashboard::Logger.warn("Attempt to read sensitive file: #{normalized}")
143
+ return false
144
+ end
145
+
146
+ # Only show app code if configured
147
+ if RailsErrorDashboard.configuration.only_show_app_code_source
148
+ # Block gem/vendor code
149
+ blocked_patterns = [
150
+ %r{/gems/},
151
+ %r{/vendor/bundle/},
152
+ %r{/vendor/ruby/},
153
+ %r{/.bundle/}
154
+ ]
155
+
156
+ if blocked_patterns.any? { |pattern| normalized.match?(pattern) }
157
+ RailsErrorDashboard::Logger.debug("Skipping gem/vendor code: #{normalized}")
158
+ return false
159
+ end
160
+ end
161
+
162
+ true
163
+ end
164
+
165
+ # Read specific lines from file
166
+ #
167
+ # @param file_path [String] Path to file
168
+ # @param start_line [Integer] First line to read (1-indexed)
169
+ # @param end_line [Integer] Last line to read (1-indexed)
170
+ # @return [Array<Hash>] Array of line data
171
+ def read_specific_lines(file_path, start_line, end_line)
172
+ start_line = [ start_line, 1 ].max
173
+ lines = []
174
+
175
+ File.open(file_path, "r") do |file|
176
+ file.each_line.with_index(1) do |line, line_num|
177
+ break if line_num > end_line
178
+
179
+ next if line_num < start_line
180
+
181
+ lines << {
182
+ number: line_num,
183
+ content: line.chomp,
184
+ highlight: line_num == @line_number
185
+ }
186
+ end
187
+ end
188
+
189
+ lines
190
+ rescue StandardError => e
191
+ RailsErrorDashboard::Logger.error("Error reading specific lines from #{file_path}: #{e.message}")
192
+ []
193
+ end
194
+
195
+ # Check if file is binary
196
+ #
197
+ # @param file_path [String] Path to file
198
+ # @return [Boolean]
199
+ def binary_file?(file_path)
200
+ # Read first 8KB to check for null bytes
201
+ sample_size = 8192
202
+ File.open(file_path, "rb") do |file|
203
+ sample = file.read(sample_size)
204
+ return false if sample.nil? || sample.empty?
205
+
206
+ # Binary files typically contain null bytes
207
+ sample.include?("\x00")
208
+ end
209
+ rescue StandardError
210
+ false # If we can't determine, assume text
211
+ end
212
+ end
213
+ end
214
+ end
@@ -1,3 +1,3 @@
1
1
  module RailsErrorDashboard
2
- VERSION = "0.1.28"
2
+ VERSION = "0.1.30"
3
3
  end
@@ -1,5 +1,6 @@
1
1
  require "rails_error_dashboard/version"
2
2
  require "rails_error_dashboard/engine"
3
+ require "rails_error_dashboard/configuration_error"
3
4
  require "rails_error_dashboard/configuration"
4
5
  require "rails_error_dashboard/logger"
5
6
  require "rails_error_dashboard/manual_error_reporter"
@@ -16,6 +17,7 @@ require "turbo-rails"
16
17
 
17
18
  # Core library files
18
19
  require "rails_error_dashboard/value_objects/error_context"
20
+ require "rails_error_dashboard/helpers/user_model_detector"
19
21
  require "rails_error_dashboard/services/platform_detector"
20
22
  require "rails_error_dashboard/services/backtrace_parser"
21
23
  require "rails_error_dashboard/services/similarity_calculator"
@@ -23,6 +25,10 @@ require "rails_error_dashboard/services/cascade_detector"
23
25
  require "rails_error_dashboard/services/baseline_calculator"
24
26
  require "rails_error_dashboard/services/baseline_alert_throttler"
25
27
  require "rails_error_dashboard/services/pattern_detector"
28
+ require "rails_error_dashboard/services/error_normalizer"
29
+ require "rails_error_dashboard/services/source_code_reader"
30
+ require "rails_error_dashboard/services/git_blame_reader"
31
+ require "rails_error_dashboard/services/github_link_generator"
26
32
  require "rails_error_dashboard/queries/co_occurring_errors"
27
33
  require "rails_error_dashboard/queries/error_cascades"
28
34
  require "rails_error_dashboard/queries/baseline_stats"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_error_dashboard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.28
4
+ version: 0.1.30
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anjan Jagirdar
@@ -267,13 +267,6 @@ files:
267
267
  - MIT-LICENSE
268
268
  - README.md
269
269
  - Rakefile
270
- - app/assets/stylesheets/rails_error_dashboard/_catppuccin_mocha.scss
271
- - app/assets/stylesheets/rails_error_dashboard/_components.scss
272
- - app/assets/stylesheets/rails_error_dashboard/_layout.scss
273
- - app/assets/stylesheets/rails_error_dashboard/_theme_variables.scss
274
- - app/assets/stylesheets/rails_error_dashboard/application.css
275
- - app/assets/stylesheets/rails_error_dashboard/application.css.map
276
- - app/assets/stylesheets/rails_error_dashboard/application.scss
277
270
  - app/controllers/rails_error_dashboard/application_controller.rb
278
271
  - app/controllers/rails_error_dashboard/errors_controller.rb
279
272
  - app/helpers/rails_error_dashboard/application_helper.rb
@@ -298,22 +291,25 @@ files:
298
291
  - app/models/rails_error_dashboard/error_logs_record.rb
299
292
  - app/models/rails_error_dashboard/error_occurrence.rb
300
293
  - app/views/layouts/rails_error_dashboard.html.erb
301
- - app/views/layouts/rails_error_dashboard/application.html.erb
302
294
  - app/views/rails_error_dashboard/error_notification_mailer/error_alert.html.erb
303
295
  - app/views/rails_error_dashboard/error_notification_mailer/error_alert.text.erb
304
296
  - app/views/rails_error_dashboard/errors/_error_row.html.erb
305
297
  - app/views/rails_error_dashboard/errors/_pattern_insights.html.erb
298
+ - app/views/rails_error_dashboard/errors/_source_code.html.erb
306
299
  - app/views/rails_error_dashboard/errors/_stats.html.erb
307
300
  - app/views/rails_error_dashboard/errors/_timeline.html.erb
301
+ - app/views/rails_error_dashboard/errors/_user_errors_table.html.erb
308
302
  - app/views/rails_error_dashboard/errors/analytics.html.erb
309
303
  - app/views/rails_error_dashboard/errors/correlation.html.erb
310
304
  - app/views/rails_error_dashboard/errors/index.html.erb
311
305
  - app/views/rails_error_dashboard/errors/overview.html.erb
312
306
  - app/views/rails_error_dashboard/errors/platform_comparison.html.erb
313
307
  - app/views/rails_error_dashboard/errors/settings.html.erb
308
+ - app/views/rails_error_dashboard/errors/settings/_value_badge.html.erb
314
309
  - app/views/rails_error_dashboard/errors/show.html.erb
315
310
  - config/routes.rb
316
311
  - db/development.sqlite3
312
+ - db/migrate/20251223000000_create_rails_error_dashboard_complete_schema.rb
317
313
  - db/migrate/20251224000001_create_rails_error_dashboard_error_logs.rb
318
314
  - db/migrate/20251224081522_add_better_tracking_to_error_logs.rb
319
315
  - db/migrate/20251224101217_add_controller_action_to_error_logs.rb
@@ -344,8 +340,10 @@ files:
344
340
  - lib/rails_error_dashboard/commands/log_error.rb
345
341
  - lib/rails_error_dashboard/commands/resolve_error.rb
346
342
  - lib/rails_error_dashboard/configuration.rb
343
+ - lib/rails_error_dashboard/configuration_error.rb
347
344
  - lib/rails_error_dashboard/engine.rb
348
345
  - lib/rails_error_dashboard/error_reporter.rb
346
+ - lib/rails_error_dashboard/helpers/user_model_detector.rb
349
347
  - lib/rails_error_dashboard/logger.rb
350
348
  - lib/rails_error_dashboard/manual_error_reporter.rb
351
349
  - lib/rails_error_dashboard/middleware/error_catcher.rb
@@ -371,9 +369,13 @@ files:
371
369
  - lib/rails_error_dashboard/services/baseline_alert_throttler.rb
372
370
  - lib/rails_error_dashboard/services/baseline_calculator.rb
373
371
  - lib/rails_error_dashboard/services/cascade_detector.rb
372
+ - lib/rails_error_dashboard/services/error_normalizer.rb
373
+ - lib/rails_error_dashboard/services/git_blame_reader.rb
374
+ - lib/rails_error_dashboard/services/github_link_generator.rb
374
375
  - lib/rails_error_dashboard/services/pattern_detector.rb
375
376
  - lib/rails_error_dashboard/services/platform_detector.rb
376
377
  - lib/rails_error_dashboard/services/similarity_calculator.rb
378
+ - lib/rails_error_dashboard/services/source_code_reader.rb
377
379
  - lib/rails_error_dashboard/value_objects/error_context.rb
378
380
  - lib/rails_error_dashboard/version.rb
379
381
  - lib/tasks/error_dashboard.rake
@@ -385,8 +387,10 @@ metadata:
385
387
  homepage_uri: https://github.com/AnjanJ/rails_error_dashboard
386
388
  source_code_uri: https://github.com/AnjanJ/rails_error_dashboard
387
389
  changelog_uri: https://github.com/AnjanJ/rails_error_dashboard/blob/main/CHANGELOG.md
390
+ documentation_uri: https://rails-error-dashboard.anjan.dev
391
+ demo_uri: https://rails-error-dashboard.anjan.dev
388
392
  post_install_message: "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n
389
- \ Rails Error Dashboard v0.1.28\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n\U0001F195
393
+ \ Rails Error Dashboard v0.1.30\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n\U0001F195
390
394
  First time? Quick start:\n rails generate rails_error_dashboard:install\n rails
391
395
  db:migrate\n # Add to config/routes.rb:\n mount RailsErrorDashboard::Engine
392
396
  => '/error_dashboard'\n\n\U0001F504 Upgrading from v0.1.x?\n rails db:migrate\n
@@ -1,107 +0,0 @@
1
- // =============================================================================
2
- // Catppuccin Mocha Theme - Color Palette
3
- // =============================================================================
4
- // Official Catppuccin color palette for the Mocha flavor (dark theme)
5
- // https://github.com/catppuccin/catppuccin
6
- //
7
- // This file defines both SCSS variables and CSS custom properties for
8
- // maximum flexibility in styling components.
9
- // =============================================================================
10
-
11
- // -----------------------------------------------------------------------------
12
- // SCSS Variables - Accent Colors
13
- // -----------------------------------------------------------------------------
14
- // Use these for compile-time color calculations and SCSS functions
15
-
16
- $ctp-rosewater: #f5e0dc !default; // Soft highlights, subtle accents
17
- $ctp-flamingo: #f2cdcd !default; // Gentle warnings, soft alerts
18
- $ctp-pink: #f5c2e7 !default; // Playful accents, decorative
19
- $ctp-mauve: #cba6f7 !default; // Primary brand color, links
20
- $ctp-red: #f38ba8 !default; // Errors, critical states
21
- $ctp-maroon: #eba0ac !default; // Secondary errors, warnings
22
- $ctp-peach: #fab387 !default; // Warnings, cautionary states
23
- $ctp-yellow: #f9e2af !default; // Highlights, important info
24
- $ctp-green: #a6e3a1 !default; // Success, positive states
25
- $ctp-teal: #94e2d5 !default; // Info, neutral positive
26
- $ctp-sky: #89dceb !default; // Links, interactive elements
27
- $ctp-sapphire: #74c7ec !default; // Accents, decorative
28
- $ctp-blue: #89b4fa !default; // Info, primary actions
29
- $ctp-lavender: #b4befe !default; // Soft accents, highlights
30
-
31
- // -----------------------------------------------------------------------------
32
- // SCSS Variables - Neutral Colors
33
- // -----------------------------------------------------------------------------
34
- // Background and text colors for UI structure
35
-
36
- $ctp-text: #cdd6f4 !default; // Primary text
37
- $ctp-subtext1: #bac2de !default; // Secondary text
38
- $ctp-subtext0: #a6adc8 !default; // Tertiary text, muted
39
- $ctp-overlay2: #9399b2 !default; // Hover states, highlights
40
- $ctp-overlay1: #7f849c !default; // Subtle backgrounds
41
- $ctp-overlay0: #6c7086 !default; // Muted elements, disabled
42
- $ctp-surface2: #585b70 !default; // Secondary surfaces
43
- $ctp-surface1: #45475a !default; // Interactive elements
44
- $ctp-surface0: #313244 !default; // Component backgrounds (cards)
45
- $ctp-base: #1e1e2e !default; // Main background
46
- $ctp-mantle: #181825 !default; // Alternate background
47
- $ctp-crust: #11111b !default; // Borders, edges
48
-
49
- // -----------------------------------------------------------------------------
50
- // CSS Custom Properties (CSS Variables)
51
- // -----------------------------------------------------------------------------
52
- // These can be changed at runtime and accessed from JavaScript
53
- // Use these for theme switching and dynamic styling
54
-
55
- :root {
56
- // Accent colors as CSS variables
57
- --ctp-rosewater: #{$ctp-rosewater};
58
- --ctp-flamingo: #{$ctp-flamingo};
59
- --ctp-pink: #{$ctp-pink};
60
- --ctp-mauve: #{$ctp-mauve};
61
- --ctp-red: #{$ctp-red};
62
- --ctp-maroon: #{$ctp-maroon};
63
- --ctp-peach: #{$ctp-peach};
64
- --ctp-yellow: #{$ctp-yellow};
65
- --ctp-green: #{$ctp-green};
66
- --ctp-teal: #{$ctp-teal};
67
- --ctp-sky: #{$ctp-sky};
68
- --ctp-sapphire: #{$ctp-sapphire};
69
- --ctp-blue: #{$ctp-blue};
70
- --ctp-lavender: #{$ctp-lavender};
71
-
72
- // Neutral colors as CSS variables
73
- --ctp-text: #{$ctp-text};
74
- --ctp-subtext1: #{$ctp-subtext1};
75
- --ctp-subtext0: #{$ctp-subtext0};
76
- --ctp-overlay2: #{$ctp-overlay2};
77
- --ctp-overlay1: #{$ctp-overlay1};
78
- --ctp-overlay0: #{$ctp-overlay0};
79
- --ctp-surface2: #{$ctp-surface2};
80
- --ctp-surface1: #{$ctp-surface1};
81
- --ctp-surface0: #{$ctp-surface0};
82
- --ctp-base: #{$ctp-base};
83
- --ctp-mantle: #{$ctp-mantle};
84
- --ctp-crust: #{$ctp-crust};
85
- }
86
-
87
- // -----------------------------------------------------------------------------
88
- // Utility Functions
89
- // -----------------------------------------------------------------------------
90
-
91
- // Add opacity to a Catppuccin color
92
- // Usage: background-color: ctp-opacity($ctp-red, 0.1);
93
- @function ctp-opacity($color, $opacity) {
94
- @return rgba($color, $opacity);
95
- }
96
-
97
- // Lighten a Catppuccin color (for hover states)
98
- // Usage: background-color: ctp-lighten($ctp-mauve, 10%);
99
- @function ctp-lighten($color, $amount) {
100
- @return lighten($color, $amount);
101
- }
102
-
103
- // Darken a Catppuccin color (for active states)
104
- // Usage: background-color: ctp-darken($ctp-mauve, 10%);
105
- @function ctp-darken($color, $amount) {
106
- @return darken($color, $amount);
107
- }