imcp 0.0.1

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 (124) hide show
  1. package/.github/ISSUE_TEMPLATE/JitAccess.yml +28 -0
  2. package/.github/acl/access.yml +20 -0
  3. package/.github/compliance/inventory.yml +5 -0
  4. package/.github/policies/jit.yml +19 -0
  5. package/README.md +137 -0
  6. package/dist/cli/commands/install.d.ts +2 -0
  7. package/dist/cli/commands/install.js +105 -0
  8. package/dist/cli/commands/list.d.ts +2 -0
  9. package/dist/cli/commands/list.js +90 -0
  10. package/dist/cli/commands/pull.d.ts +2 -0
  11. package/dist/cli/commands/pull.js +17 -0
  12. package/dist/cli/commands/serve.d.ts +2 -0
  13. package/dist/cli/commands/serve.js +32 -0
  14. package/dist/cli/commands/start.d.ts +2 -0
  15. package/dist/cli/commands/start.js +32 -0
  16. package/dist/cli/commands/sync.d.ts +2 -0
  17. package/dist/cli/commands/sync.js +17 -0
  18. package/dist/cli/commands/uninstall.d.ts +2 -0
  19. package/dist/cli/commands/uninstall.js +39 -0
  20. package/dist/cli/index.d.ts +2 -0
  21. package/dist/cli/index.js +114 -0
  22. package/dist/core/ConfigurationProvider.d.ts +31 -0
  23. package/dist/core/ConfigurationProvider.js +416 -0
  24. package/dist/core/InstallationService.d.ts +17 -0
  25. package/dist/core/InstallationService.js +144 -0
  26. package/dist/core/MCPManager.d.ts +17 -0
  27. package/dist/core/MCPManager.js +98 -0
  28. package/dist/core/RequirementService.d.ts +45 -0
  29. package/dist/core/RequirementService.js +123 -0
  30. package/dist/core/constants.d.ts +29 -0
  31. package/dist/core/constants.js +55 -0
  32. package/dist/core/installers/BaseInstaller.d.ts +73 -0
  33. package/dist/core/installers/BaseInstaller.js +247 -0
  34. package/dist/core/installers/ClientInstaller.d.ts +17 -0
  35. package/dist/core/installers/ClientInstaller.js +307 -0
  36. package/dist/core/installers/CommandInstaller.d.ts +36 -0
  37. package/dist/core/installers/CommandInstaller.js +170 -0
  38. package/dist/core/installers/GeneralInstaller.d.ts +32 -0
  39. package/dist/core/installers/GeneralInstaller.js +87 -0
  40. package/dist/core/installers/InstallerFactory.d.ts +52 -0
  41. package/dist/core/installers/InstallerFactory.js +95 -0
  42. package/dist/core/installers/NpmInstaller.d.ts +25 -0
  43. package/dist/core/installers/NpmInstaller.js +123 -0
  44. package/dist/core/installers/PipInstaller.d.ts +25 -0
  45. package/dist/core/installers/PipInstaller.js +114 -0
  46. package/dist/core/installers/RequirementInstaller.d.ts +32 -0
  47. package/dist/core/installers/RequirementInstaller.js +3 -0
  48. package/dist/core/installers/index.d.ts +6 -0
  49. package/dist/core/installers/index.js +7 -0
  50. package/dist/core/types.d.ts +152 -0
  51. package/dist/core/types.js +16 -0
  52. package/dist/index.d.ts +11 -0
  53. package/dist/index.js +19 -0
  54. package/dist/services/InstallRequestValidator.d.ts +21 -0
  55. package/dist/services/InstallRequestValidator.js +99 -0
  56. package/dist/services/ServerService.d.ts +47 -0
  57. package/dist/services/ServerService.js +145 -0
  58. package/dist/utils/UpdateCheckTracker.d.ts +39 -0
  59. package/dist/utils/UpdateCheckTracker.js +80 -0
  60. package/dist/utils/clientUtils.d.ts +29 -0
  61. package/dist/utils/clientUtils.js +105 -0
  62. package/dist/utils/feedUtils.d.ts +5 -0
  63. package/dist/utils/feedUtils.js +29 -0
  64. package/dist/utils/githubAuth.d.ts +1 -0
  65. package/dist/utils/githubAuth.js +123 -0
  66. package/dist/utils/logger.d.ts +14 -0
  67. package/dist/utils/logger.js +90 -0
  68. package/dist/utils/osUtils.d.ts +16 -0
  69. package/dist/utils/osUtils.js +235 -0
  70. package/dist/web/public/css/modal.css +250 -0
  71. package/dist/web/public/css/notifications.css +70 -0
  72. package/dist/web/public/index.html +157 -0
  73. package/dist/web/public/js/api.js +213 -0
  74. package/dist/web/public/js/modal.js +572 -0
  75. package/dist/web/public/js/notifications.js +99 -0
  76. package/dist/web/public/js/serverCategoryDetails.js +210 -0
  77. package/dist/web/public/js/serverCategoryList.js +82 -0
  78. package/dist/web/public/modal.html +61 -0
  79. package/dist/web/public/styles.css +155 -0
  80. package/dist/web/server.d.ts +5 -0
  81. package/dist/web/server.js +150 -0
  82. package/package.json +53 -0
  83. package/src/cli/commands/install.ts +140 -0
  84. package/src/cli/commands/list.ts +112 -0
  85. package/src/cli/commands/pull.ts +16 -0
  86. package/src/cli/commands/serve.ts +37 -0
  87. package/src/cli/commands/uninstall.ts +54 -0
  88. package/src/cli/index.ts +127 -0
  89. package/src/core/ConfigurationProvider.ts +489 -0
  90. package/src/core/InstallationService.ts +173 -0
  91. package/src/core/MCPManager.ts +134 -0
  92. package/src/core/RequirementService.ts +147 -0
  93. package/src/core/constants.ts +61 -0
  94. package/src/core/installers/BaseInstaller.ts +292 -0
  95. package/src/core/installers/ClientInstaller.ts +423 -0
  96. package/src/core/installers/CommandInstaller.ts +185 -0
  97. package/src/core/installers/GeneralInstaller.ts +89 -0
  98. package/src/core/installers/InstallerFactory.ts +109 -0
  99. package/src/core/installers/NpmInstaller.ts +128 -0
  100. package/src/core/installers/PipInstaller.ts +121 -0
  101. package/src/core/installers/RequirementInstaller.ts +38 -0
  102. package/src/core/installers/index.ts +9 -0
  103. package/src/core/types.ts +163 -0
  104. package/src/index.ts +44 -0
  105. package/src/services/InstallRequestValidator.ts +112 -0
  106. package/src/services/ServerService.ts +181 -0
  107. package/src/utils/UpdateCheckTracker.ts +86 -0
  108. package/src/utils/clientUtils.ts +112 -0
  109. package/src/utils/feedUtils.ts +31 -0
  110. package/src/utils/githubAuth.ts +142 -0
  111. package/src/utils/logger.ts +101 -0
  112. package/src/utils/osUtils.ts +250 -0
  113. package/src/web/public/css/modal.css +250 -0
  114. package/src/web/public/css/notifications.css +70 -0
  115. package/src/web/public/index.html +157 -0
  116. package/src/web/public/js/api.js +213 -0
  117. package/src/web/public/js/modal.js +572 -0
  118. package/src/web/public/js/notifications.js +99 -0
  119. package/src/web/public/js/serverCategoryDetails.js +210 -0
  120. package/src/web/public/js/serverCategoryList.js +82 -0
  121. package/src/web/public/modal.html +61 -0
  122. package/src/web/public/styles.css +155 -0
  123. package/src/web/server.ts +195 -0
  124. package/tsconfig.json +18 -0
