bertui 1.2.8 → 2.0.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.
Files changed (182) hide show
  1. package/README.md +45 -196
  2. package/TYPES_PATCH.md +17 -0
  3. package/bin/bertui.js +2 -7
  4. package/package.json +32 -98
  5. package/src/config.ts +4 -0
  6. package/src/index.ts +32 -0
  7. package/src/optional.ts +49 -0
  8. package/src/router.ts +3 -0
  9. package/tsconfig.json +29 -0
  10. package/LICENSE +0 -21
  11. package/index.js +0 -103
  12. package/src/analyzer/index.js +0 -370
  13. package/src/build/compiler/file-transpiler.js +0 -216
  14. package/src/build/compiler/index.js +0 -31
  15. package/src/build/compiler/route-discoverer.js +0 -49
  16. package/src/build/compiler/router-generator.js +0 -105
  17. package/src/build/css-builder.js +0 -81
  18. package/src/build/generators/html-generator.js +0 -151
  19. package/src/build/generators/robots-generator.js +0 -58
  20. package/src/build/generators/sitemap-generator.js +0 -63
  21. package/src/build/image-optimizer.js +0 -137
  22. package/src/build/processors/asset-processor.js +0 -19
  23. package/src/build/processors/css-builder.js +0 -142
  24. package/src/build/server-island-validator.js +0 -12
  25. package/src/build.js +0 -266
  26. package/src/cli.js +0 -131
  27. package/src/client/compiler.js +0 -522
  28. package/src/client/fast-refresh.js +0 -72
  29. package/src/client/hmr-runtime.js +0 -59
  30. package/src/compiler/index.js +0 -25
  31. package/src/compiler/router-generator-pure.js +0 -104
  32. package/src/compiler/transform.js +0 -149
  33. package/src/config/defaultConfig.js +0 -37
  34. package/src/config/index.js +0 -2
  35. package/src/config/loadConfig.js +0 -64
  36. package/src/config/og-image.png +0 -0
  37. package/src/css/index.js +0 -46
  38. package/src/css/processor.js +0 -172
  39. package/src/dev.js +0 -68
  40. package/src/hydration/index.js +0 -151
  41. package/src/image-optimizer/index.js +0 -103
  42. package/src/images/index.js +0 -102
  43. package/src/images/processor.js +0 -169
  44. package/src/layouts/index.js +0 -165
  45. package/src/loading/index.js +0 -210
  46. package/src/logger/logger.js +0 -320
  47. package/src/logger/notes.md +0 -20
  48. package/src/middleware/index.js +0 -182
  49. package/src/router/Router.js +0 -150
  50. package/src/router/SSRRouter.js +0 -156
  51. package/src/router/index.js +0 -3
  52. package/src/scaffolder/index.js +0 -310
  53. package/src/serve.js +0 -193
  54. package/src/server/dev-handler.js +0 -195
  55. package/src/server/dev-server-utils.js +0 -406
  56. package/src/server/dev-server.js +0 -15
  57. package/src/server/hmr-handler.js +0 -148
  58. package/src/server/index.js +0 -3
  59. package/src/server/notes.md +0 -1
  60. package/src/server/request-handler.js +0 -36
  61. package/src/server-islands/extractor.js +0 -198
  62. package/src/server-islands/index.js +0 -59
  63. package/src/styles/bertui.css +0 -210
  64. package/src/utils/cache.js +0 -297
  65. package/src/utils/env.js +0 -87
  66. package/src/utils/importhow.js +0 -52
  67. package/src/utils/index.js +0 -11
  68. package/src/utils/meta-extractor.js +0 -127
  69. package/types/bin/bertui.d.ts +0 -3
  70. package/types/bin/bertui.d.ts.map +0 -1
  71. package/types/error-overlay.d.ts +0 -2
  72. package/types/error-overlay.d.ts.map +0 -1
  73. package/types/index.d.ts +0 -26
  74. package/types/index.d.ts.map +0 -1
  75. package/types/scripts/fix-wasm-exports.d.ts +0 -2
  76. package/types/scripts/fix-wasm-exports.d.ts.map +0 -1
  77. package/types/src/analyzer/index.d.ts +0 -8
  78. package/types/src/analyzer/index.d.ts.map +0 -1
  79. package/types/src/build/compiler/file-transpiler.d.ts +0 -5
  80. package/types/src/build/compiler/file-transpiler.d.ts.map +0 -1
  81. package/types/src/build/compiler/index.d.ts +0 -12
  82. package/types/src/build/compiler/index.d.ts.map +0 -1
  83. package/types/src/build/compiler/route-discoverer.d.ts +0 -2
  84. package/types/src/build/compiler/route-discoverer.d.ts.map +0 -1
  85. package/types/src/build/compiler/router-generator.d.ts +0 -2
  86. package/types/src/build/compiler/router-generator.d.ts.map +0 -1
  87. package/types/src/build/css-builder.d.ts +0 -18
  88. package/types/src/build/css-builder.d.ts.map +0 -1
  89. package/types/src/build/generators/html-generator.d.ts +0 -2
  90. package/types/src/build/generators/html-generator.d.ts.map +0 -1
  91. package/types/src/build/generators/robots-generator.d.ts +0 -11
  92. package/types/src/build/generators/robots-generator.d.ts.map +0 -1
  93. package/types/src/build/generators/sitemap-generator.d.ts +0 -5
  94. package/types/src/build/generators/sitemap-generator.d.ts.map +0 -1
  95. package/types/src/build/image-optimizer.d.ts +0 -11
  96. package/types/src/build/image-optimizer.d.ts.map +0 -1
  97. package/types/src/build/processors/asset-processor.d.ts +0 -2
  98. package/types/src/build/processors/asset-processor.d.ts.map +0 -1
  99. package/types/src/build/processors/css-builder.d.ts +0 -2
  100. package/types/src/build/processors/css-builder.d.ts.map +0 -1
  101. package/types/src/build/server-island-validator.d.ts +0 -27
  102. package/types/src/build/server-island-validator.d.ts.map +0 -1
  103. package/types/src/build.d.ts +0 -5
  104. package/types/src/build.d.ts.map +0 -1
  105. package/types/src/cli.d.ts +0 -2
  106. package/types/src/cli.d.ts.map +0 -1
  107. package/types/src/client/compiler.d.ts +0 -16
  108. package/types/src/client/compiler.d.ts.map +0 -1
  109. package/types/src/client/fast-refresh.d.ts +0 -3
  110. package/types/src/client/fast-refresh.d.ts.map +0 -1
  111. package/types/src/client/hmr-runtime.d.ts +0 -4
  112. package/types/src/client/hmr-runtime.d.ts.map +0 -1
  113. package/types/src/compiler/index.d.ts +0 -8
  114. package/types/src/compiler/index.d.ts.map +0 -1
  115. package/types/src/compiler/router-generator-pure.d.ts +0 -2
  116. package/types/src/compiler/router-generator-pure.d.ts.map +0 -1
  117. package/types/src/compiler/transform.d.ts +0 -36
  118. package/types/src/compiler/transform.d.ts.map +0 -1
  119. package/types/src/config/defaultConfig.d.ts +0 -26
  120. package/types/src/config/defaultConfig.d.ts.map +0 -1
  121. package/types/src/config/index.d.ts +0 -3
  122. package/types/src/config/index.d.ts.map +0 -1
  123. package/types/src/config/loadConfig.d.ts +0 -2
  124. package/types/src/config/loadConfig.d.ts.map +0 -1
  125. package/types/src/css/index.d.ts +0 -6
  126. package/types/src/css/index.d.ts.map +0 -1
  127. package/types/src/css/processor.d.ts +0 -23
  128. package/types/src/css/processor.d.ts.map +0 -1
  129. package/types/src/dev.d.ts +0 -2
  130. package/types/src/dev.d.ts.map +0 -1
  131. package/types/src/hydration/index.d.ts +0 -33
  132. package/types/src/hydration/index.d.ts.map +0 -1
  133. package/types/src/image-optimizer/index.d.ts +0 -24
  134. package/types/src/image-optimizer/index.d.ts.map +0 -1
  135. package/types/src/images/index.d.ts +0 -12
  136. package/types/src/images/index.d.ts.map +0 -1
  137. package/types/src/images/processor.d.ts +0 -30
  138. package/types/src/images/processor.d.ts.map +0 -1
  139. package/types/src/layouts/index.d.ts +0 -28
  140. package/types/src/layouts/index.d.ts.map +0 -1
  141. package/types/src/loading/index.d.ts +0 -28
  142. package/types/src/loading/index.d.ts.map +0 -1
  143. package/types/src/logger/logger.d.ts +0 -30
  144. package/types/src/logger/logger.d.ts.map +0 -1
  145. package/types/src/middleware/index.d.ts +0 -61
  146. package/types/src/middleware/index.d.ts.map +0 -1
  147. package/types/src/router/Router.d.ts +0 -16
  148. package/types/src/router/Router.d.ts.map +0 -1
  149. package/types/src/router/SSRRouter.d.ts +0 -20
  150. package/types/src/router/SSRRouter.d.ts.map +0 -1
  151. package/types/src/router/index.d.ts +0 -3
  152. package/types/src/router/index.d.ts.map +0 -1
  153. package/types/src/scaffolder/index.d.ts +0 -14
  154. package/types/src/scaffolder/index.d.ts.map +0 -1
  155. package/types/src/serve.d.ts +0 -3
  156. package/types/src/serve.d.ts.map +0 -1
  157. package/types/src/server/dev-handler.d.ts +0 -13
  158. package/types/src/server/dev-handler.d.ts.map +0 -1
  159. package/types/src/server/dev-server-utils.d.ts +0 -6
  160. package/types/src/server/dev-server-utils.d.ts.map +0 -1
  161. package/types/src/server/dev-server.d.ts +0 -18
  162. package/types/src/server/dev-server.d.ts.map +0 -1
  163. package/types/src/server/hmr-handler.d.ts +0 -19
  164. package/types/src/server/hmr-handler.d.ts.map +0 -1
  165. package/types/src/server/index.d.ts +0 -4
  166. package/types/src/server/index.d.ts.map +0 -1
  167. package/types/src/server/request-handler.d.ts +0 -19
  168. package/types/src/server/request-handler.d.ts.map +0 -1
  169. package/types/src/server-islands/extractor.d.ts +0 -16
  170. package/types/src/server-islands/extractor.d.ts.map +0 -1
  171. package/types/src/server-islands/index.d.ts +0 -3
  172. package/types/src/server-islands/index.d.ts.map +0 -1
  173. package/types/src/utils/cache.d.ts +0 -52
  174. package/types/src/utils/cache.d.ts.map +0 -1
  175. package/types/src/utils/env.d.ts +0 -20
  176. package/types/src/utils/env.d.ts.map +0 -1
  177. package/types/src/utils/importhow.d.ts +0 -15
  178. package/types/src/utils/importhow.d.ts.map +0 -1
  179. package/types/src/utils/index.d.ts +0 -3
  180. package/types/src/utils/index.d.ts.map +0 -1
  181. package/types/src/utils/meta-extractor.d.ts +0 -13
  182. package/types/src/utils/meta-extractor.d.ts.map +0 -1