@@ -0,0 +1,16 @@
1
+ import { OSType } from '../core/types.js';
2
+ export declare function getOSType(): OSType;
3
+ export declare function installCLI(tool: 'gh' | 'git'): Promise<void>;
4
+ /**
5
+ * Refreshes the PATH environment variable for the current Node.js process
6
+ * This is necessary because when tools are installed using package managers,
7
+ * they update the system PATH but the current Node process doesn't see those changes.
8
+ */
9
+ export declare function refreshPathEnv(): Promise<void>;
10
+ export declare function isToolInstalled(tool: 'gh' | 'git', retries?: number): Promise<boolean>;
11
+ /**
12
+ * Opens a URL in the default browser
13
+ * @param url The URL to open
14
+ * @returns A promise that resolves when the browser is launched
15
+ */
16
+ export declare function openBrowser(url: string): Promise<void>;
@@ -0,0 +1,235 @@
1
+ import { OSType } from '../core/types.js';
2
+ import os from 'os';
3
+ import { exec } from 'child_process';
4
+ import util from 'util';
5
+ import { Logger } from './logger.js';
6
+ const execAsync = util.promisify(exec);
7
+ export function getOSType() {
8
+ const platform = os.platform();
9
+ Logger.debug({
10
+ action: 'get_os_type',
11
+ platform
12
+ });
13
+ switch (platform) {
14
+ case 'win32':
15
+ return OSType.Windows;
16
+ case 'darwin':
17
+ return OSType.MacOS;
18
+ case 'linux':
19
+ return OSType.Linux;
20
+ default:
21
+ const error = `Unsupported operating system: ${platform}`;
22
+ Logger.error(error);
23
+ throw new Error(error);
24
+ }
25
+ }
26
+ export async function installCLI(tool) {
27
+ const osType = getOSType();
28
+ Logger.debug({
29
+ action: 'install_cli',
30
+ tool,
31
+ osType
32
+ });
33
+ try {
34
+ switch (osType) {
35
+ case OSType.Windows:
36
+ if (tool === 'git') {
37
+ await execAsync('winget install --id Git.Git -e --source winget --silent');
38
+ }
39
+ else {
40
+ await execAsync('winget install --id GitHub.cli --silent');
41
+ }
42
+ // Refresh PATH environment variable after installation
43
+ await refreshPathEnv();
44
+ break;
45
+ case OSType.MacOS:
46
+ if (tool === 'git') {
47
+ await execAsync('brew install git');
48
+ }
49
+ else {
50
+ await execAsync('brew install gh');
51
+ }
52
+ // On macOS, we may need to source profile files
53
+ if (tool === 'git') {
54
+ await execAsync('source ~/.zshrc || source ~/.bash_profile || source ~/.bashrc || true');
55
+ }
56
+ break;
57
+ case OSType.Linux:
58
+ if (tool === 'git') {
59
+ await execAsync('sudo apt-get update && sudo apt-get install -y git');
60
+ }
61
+ else {
62
+ await execAsync('curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null && sudo apt update && sudo apt install -y gh');
63
+ }
64
+ // Source bash profile to refresh PATH
65
+ await execAsync('source ~/.bashrc || source ~/.profile || true');
66
+ break;
67
+ default:
68
+ throw new Error(`Unsupported operating system for installing ${tool}`);
69
+ }
70
+ // Wait a moment for system to register the new binaries
71
+ await new Promise(resolve => setTimeout(resolve, 1000));
72
+ Logger.debug({
73
+ action: 'install_cli_success',
74
+ tool,
75
+ osType
76
+ });
77
+ }
78
+ catch (error) {
79
+ Logger.error('Failed to install CLI tool', {
80
+ tool,
81
+ osType,
82
+ error
83
+ });
84
+ throw error;
85
+ }
86
+ }
87
+ /**
88
+ * Refreshes the PATH environment variable for the current Node.js process
89
+ * This is necessary because when tools are installed using package managers,
90
+ * they update the system PATH but the current Node process doesn't see those changes.
91
+ */
92
+ export async function refreshPathEnv() {
93
+ const osType = getOSType();
94
+ Logger.debug({
95
+ action: 'refresh_path_env',
96
+ osType
97
+ });
98
+ try {
99
+ switch (osType) {
100
+ case OSType.Windows:
101
+ // On Windows, get the PATH from registry
102
+ const { stdout: winPath } = await execAsync('powershell -command "[Environment]::GetEnvironmentVariable(\'Path\', \'Machine\') + \';\' + [Environment]::GetEnvironmentVariable(\'Path\', \'User\')"');
103
+ if (winPath) {
104
+ process.env.PATH = winPath.trim();
105
+ Logger.debug('Refreshed PATH from Windows registry');
106
+ }
107
+ break;
108
+ case OSType.MacOS:
109
+ case OSType.Linux:
110
+ // On Unix systems, typical installation locations if PATH isn't updated
111
+ const commonPaths = [
112
+ '/usr/local/bin',
113
+ '/usr/bin',
114
+ '/bin',
115
+ '/usr/sbin',
116
+ '/sbin',
117
+ '/usr/local/git/bin',
118
+ '/opt/homebrew/bin', // For M1 Macs
119
+ `${os.homedir()}/.local/bin`
120
+ ];
121
+ // Ensure these paths are in process.env.PATH
122
+ if (process.env.PATH) {
123
+ const currentPaths = process.env.PATH.split(':');
124
+ const newPaths = [...new Set([...currentPaths, ...commonPaths])];
125
+ process.env.PATH = newPaths.join(':');
126
+ Logger.debug('Expanded PATH with common Unix binary locations');
127
+ }
128
+ break;
129
+ }
130
+ Logger.debug({
131
+ action: 'refresh_path_env_success',
132
+ path: process.env.PATH
133
+ });
134
+ }
135
+ catch (error) {
136
+ Logger.error('Failed to refresh PATH environment variable', error);
137
+ // Continue execution even if PATH refresh fails
138
+ }
139
+ }
140
+ export async function isToolInstalled(tool, retries = 3) {
141
+ try {
142
+ Logger.debug({
143
+ action: 'check_tool_installed',
144
+ tool,
145
+ retries
146
+ });
147
+ // Try to execute tool command
148
+ try {
149
+ await execAsync(`${tool} --version`);
150
+ Logger.debug({
151
+ action: 'check_tool_installed_success',
152
+ tool,
153
+ installed: true
154
+ });
155
+ return true;
156
+ }
157
+ catch (error) {
158
+ // If we have retries left, refresh PATH and try again
159
+ if (retries > 0) {
160
+ Logger.debug(`${tool} not found, refreshing PATH and retrying...`);
161
+ // Refresh environment PATH variable
162
+ await refreshPathEnv();
163
+ // Wait a moment before retrying
164
+ await new Promise(resolve => setTimeout(resolve, 500));
165
+ // Recursive retry with decremented counter
166
+ return isToolInstalled(tool, retries - 1);
167
+ }
168
+ // No retries left, tool is not installed
169
+ Logger.debug({
170
+ action: 'check_tool_installed_success',
171
+ tool,
172
+ installed: false
173
+ });
174
+ return false;
175
+ }
176
+ }
177
+ catch (error) {
178
+ Logger.error(`Error checking if ${tool} is installed`, error);
179
+ return false;
180
+ }
181
+ }
182
+ /**
183
+ * Opens a URL in the default browser
184
+ * @param url The URL to open
185
+ * @returns A promise that resolves when the browser is launched
186
+ */
187
+ export async function openBrowser(url) {
188
+ const osType = getOSType();
189
+ Logger.debug({
190
+ action: 'open_browser',
191
+ url,
192
+ osType
193
+ });
194
+ try {
195
+ switch (osType) {
196
+ case OSType.Windows:
197
+ await execAsync(`start ${url}`);
198
+ break;
199
+ case OSType.MacOS:
200
+ await execAsync(`open ${url}`);
201
+ break;
202
+ case OSType.Linux:
203
+ // Try different commands that might be available
204
+ try {
205
+ await execAsync(`xdg-open ${url}`);
206
+ }
207
+ catch (error) {
208
+ // Try alternative commands
209
+ try {
210
+ await execAsync(`sensible-browser ${url}`);
211
+ }
212
+ catch (error) {
213
+ await execAsync(`gnome-open ${url}`);
214
+ }
215
+ }
216
+ break;
217
+ default:
218
+ throw new Error(`Unsupported operating system for opening browser`);
219
+ }
220
+ Logger.debug({
221
+ action: 'open_browser_success',
222
+ url,
223
+ osType
224
+ });
225
+ }
226
+ catch (error) {
227
+ Logger.error('Failed to open browser', {
228
+ url,
229
+ osType,
230
+ error
231
+ });
232
+ // Don't throw the error - just log it and continue
233
+ }
234
+ }
235
+ //# sourceMappingURL=osUtils.js.map
@@ -0,0 +1,250 @@
1
+ /* Import Inter font */
2
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
3
+
4
+ /* Base styles */
5
+ body {
6
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
7
+ }
8
+
9
+ /* Modal container */
10
+ .modal {
11
+ display: none;
12
+ position: fixed;
13
+ z-index: 50;
14
+ left: 0;
15
+ top: 0;
16
+ width: 100%;
17
+ height: 100%;
18
+ overflow: auto;
19
+ background-color: rgba(0, 0, 0, 0.5);
20
+ backdrop-filter: blur(4px);
21
+ animation: fadeIn 0.2s ease-out;
22
+ /* Debug: Ensure loading modal is always visible and content is not hidden */
23
+ #installLoadingModal {
24
+ z-index: 3000 !important;
25
+ display: none;
26
+ }
27
+ #installLoadingModal .modal-content {
28
+ z-index: 3100 !important;
29
+ pointer-events: auto;
30
+ background: #fff !important;
31
+ border: 3px solid #3498db !important;
32
+ color: #222 !important;
33
+ min-width: 320px;
34
+ min-height: 120px;
35
+ opacity: 1 !important;
36
+ box-shadow: 0 0 16px #3498db;
37
+ }
38
+ /* Loading modal always on top */
39
+ #installLoadingModal {
40
+ z-index: 2000 !important;
41
+ display: none;
42
+ }
43
+ #installLoadingModal .modal-content {
44
+ z-index: 2100 !important;
45
+ pointer-events: auto;
46
+ }
47
+ }
48
+
49
+ /* Modal content */
50
+ .modal-content {
51
+ background-color: #ffffff;
52
+ margin: 10% auto;
53
+ padding: 2rem;
54
+ border: none;
55
+ border-radius: 1rem;
56
+ width: 90%;
57
+ max-width: 550px;
58
+ position: relative;
59
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
60
+ transform: translateY(0);
61
+ transition: all 0.3s ease-out;
62
+ animation: slideIn 0.3s ease-out;
63
+ }
64
+
65
+ /* Close button */
66
+ .close {
67
+ position: absolute;
68
+ right: 1.5rem;
69
+ top: 1.5rem;
70
+ font-size: 1.5rem;
71
+ font-weight: 600;
72
+ color: #6b7280;
73
+ cursor: pointer;
74
+ width: 32px;
75
+ height: 32px;
76
+ display: flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ border-radius: 50%;
80
+ transition: color 0.2s ease;
81
+ }
82
+
83
+ .close:hover {
84
+ background-color: #f3f4f6;
85
+ color: #111827;
86
+ }
87
+
88
+ /* Sections layout */
89
+ .modal-sections {
90
+ margin-top: 1.5rem;
91
+ }
92
+
93
+ .section-container {
94
+ padding: 1.25rem;
95
+ margin-bottom: 1.5rem;
96
+ border: 1px solid #e5e7eb;
97
+ border-radius: 0.75rem;
98
+ background-color: #f9fafb;
99
+ transition: all 0.2s ease;
100
+ }
101
+
102
+ .section-title {
103
+ margin-bottom: 1rem;
104
+ }
105
+
106
+ /* Client grid */
107
+ .client-grid {
108
+ display: grid;
109
+ grid-template-columns: 1fr;
110
+ gap: 0.75rem;
111
+ }
112
+
113
+ /* Client item styling */
114
+ .client-item {
115
+ display: flex;
116
+ align-items: center;
117
+ justify-content: space-between;
118
+ padding: 0.75rem 1rem;
119
+ border-radius: 0.5rem;
120
+ border: 2px solid #e5e7eb;
121
+ background-color: #ffffff;
122
+ transition: all 0.2s ease;
123
+ cursor: pointer;
124
+ user-select: none;
125
+ }
126
+
127
+ .client-item:hover {
128
+ background-color: #f3f4f6;
129
+ transform: translateY(-1px);
130
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
131
+ }
132
+
133
+ .client-item.selected {
134
+ border-color: #2563eb;
135
+ background-color: #eff6ff;
136
+ }
137
+
138
+ /* Client item info section */
139
+ .client-info {
140
+ display: flex;
141
+ align-items: center;
142
+ gap: 0.75rem;
143
+ }
144
+
145
+ /* Status badges */
146
+ .status-badge {
147
+ display: inline-flex;
148
+ align-items: center;
149
+ padding: 0.25rem 0.75rem;
150
+ border-radius: 9999px;
151
+ font-size: 0.75rem;
152
+ font-weight: 500;
153
+ }
154
+
155
+ .status-badge.installed {
156
+ background-color: #dcfce7;
157
+ color: #166534;
158
+ }
159
+
160
+ .status-badge.not-installed {
161
+ background-color: #fee2e2;
162
+ color: #991b1b;
163
+ }
164
+
165
+ .status-badge.pending {
166
+ background-color: #fef3c7;
167
+ color: #92400e;
168
+ }
169
+
170
+ /* Non-selectable items (installed or in-progress) */
171
+ .client-item.non-selectable {
172
+ background-color: #f9fafb;
173
+ cursor: default;
174
+ opacity: 0.85;
175
+ }
176
+
177
+ .client-item.non-selectable:hover {
178
+ transform: none;
179
+ box-shadow: none;
180
+ }
181
+
182
+ /* Specific styling for installed items */
183
+ .client-item.installed-item {
184
+ background-color: #f0fdf4;
185
+ }
186
+
187
+ /* Specific styling for in-progress items */
188
+ .client-item.in-progress-item {
189
+ background-color: #fef3c7;
190
+ }
191
+
192
+ /* Environment variables section */
193
+ #modalEnvInputs input {
194
+ width: 100%;
195
+ padding: 0.75rem 1rem;
196
+ border: 1px solid #e5e7eb;
197
+ border-radius: 0.5rem;
198
+ transition: all 0.2s ease;
199
+ }
200
+
201
+ #modalEnvInputs input:focus {
202
+ outline: none;
203
+ border-color: #2563eb;
204
+ box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
205
+ }
206
+
207
+ /* Form buttons */
208
+ .submit-button {
209
+ background-color: #2563eb;
210
+ color: white;
211
+ padding: 0.625rem 1.25rem;
212
+ border-radius: 0.5rem;
213
+ font-weight: 500;
214
+ transition: all 0.2s ease;
215
+ }
216
+
217
+ .submit-button:hover {
218
+ background-color: #1d4ed8;
219
+ transform: translateY(-1px);
220
+ }
221
+
222
+ .submit-button:active {
223
+ transform: translateY(0);
224
+ }
225
+
226
+ /* Animations */
227
+ @keyframes fadeIn {
228
+ from { opacity: 0; }
229
+ to { opacity: 1; }
230
+ }
231
+
232
+ @keyframes slideIn {
233
+ from {
234
+ opacity: 0;
235
+ transform: translateY(-20px);
236
+ }
237
+ to {
238
+ opacity: 1;
239
+ transform: translateY(0);
240
+ }
241
+ }
242
+
243
+ /* Center loading icon in loading modal */
244
+ #installLoadingModal .loading-icon {
245
+ display: flex;
246
+ justify-content: center;
247
+ align-items: center;
248
+ width: 100%;
249
+ margin-bottom: 8px;
250
+ }
@@ -0,0 +1,70 @@
1
+ /* Alert container */
2
+ .alert-container {
3
+ z-index: 999999; /* Extremely high to appear above modals */
4
+ position: fixed;
5
+ top: 0 !important;
6
+ left: 0 !important;
7
+ right: 0 !important;
8
+ display: flex;
9
+ flex-direction: column;
10
+ align-items: center;
11
+ gap: 10px;
12
+ pointer-events: none; /* Allow clicking through the container */
13
+ }
14
+
15
+ .alert {
16
+ min-width: 350px;
17
+ max-width: 500px;
18
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
19
+ backdrop-filter: blur(8px);
20
+ border-width: 2px;
21
+ pointer-events: auto; /* Re-enable pointer events for alerts */
22
+ padding: 0.75rem 1.5rem;
23
+ font-size: 1.1rem;
24
+ font-weight: 500;
25
+ margin-top: 10px;
26
+ }
27
+
28
+ .alert:first-child {
29
+ margin-top: 0;
30
+ }
31
+
32
+ .alert.alert-success {
33
+ background-color: rgba(25, 135, 84, 0.98);
34
+ border-color: #146c43;
35
+ color: white;
36
+ font-weight: 500;
37
+ }
38
+
39
+ .alert.alert-error {
40
+ background-color: rgba(220, 53, 69, 0.98);
41
+ border-color: #b02a37;
42
+ color: white;
43
+ font-weight: 500;
44
+ }
45
+
46
+ .alert .btn-close {
47
+ filter: brightness(0) invert(1);
48
+ opacity: 0.8;
49
+ padding: 0.75rem;
50
+ }
51
+
52
+ /* When modal is open, add backdrop to alerts */
53
+ .modal.show ~ .alert-container .alert {
54
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
55
+ backdrop-filter: blur(12px);
56
+ }
57
+
58
+ /* Modal customization */
59
+ .modal-content {
60
+ border: none;
61
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
62
+ }
63
+
64
+ .modal-header {
65
+ border-bottom: 1px solid rgba(0, 0, 0, 0.05);
66
+ }
67
+
68
+ .modal-footer {
69
+ border-top: 1px solid rgba(0, 0, 0, 0.05);
70
+ }