@@ -1,198 +0,0 @@
1
- // bertui/src/server-islands/extractor.js - PURE SERVER ISLAND EXTRACTOR
2
- // Extract static HTML from Server Island components
3
-
4
- import logger from '../logger/logger.js';
5
-
6
- /**
7
- * Extract static HTML from a Server Island component
8
- * @param {string} sourceCode - The component source code
9
- * @param {string} filePath - Path to file (for error messages)
10
- * @returns {string|null} Extracted HTML or null if extraction fails
11
- */
12
- export function extractStaticHTML(sourceCode, filePath = 'unknown') {
13
- try {
14
- // Find the return statement
15
- const returnMatch = sourceCode.match(/return\s*\(/);
16
- if (!returnMatch) {
17
- logger.warn(`⚠️ Could not find return statement in ${filePath}`);
18
- return null;
19
- }
20
-
21
- // Get code before return for validation
22
- const codeBeforeReturn = sourceCode.substring(0, returnMatch.index);
23
-
24
- // Check for hooks (disallowed in Server Islands)
25
- const hooks = [
26
- 'useState', 'useEffect', 'useContext', 'useReducer',
27
- 'useCallback', 'useMemo', 'useRef', 'useImperativeHandle',
28
- 'useLayoutEffect', 'useDebugValue', 'useId',
29
- 'useDeferredValue', 'useTransition', 'useSyncExternalStore'
30
- ];
31
-
32
- for (const hook of hooks) {
33
- const hookRegex = new RegExp(`\\b${hook}\\s*\\(`, 'g');
34
- if (hookRegex.test(codeBeforeReturn)) {
35
- logger.error(`❌ Server Island at ${filePath} contains React hook: ${hook}`);
36
- return null;
37
- }
38
- }
39
-
40
- // Check for router imports (disallowed)
41
- if (sourceCode.includes('from \'bertui/router\'') ||
42
- sourceCode.includes('from "bertui/router"')) {
43
- logger.error(`❌ Server Island at ${filePath} imports from 'bertui/router'`);
44
- return null;
45
- }
46
-
47
- // Check for event handlers (disallowed in static HTML)
48
- const eventHandlers = [
49
- 'onClick=', 'onChange=', 'onSubmit=', 'onInput=',
50
- 'onFocus=', 'onBlur=', 'onMouseEnter=', 'onMouseLeave=',
51
- 'onKeyDown=', 'onKeyUp=', 'onScroll='
52
- ];
53
-
54
- for (const handler of eventHandlers) {
55
- if (sourceCode.includes(handler)) {
56
- logger.error(`❌ Server Island at ${filePath} uses event handler: ${handler.replace('=', '')}`);
57
- return null;
58
- }
59
- }
60
-
61
- // Extract the JSX content
62
- const fullReturnMatch = sourceCode.match(/return\s*\(([\s\S]*?)\);?\s*}/);
63
- if (!fullReturnMatch) {
64
- logger.warn(`⚠️ Could not extract JSX from ${filePath}`);
65
- return null;
66
- }
67
-
68
- let html = fullReturnMatch[1].trim();
69
-
70
- // Remove comments
71
- html = html.replace(/\{\/\*[\s\S]*?\*\/\}/g, '');
72
-
73
- // Convert className to class
74
- html = html.replace(/className=/g, 'class=');
75
-
76
- // Convert style objects to inline CSS strings
77
- html = convertStyleObjects(html);
78
-
79
- // Fix self-closing tags
80
- html = fixVoidElements(html);
81
-
82
- // Remove JavaScript expressions
83
- html = removeJSExpressions(html);
84
-
85
- // Clean up whitespace
86
- html = html.replace(/\s+/g, ' ').trim();
87
-
88
- logger.debug(` Extracted ${html.length} chars of static HTML from ${filePath}`);
89
- return html;
90
-
91
- } catch (error) {
92
- logger.error(`Failed to extract HTML from ${filePath}: ${error.message}`);
93
- return null;
94
- }
95
- }
96
-
97
- /**
98
- * Convert React style objects to inline CSS strings
99
- */
100
- function convertStyleObjects(html) {
101
- return html.replace(/style=\{\{([^}]+)\}\}/g, (match, styleObj) => {
102
- try {
103
- // Parse the style object properties
104
- const props = [];
105
- let current = '';
106
- let depth = 0;
107
-
108
- for (let i = 0; i < styleObj.length; i++) {
109
- const char = styleObj[i];
110
- if (char === '(') depth++;
111
- if (char === ')') depth--;
112
-
113
- if (char === ',' && depth === 0) {
114
- props.push(current.trim());
115
- current = '';
116
- } else {
117
- current += char;
118
- }
119
- }
120
- if (current.trim()) props.push(current.trim());
121
-
122
- // Convert to CSS string
123
- const cssString = props
124
- .map(prop => {
125
- const colonIndex = prop.indexOf(':');
126
- if (colonIndex === -1) return '';
127
-
128
- const key = prop.substring(0, colonIndex).trim();
129
- const value = prop.substring(colonIndex + 1).trim();
130
-
131
- if (!key || !value) return '';
132
-
133
- // Convert camelCase to kebab-case
134
- const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
135
- // Remove quotes from value
136
- const cssValue = value.replace(/['"]/g, '');
137
-
138
- return `${cssKey}: ${cssValue}`;
139
- })
140
- .filter(Boolean)
141
- .join('; ');
142
-
143
- return `style="${cssString}"`;
144
- } catch (e) {
145
- return 'style=""';
146
- }
147
- });
148
- }
149
-
150
- /**
151
- * Fix void elements (self-closing tags)
152
- */
153
- function fixVoidElements(html) {
154
- const voidElements = [
155
- 'area', 'base', 'br', 'col', 'embed', 'hr', 'img',
156
- 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'
157
- ];
158
-
159
- return html.replace(/<(\w+)([^>]*)\s*\/>/g, (match, tag, attrs) => {
160
- if (voidElements.includes(tag.toLowerCase())) {
161
- // Keep self-closing for void elements
162
- return match;
163
- } else {
164
- // Expand to open/close tags for non-void elements
165
- return `<${tag}${attrs}></${tag}>`;
166
- }
167
- });
168
- }
169
-
170
- /**
171
- * Remove JavaScript expressions from JSX
172
- */
173
- function removeJSExpressions(html) {
174
- return html
175
- // Template literals: {`value`} → value
176
- .replace(/\{`([^`]*)`\}/g, '$1')
177
- // String literals: {'value'} or {"value"} → value
178
- .replace(/\{(['"])(.*?)\1\}/g, '$2')
179
- // Number literals: {123} → 123
180
- .replace(/\{(\d+)\}/g, '$1')
181
- // Remove other expressions
182
- .replace(/\{[^}]+\}/g, '');
183
- }
184
-
185
- /**
186
- * Quick check if a file is a Server Island
187
- */
188
- export function isServerIsland(sourceCode) {
189
- return sourceCode.includes('export const render = "server"');
190
- }
191
-
192
- /**
193
- * Extract component name from file
194
- */
195
- export function extractComponentName(filePath) {
196
- const fileName = filePath.split(/[\/\\]/).pop() || '';
197
- return fileName.replace(/\.[^/.]+$/, '');
198
- }
@@ -1,59 +0,0 @@
1
- // bertui/src/server-islands/index.js - NEW FILE
2
- // PURE Server Island extraction - AST-based, not regex
3
-
4
- import { validateServerIsland } from '../build/server-island-validator.js';
5
-
6
- function extractStaticHTML(componentCode) {
7
- // For now, use existing regex-based extractor
8
- // TODO: Replace with proper AST parser
9
- return extractJSXFromReturn(componentCode);
10
- }
11
-
12
- function extractJSXFromReturn(code) {
13
- const returnMatch = code.match(/return\s*\(([\s\S]*?)\);?\s*}/);
14
- if (!returnMatch) return null;
15
-
16
- let html = returnMatch[1].trim();
17
-
18
- // Basic transformations
19
- html = html.replace(/\{\/\*[\s\S]*?\*\/\}/g, '');
20
- html = html.replace(/className=/g, 'class=');
21
-
22
- // Convert style objects to strings
23
- html = html.replace(/style=\{\{([^}]+)\}\}/g, (match, styleObj) => {
24
- const props = styleObj.split(',').map(p => p.trim()).filter(Boolean);
25
- const cssString = props
26
- .map(prop => {
27
- const [key, value] = prop.split(':').map(s => s.trim());
28
- if (!key || !value) return '';
29
- const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
30
- const cssValue = value.replace(/['"]/g, '');
31
- return `${cssKey}: ${cssValue}`;
32
- })
33
- .filter(Boolean)
34
- .join('; ');
35
- return `style="${cssString}"`;
36
- });
37
-
38
- // Fix void elements
39
- const voidElements = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img',
40
- 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
41
-
42
- html = html.replace(/<(\w+)([^>]*)\s*\/>/g, (match, tag, attrs) => {
43
- if (voidElements.includes(tag.toLowerCase())) {
44
- return match;
45
- }
46
- return `<${tag}${attrs}></${tag}>`;
47
- });
48
-
49
- // Remove JS expressions
50
- html = html.replace(/\{`([^`]*)`\}/g, '$1');
51
- html = html.replace(/\{(['"])(.*?)\1\}/g, '$2');
52
- html = html.replace(/\{(\d+)\}/g, '$1');
53
-
54
- return html;
55
- }
56
-
57
-
58
- export { extractStaticHTML, isServerIsland, extractComponentName } from './extractor.js';
59
- export { validateServerIsland, displayValidationErrors, validateAllServerIslands } from '../build/server-island-validator.js';
@@ -1,210 +0,0 @@
1
- /* BertUI Built-in Utilities v0.1.0 */
2
-
3
- /* Split Text Animation */
4
- .split {
5
- display: inline-block;
6
- position: relative;
7
- overflow: hidden;
8
- }
9
-
10
- .split::before {
11
- content: attr(data-text);
12
- position: absolute;
13
- top: 0;
14
- left: 0;
15
- width: 50%;
16
- overflow: hidden;
17
- animation: split-left 0.6s ease-out;
18
- }
19
-
20
- .split::after {
21
- content: attr(data-text);
22
- position: absolute;
23
- top: 0;
24
- right: 0;
25
- width: 50%;
26
- overflow: hidden;
27
- animation: split-right 0.6s ease-out;
28
- }
29
-
30
- @keyframes split-left {
31
- from {
32
- transform: translateX(-100%);
33
- opacity: 0;
34
- }
35
- to {
36
- transform: translateX(0);
37
- opacity: 1;
38
- }
39
- }
40
-
41
- @keyframes split-right {
42
- from {
43
- transform: translateX(100%);
44
- opacity: 0;
45
- }
46
- to {
47
- transform: translateX(0);
48
- opacity: 1;
49
- }
50
- }
51
-
52
- /* Move Right Animation */
53
- .moveright {
54
- animation: moveright 0.5s ease-out;
55
- }
56
-
57
- @keyframes moveright {
58
- from {
59
- transform: translateX(-20px);
60
- opacity: 0;
61
- }
62
- to {
63
- transform: translateX(0);
64
- opacity: 1;
65
- }
66
- }
67
-
68
- /* Move Left Animation */
69
- .moveleft {
70
- animation: moveleft 0.5s ease-out;
71
- }
72
-
73
- @keyframes moveleft {
74
- from {
75
- transform: translateX(20px);
76
- opacity: 0;
77
- }
78
- to {
79
- transform: translateX(0);
80
- opacity: 1;
81
- }
82
- }
83
-
84
- /* Fade In */
85
- .fadein {
86
- animation: fadein 0.5s ease-out;
87
- }
88
-
89
- @keyframes fadein {
90
- from {
91
- opacity: 0;
92
- }
93
- to {
94
- opacity: 1;
95
- }
96
- }
97
-
98
- /* Scale In */
99
- .scalein {
100
- animation: scalein 0.4s ease-out;
101
- }
102
-
103
- @keyframes scalein {
104
- from {
105
- transform: scale(0.8);
106
- opacity: 0;
107
- }
108
- to {
109
- transform: scale(1);
110
- opacity: 1;
111
- }
112
- }
113
-
114
- /* Bounce In */
115
- .bouncein {
116
- animation: bouncein 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55);
117
- }
118
-
119
- @keyframes bouncein {
120
- 0% {
121
- transform: scale(0);
122
- opacity: 0;
123
- }
124
- 50% {
125
- transform: scale(1.1);
126
- }
127
- 100% {
128
- transform: scale(1);
129
- opacity: 1;
130
- }
131
- }
132
-
133
- /* Slide Up */
134
- .slideup {
135
- animation: slideup 0.5s ease-out;
136
- }
137
-
138
- @keyframes slideup {
139
- from {
140
- transform: translateY(20px);
141
- opacity: 0;
142
- }
143
- to {
144
- transform: translateY(0);
145
- opacity: 1;
146
- }
147
- }
148
-
149
- /* Slide Down */
150
- .slidedown {
151
- animation: slidedown 0.5s ease-out;
152
- }
153
-
154
- @keyframes slidedown {
155
- from {
156
- transform: translateY(-20px);
157
- opacity: 0;
158
- }
159
- to {
160
- transform: translateY(0);
161
- opacity: 1;
162
- }
163
- }
164
-
165
- /* Rotate In */
166
- .rotatein {
167
- animation: rotatein 0.6s ease-out;
168
- }
169
-
170
- @keyframes rotatein {
171
- from {
172
- transform: rotate(-180deg) scale(0);
173
- opacity: 0;
174
- }
175
- to {
176
- transform: rotate(0) scale(1);
177
- opacity: 1;
178
- }
179
- }
180
-
181
- /* Pulse */
182
- .pulse {
183
- animation: pulse 1.5s ease-in-out infinite;
184
- }
185
-
186
- @keyframes pulse {
187
- 0%, 100% {
188
- transform: scale(1);
189
- }
190
- 50% {
191
- transform: scale(1.05);
192
- }
193
- }
194
-
195
- /* Shake */
196
- .shake {
197
- animation: shake 0.5s ease-in-out;
198
- }
199
-
200
- @keyframes shake {
201
- 0%, 100% {
202
- transform: translateX(0);
203
- }
204
- 10%, 30%, 50%, 70%, 90% {
205
- transform: translateX(-5px);
206
- }
207
- 20%, 40%, 60%, 80% {
208
- transform: translateX(5px);
209
- }
210
- }