@seo-console/package 1.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.
@@ -0,0 +1,3593 @@
1
+ // src/components/seo/SEORecordList.tsx
2
+ import { useState as useState3, useEffect as useEffect2 } from "react";
3
+
4
+ // src/components/ui/button.tsx
5
+ import * as React from "react";
6
+
7
+ // src/lib/utils.ts
8
+ import { clsx } from "clsx";
9
+
10
+ // ../../node_modules/tailwind-merge/dist/bundle-mjs.mjs
11
+ var CLASS_PART_SEPARATOR = "-";
12
+ var createClassGroupUtils = (config) => {
13
+ const classMap = createClassMap(config);
14
+ const {
15
+ conflictingClassGroups,
16
+ conflictingClassGroupModifiers
17
+ } = config;
18
+ const getClassGroupId = (className) => {
19
+ const classParts = className.split(CLASS_PART_SEPARATOR);
20
+ if (classParts[0] === "" && classParts.length !== 1) {
21
+ classParts.shift();
22
+ }
23
+ return getGroupRecursive(classParts, classMap) || getGroupIdForArbitraryProperty(className);
24
+ };
25
+ const getConflictingClassGroupIds = (classGroupId, hasPostfixModifier) => {
26
+ const conflicts = conflictingClassGroups[classGroupId] || [];
27
+ if (hasPostfixModifier && conflictingClassGroupModifiers[classGroupId]) {
28
+ return [...conflicts, ...conflictingClassGroupModifiers[classGroupId]];
29
+ }
30
+ return conflicts;
31
+ };
32
+ return {
33
+ getClassGroupId,
34
+ getConflictingClassGroupIds
35
+ };
36
+ };
37
+ var getGroupRecursive = (classParts, classPartObject) => {
38
+ if (classParts.length === 0) {
39
+ return classPartObject.classGroupId;
40
+ }
41
+ const currentClassPart = classParts[0];
42
+ const nextClassPartObject = classPartObject.nextPart.get(currentClassPart);
43
+ const classGroupFromNextClassPart = nextClassPartObject ? getGroupRecursive(classParts.slice(1), nextClassPartObject) : void 0;
44
+ if (classGroupFromNextClassPart) {
45
+ return classGroupFromNextClassPart;
46
+ }
47
+ if (classPartObject.validators.length === 0) {
48
+ return void 0;
49
+ }
50
+ const classRest = classParts.join(CLASS_PART_SEPARATOR);
51
+ return classPartObject.validators.find(({
52
+ validator
53
+ }) => validator(classRest))?.classGroupId;
54
+ };
55
+ var arbitraryPropertyRegex = /^\[(.+)\]$/;
56
+ var getGroupIdForArbitraryProperty = (className) => {
57
+ if (arbitraryPropertyRegex.test(className)) {
58
+ const arbitraryPropertyClassName = arbitraryPropertyRegex.exec(className)[1];
59
+ const property = arbitraryPropertyClassName?.substring(0, arbitraryPropertyClassName.indexOf(":"));
60
+ if (property) {
61
+ return "arbitrary.." + property;
62
+ }
63
+ }
64
+ };
65
+ var createClassMap = (config) => {
66
+ const {
67
+ theme,
68
+ prefix
69
+ } = config;
70
+ const classMap = {
71
+ nextPart: /* @__PURE__ */ new Map(),
72
+ validators: []
73
+ };
74
+ const prefixedClassGroupEntries = getPrefixedClassGroupEntries(Object.entries(config.classGroups), prefix);
75
+ prefixedClassGroupEntries.forEach(([classGroupId, classGroup]) => {
76
+ processClassesRecursively(classGroup, classMap, classGroupId, theme);
77
+ });
78
+ return classMap;
79
+ };
80
+ var processClassesRecursively = (classGroup, classPartObject, classGroupId, theme) => {
81
+ classGroup.forEach((classDefinition) => {
82
+ if (typeof classDefinition === "string") {
83
+ const classPartObjectToEdit = classDefinition === "" ? classPartObject : getPart(classPartObject, classDefinition);
84
+ classPartObjectToEdit.classGroupId = classGroupId;
85
+ return;
86
+ }
87
+ if (typeof classDefinition === "function") {
88
+ if (isThemeGetter(classDefinition)) {
89
+ processClassesRecursively(classDefinition(theme), classPartObject, classGroupId, theme);
90
+ return;
91
+ }
92
+ classPartObject.validators.push({
93
+ validator: classDefinition,
94
+ classGroupId
95
+ });
96
+ return;
97
+ }
98
+ Object.entries(classDefinition).forEach(([key, classGroup2]) => {
99
+ processClassesRecursively(classGroup2, getPart(classPartObject, key), classGroupId, theme);
100
+ });
101
+ });
102
+ };
103
+ var getPart = (classPartObject, path) => {
104
+ let currentClassPartObject = classPartObject;
105
+ path.split(CLASS_PART_SEPARATOR).forEach((pathPart) => {
106
+ if (!currentClassPartObject.nextPart.has(pathPart)) {
107
+ currentClassPartObject.nextPart.set(pathPart, {
108
+ nextPart: /* @__PURE__ */ new Map(),
109
+ validators: []
110
+ });
111
+ }
112
+ currentClassPartObject = currentClassPartObject.nextPart.get(pathPart);
113
+ });
114
+ return currentClassPartObject;
115
+ };
116
+ var isThemeGetter = (func) => func.isThemeGetter;
117
+ var getPrefixedClassGroupEntries = (classGroupEntries, prefix) => {
118
+ if (!prefix) {
119
+ return classGroupEntries;
120
+ }
121
+ return classGroupEntries.map(([classGroupId, classGroup]) => {
122
+ const prefixedClassGroup = classGroup.map((classDefinition) => {
123
+ if (typeof classDefinition === "string") {
124
+ return prefix + classDefinition;
125
+ }
126
+ if (typeof classDefinition === "object") {
127
+ return Object.fromEntries(Object.entries(classDefinition).map(([key, value]) => [prefix + key, value]));
128
+ }
129
+ return classDefinition;
130
+ });
131
+ return [classGroupId, prefixedClassGroup];
132
+ });
133
+ };
134
+ var createLruCache = (maxCacheSize) => {
135
+ if (maxCacheSize < 1) {
136
+ return {
137
+ get: () => void 0,
138
+ set: () => {
139
+ }
140
+ };
141
+ }
142
+ let cacheSize = 0;
143
+ let cache = /* @__PURE__ */ new Map();
144
+ let previousCache = /* @__PURE__ */ new Map();
145
+ const update = (key, value) => {
146
+ cache.set(key, value);
147
+ cacheSize++;
148
+ if (cacheSize > maxCacheSize) {
149
+ cacheSize = 0;
150
+ previousCache = cache;
151
+ cache = /* @__PURE__ */ new Map();
152
+ }
153
+ };
154
+ return {
155
+ get(key) {
156
+ let value = cache.get(key);
157
+ if (value !== void 0) {
158
+ return value;
159
+ }
160
+ if ((value = previousCache.get(key)) !== void 0) {
161
+ update(key, value);
162
+ return value;
163
+ }
164
+ },
165
+ set(key, value) {
166
+ if (cache.has(key)) {
167
+ cache.set(key, value);
168
+ } else {
169
+ update(key, value);
170
+ }
171
+ }
172
+ };
173
+ };
174
+ var IMPORTANT_MODIFIER = "!";
175
+ var createParseClassName = (config) => {
176
+ const {
177
+ separator,
178
+ experimentalParseClassName
179
+ } = config;
180
+ const isSeparatorSingleCharacter = separator.length === 1;
181
+ const firstSeparatorCharacter = separator[0];
182
+ const separatorLength = separator.length;
183
+ const parseClassName = (className) => {
184
+ const modifiers = [];
185
+ let bracketDepth = 0;
186
+ let modifierStart = 0;
187
+ let postfixModifierPosition;
188
+ for (let index = 0; index < className.length; index++) {
189
+ let currentCharacter = className[index];
190
+ if (bracketDepth === 0) {
191
+ if (currentCharacter === firstSeparatorCharacter && (isSeparatorSingleCharacter || className.slice(index, index + separatorLength) === separator)) {
192
+ modifiers.push(className.slice(modifierStart, index));
193
+ modifierStart = index + separatorLength;
194
+ continue;
195
+ }
196
+ if (currentCharacter === "/") {
197
+ postfixModifierPosition = index;
198
+ continue;
199
+ }
200
+ }
201
+ if (currentCharacter === "[") {
202
+ bracketDepth++;
203
+ } else if (currentCharacter === "]") {
204
+ bracketDepth--;
205
+ }
206
+ }
207
+ const baseClassNameWithImportantModifier = modifiers.length === 0 ? className : className.substring(modifierStart);
208
+ const hasImportantModifier = baseClassNameWithImportantModifier.startsWith(IMPORTANT_MODIFIER);
209
+ const baseClassName = hasImportantModifier ? baseClassNameWithImportantModifier.substring(1) : baseClassNameWithImportantModifier;
210
+ const maybePostfixModifierPosition = postfixModifierPosition && postfixModifierPosition > modifierStart ? postfixModifierPosition - modifierStart : void 0;
211
+ return {
212
+ modifiers,
213
+ hasImportantModifier,
214
+ baseClassName,
215
+ maybePostfixModifierPosition
216
+ };
217
+ };
218
+ if (experimentalParseClassName) {
219
+ return (className) => experimentalParseClassName({
220
+ className,
221
+ parseClassName
222
+ });
223
+ }
224
+ return parseClassName;
225
+ };
226
+ var sortModifiers = (modifiers) => {
227
+ if (modifiers.length <= 1) {
228
+ return modifiers;
229
+ }
230
+ const sortedModifiers = [];
231
+ let unsortedModifiers = [];
232
+ modifiers.forEach((modifier) => {
233
+ const isArbitraryVariant = modifier[0] === "[";
234
+ if (isArbitraryVariant) {
235
+ sortedModifiers.push(...unsortedModifiers.sort(), modifier);
236
+ unsortedModifiers = [];
237
+ } else {
238
+ unsortedModifiers.push(modifier);
239
+ }
240
+ });
241
+ sortedModifiers.push(...unsortedModifiers.sort());
242
+ return sortedModifiers;
243
+ };
244
+ var createConfigUtils = (config) => ({
245
+ cache: createLruCache(config.cacheSize),
246
+ parseClassName: createParseClassName(config),
247
+ ...createClassGroupUtils(config)
248
+ });
249
+ var SPLIT_CLASSES_REGEX = /\s+/;
250
+ var mergeClassList = (classList, configUtils) => {
251
+ const {
252
+ parseClassName,
253
+ getClassGroupId,
254
+ getConflictingClassGroupIds
255
+ } = configUtils;
256
+ const classGroupsInConflict = [];
257
+ const classNames = classList.trim().split(SPLIT_CLASSES_REGEX);
258
+ let result = "";
259
+ for (let index = classNames.length - 1; index >= 0; index -= 1) {
260
+ const originalClassName = classNames[index];
261
+ const {
262
+ modifiers,
263
+ hasImportantModifier,
264
+ baseClassName,
265
+ maybePostfixModifierPosition
266
+ } = parseClassName(originalClassName);
267
+ let hasPostfixModifier = Boolean(maybePostfixModifierPosition);
268
+ let classGroupId = getClassGroupId(hasPostfixModifier ? baseClassName.substring(0, maybePostfixModifierPosition) : baseClassName);
269
+ if (!classGroupId) {
270
+ if (!hasPostfixModifier) {
271
+ result = originalClassName + (result.length > 0 ? " " + result : result);
272
+ continue;
273
+ }
274
+ classGroupId = getClassGroupId(baseClassName);
275
+ if (!classGroupId) {
276
+ result = originalClassName + (result.length > 0 ? " " + result : result);
277
+ continue;
278
+ }
279
+ hasPostfixModifier = false;
280
+ }
281
+ const variantModifier = sortModifiers(modifiers).join(":");
282
+ const modifierId = hasImportantModifier ? variantModifier + IMPORTANT_MODIFIER : variantModifier;
283
+ const classId = modifierId + classGroupId;
284
+ if (classGroupsInConflict.includes(classId)) {
285
+ continue;
286
+ }
287
+ classGroupsInConflict.push(classId);
288
+ const conflictGroups = getConflictingClassGroupIds(classGroupId, hasPostfixModifier);
289
+ for (let i = 0; i < conflictGroups.length; ++i) {
290
+ const group = conflictGroups[i];
291
+ classGroupsInConflict.push(modifierId + group);
292
+ }
293
+ result = originalClassName + (result.length > 0 ? " " + result : result);
294
+ }
295
+ return result;
296
+ };
297
+ function twJoin() {
298
+ let index = 0;
299
+ let argument;
300
+ let resolvedValue;
301
+ let string = "";
302
+ while (index < arguments.length) {
303
+ if (argument = arguments[index++]) {
304
+ if (resolvedValue = toValue(argument)) {
305
+ string && (string += " ");
306
+ string += resolvedValue;
307
+ }
308
+ }
309
+ }
310
+ return string;
311
+ }
312
+ var toValue = (mix) => {
313
+ if (typeof mix === "string") {
314
+ return mix;
315
+ }
316
+ let resolvedValue;
317
+ let string = "";
318
+ for (let k = 0; k < mix.length; k++) {
319
+ if (mix[k]) {
320
+ if (resolvedValue = toValue(mix[k])) {
321
+ string && (string += " ");
322
+ string += resolvedValue;
323
+ }
324
+ }
325
+ }
326
+ return string;
327
+ };
328
+ function createTailwindMerge(createConfigFirst, ...createConfigRest) {
329
+ let configUtils;
330
+ let cacheGet;
331
+ let cacheSet;
332
+ let functionToCall = initTailwindMerge;
333
+ function initTailwindMerge(classList) {
334
+ const config = createConfigRest.reduce((previousConfig, createConfigCurrent) => createConfigCurrent(previousConfig), createConfigFirst());
335
+ configUtils = createConfigUtils(config);
336
+ cacheGet = configUtils.cache.get;
337
+ cacheSet = configUtils.cache.set;
338
+ functionToCall = tailwindMerge;
339
+ return tailwindMerge(classList);
340
+ }
341
+ function tailwindMerge(classList) {
342
+ const cachedResult = cacheGet(classList);
343
+ if (cachedResult) {
344
+ return cachedResult;
345
+ }
346
+ const result = mergeClassList(classList, configUtils);
347
+ cacheSet(classList, result);
348
+ return result;
349
+ }
350
+ return function callTailwindMerge() {
351
+ return functionToCall(twJoin.apply(null, arguments));
352
+ };
353
+ }
354
+ var fromTheme = (key) => {
355
+ const themeGetter = (theme) => theme[key] || [];
356
+ themeGetter.isThemeGetter = true;
357
+ return themeGetter;
358
+ };
359
+ var arbitraryValueRegex = /^\[(?:([a-z-]+):)?(.+)\]$/i;
360
+ var fractionRegex = /^\d+\/\d+$/;
361
+ var stringLengths = /* @__PURE__ */ new Set(["px", "full", "screen"]);
362
+ var tshirtUnitRegex = /^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/;
363
+ var lengthUnitRegex = /\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/;
364
+ var colorFunctionRegex = /^(rgba?|hsla?|hwb|(ok)?(lab|lch))\(.+\)$/;
365
+ var shadowRegex = /^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/;
366
+ var imageRegex = /^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/;
367
+ var isLength = (value) => isNumber(value) || stringLengths.has(value) || fractionRegex.test(value);
368
+ var isArbitraryLength = (value) => getIsArbitraryValue(value, "length", isLengthOnly);
369
+ var isNumber = (value) => Boolean(value) && !Number.isNaN(Number(value));
370
+ var isArbitraryNumber = (value) => getIsArbitraryValue(value, "number", isNumber);
371
+ var isInteger = (value) => Boolean(value) && Number.isInteger(Number(value));
372
+ var isPercent = (value) => value.endsWith("%") && isNumber(value.slice(0, -1));
373
+ var isArbitraryValue = (value) => arbitraryValueRegex.test(value);
374
+ var isTshirtSize = (value) => tshirtUnitRegex.test(value);
375
+ var sizeLabels = /* @__PURE__ */ new Set(["length", "size", "percentage"]);
376
+ var isArbitrarySize = (value) => getIsArbitraryValue(value, sizeLabels, isNever);
377
+ var isArbitraryPosition = (value) => getIsArbitraryValue(value, "position", isNever);
378
+ var imageLabels = /* @__PURE__ */ new Set(["image", "url"]);
379
+ var isArbitraryImage = (value) => getIsArbitraryValue(value, imageLabels, isImage);
380
+ var isArbitraryShadow = (value) => getIsArbitraryValue(value, "", isShadow);
381
+ var isAny = () => true;
382
+ var getIsArbitraryValue = (value, label, testValue) => {
383
+ const result = arbitraryValueRegex.exec(value);
384
+ if (result) {
385
+ if (result[1]) {
386
+ return typeof label === "string" ? result[1] === label : label.has(result[1]);
387
+ }
388
+ return testValue(result[2]);
389
+ }
390
+ return false;
391
+ };
392
+ var isLengthOnly = (value) => (
393
+ // `colorFunctionRegex` check is necessary because color functions can have percentages in them which which would be incorrectly classified as lengths.
394
+ // For example, `hsl(0 0% 0%)` would be classified as a length without this check.
395
+ // I could also use lookbehind assertion in `lengthUnitRegex` but that isn't supported widely enough.
396
+ lengthUnitRegex.test(value) && !colorFunctionRegex.test(value)
397
+ );
398
+ var isNever = () => false;
399
+ var isShadow = (value) => shadowRegex.test(value);
400
+ var isImage = (value) => imageRegex.test(value);
401
+ var getDefaultConfig = () => {
402
+ const colors = fromTheme("colors");
403
+ const spacing = fromTheme("spacing");
404
+ const blur = fromTheme("blur");
405
+ const brightness = fromTheme("brightness");
406
+ const borderColor = fromTheme("borderColor");
407
+ const borderRadius = fromTheme("borderRadius");
408
+ const borderSpacing = fromTheme("borderSpacing");
409
+ const borderWidth = fromTheme("borderWidth");
410
+ const contrast = fromTheme("contrast");
411
+ const grayscale = fromTheme("grayscale");
412
+ const hueRotate = fromTheme("hueRotate");
413
+ const invert = fromTheme("invert");
414
+ const gap = fromTheme("gap");
415
+ const gradientColorStops = fromTheme("gradientColorStops");
416
+ const gradientColorStopPositions = fromTheme("gradientColorStopPositions");
417
+ const inset = fromTheme("inset");
418
+ const margin = fromTheme("margin");
419
+ const opacity = fromTheme("opacity");
420
+ const padding = fromTheme("padding");
421
+ const saturate = fromTheme("saturate");
422
+ const scale = fromTheme("scale");
423
+ const sepia = fromTheme("sepia");
424
+ const skew = fromTheme("skew");
425
+ const space = fromTheme("space");
426
+ const translate = fromTheme("translate");
427
+ const getOverscroll = () => ["auto", "contain", "none"];
428
+ const getOverflow = () => ["auto", "hidden", "clip", "visible", "scroll"];
429
+ const getSpacingWithAutoAndArbitrary = () => ["auto", isArbitraryValue, spacing];
430
+ const getSpacingWithArbitrary = () => [isArbitraryValue, spacing];
431
+ const getLengthWithEmptyAndArbitrary = () => ["", isLength, isArbitraryLength];
432
+ const getNumberWithAutoAndArbitrary = () => ["auto", isNumber, isArbitraryValue];
433
+ const getPositions = () => ["bottom", "center", "left", "left-bottom", "left-top", "right", "right-bottom", "right-top", "top"];
434
+ const getLineStyles = () => ["solid", "dashed", "dotted", "double", "none"];
435
+ const getBlendModes = () => ["normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"];
436
+ const getAlign = () => ["start", "end", "center", "between", "around", "evenly", "stretch"];
437
+ const getZeroAndEmpty = () => ["", "0", isArbitraryValue];
438
+ const getBreaks = () => ["auto", "avoid", "all", "avoid-page", "page", "left", "right", "column"];
439
+ const getNumberAndArbitrary = () => [isNumber, isArbitraryValue];
440
+ return {
441
+ cacheSize: 500,
442
+ separator: ":",
443
+ theme: {
444
+ colors: [isAny],
445
+ spacing: [isLength, isArbitraryLength],
446
+ blur: ["none", "", isTshirtSize, isArbitraryValue],
447
+ brightness: getNumberAndArbitrary(),
448
+ borderColor: [colors],
449
+ borderRadius: ["none", "", "full", isTshirtSize, isArbitraryValue],
450
+ borderSpacing: getSpacingWithArbitrary(),
451
+ borderWidth: getLengthWithEmptyAndArbitrary(),
452
+ contrast: getNumberAndArbitrary(),
453
+ grayscale: getZeroAndEmpty(),
454
+ hueRotate: getNumberAndArbitrary(),
455
+ invert: getZeroAndEmpty(),
456
+ gap: getSpacingWithArbitrary(),
457
+ gradientColorStops: [colors],
458
+ gradientColorStopPositions: [isPercent, isArbitraryLength],
459
+ inset: getSpacingWithAutoAndArbitrary(),
460
+ margin: getSpacingWithAutoAndArbitrary(),
461
+ opacity: getNumberAndArbitrary(),
462
+ padding: getSpacingWithArbitrary(),
463
+ saturate: getNumberAndArbitrary(),
464
+ scale: getNumberAndArbitrary(),
465
+ sepia: getZeroAndEmpty(),
466
+ skew: getNumberAndArbitrary(),
467
+ space: getSpacingWithArbitrary(),
468
+ translate: getSpacingWithArbitrary()
469
+ },
470
+ classGroups: {
471
+ // Layout
472
+ /**
473
+ * Aspect Ratio
474
+ * @see https://tailwindcss.com/docs/aspect-ratio
475
+ */
476
+ aspect: [{
477
+ aspect: ["auto", "square", "video", isArbitraryValue]
478
+ }],
479
+ /**
480
+ * Container
481
+ * @see https://tailwindcss.com/docs/container
482
+ */
483
+ container: ["container"],
484
+ /**
485
+ * Columns
486
+ * @see https://tailwindcss.com/docs/columns
487
+ */
488
+ columns: [{
489
+ columns: [isTshirtSize]
490
+ }],
491
+ /**
492
+ * Break After
493
+ * @see https://tailwindcss.com/docs/break-after
494
+ */
495
+ "break-after": [{
496
+ "break-after": getBreaks()
497
+ }],
498
+ /**
499
+ * Break Before
500
+ * @see https://tailwindcss.com/docs/break-before
501
+ */
502
+ "break-before": [{
503
+ "break-before": getBreaks()
504
+ }],
505
+ /**
506
+ * Break Inside
507
+ * @see https://tailwindcss.com/docs/break-inside
508
+ */
509
+ "break-inside": [{
510
+ "break-inside": ["auto", "avoid", "avoid-page", "avoid-column"]
511
+ }],
512
+ /**
513
+ * Box Decoration Break
514
+ * @see https://tailwindcss.com/docs/box-decoration-break
515
+ */
516
+ "box-decoration": [{
517
+ "box-decoration": ["slice", "clone"]
518
+ }],
519
+ /**
520
+ * Box Sizing
521
+ * @see https://tailwindcss.com/docs/box-sizing
522
+ */
523
+ box: [{
524
+ box: ["border", "content"]
525
+ }],
526
+ /**
527
+ * Display
528
+ * @see https://tailwindcss.com/docs/display
529
+ */
530
+ display: ["block", "inline-block", "inline", "flex", "inline-flex", "table", "inline-table", "table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", "table-row-group", "table-row", "flow-root", "grid", "inline-grid", "contents", "list-item", "hidden"],
531
+ /**
532
+ * Floats
533
+ * @see https://tailwindcss.com/docs/float
534
+ */
535
+ float: [{
536
+ float: ["right", "left", "none", "start", "end"]
537
+ }],
538
+ /**
539
+ * Clear
540
+ * @see https://tailwindcss.com/docs/clear
541
+ */
542
+ clear: [{
543
+ clear: ["left", "right", "both", "none", "start", "end"]
544
+ }],
545
+ /**
546
+ * Isolation
547
+ * @see https://tailwindcss.com/docs/isolation
548
+ */
549
+ isolation: ["isolate", "isolation-auto"],
550
+ /**
551
+ * Object Fit
552
+ * @see https://tailwindcss.com/docs/object-fit
553
+ */
554
+ "object-fit": [{
555
+ object: ["contain", "cover", "fill", "none", "scale-down"]
556
+ }],
557
+ /**
558
+ * Object Position
559
+ * @see https://tailwindcss.com/docs/object-position
560
+ */
561
+ "object-position": [{
562
+ object: [...getPositions(), isArbitraryValue]
563
+ }],
564
+ /**
565
+ * Overflow
566
+ * @see https://tailwindcss.com/docs/overflow
567
+ */
568
+ overflow: [{
569
+ overflow: getOverflow()
570
+ }],
571
+ /**
572
+ * Overflow X
573
+ * @see https://tailwindcss.com/docs/overflow
574
+ */
575
+ "overflow-x": [{
576
+ "overflow-x": getOverflow()
577
+ }],
578
+ /**
579
+ * Overflow Y
580
+ * @see https://tailwindcss.com/docs/overflow
581
+ */
582
+ "overflow-y": [{
583
+ "overflow-y": getOverflow()
584
+ }],
585
+ /**
586
+ * Overscroll Behavior
587
+ * @see https://tailwindcss.com/docs/overscroll-behavior
588
+ */
589
+ overscroll: [{
590
+ overscroll: getOverscroll()
591
+ }],
592
+ /**
593
+ * Overscroll Behavior X
594
+ * @see https://tailwindcss.com/docs/overscroll-behavior
595
+ */
596
+ "overscroll-x": [{
597
+ "overscroll-x": getOverscroll()
598
+ }],
599
+ /**
600
+ * Overscroll Behavior Y
601
+ * @see https://tailwindcss.com/docs/overscroll-behavior
602
+ */
603
+ "overscroll-y": [{
604
+ "overscroll-y": getOverscroll()
605
+ }],
606
+ /**
607
+ * Position
608
+ * @see https://tailwindcss.com/docs/position
609
+ */
610
+ position: ["static", "fixed", "absolute", "relative", "sticky"],
611
+ /**
612
+ * Top / Right / Bottom / Left
613
+ * @see https://tailwindcss.com/docs/top-right-bottom-left
614
+ */
615
+ inset: [{
616
+ inset: [inset]
617
+ }],
618
+ /**
619
+ * Right / Left
620
+ * @see https://tailwindcss.com/docs/top-right-bottom-left
621
+ */
622
+ "inset-x": [{
623
+ "inset-x": [inset]
624
+ }],
625
+ /**
626
+ * Top / Bottom
627
+ * @see https://tailwindcss.com/docs/top-right-bottom-left
628
+ */
629
+ "inset-y": [{
630
+ "inset-y": [inset]
631
+ }],
632
+ /**
633
+ * Start
634
+ * @see https://tailwindcss.com/docs/top-right-bottom-left
635
+ */
636
+ start: [{
637
+ start: [inset]
638
+ }],
639
+ /**
640
+ * End
641
+ * @see https://tailwindcss.com/docs/top-right-bottom-left
642
+ */
643
+ end: [{
644
+ end: [inset]
645
+ }],
646
+ /**
647
+ * Top
648
+ * @see https://tailwindcss.com/docs/top-right-bottom-left
649
+ */
650
+ top: [{
651
+ top: [inset]
652
+ }],
653
+ /**
654
+ * Right
655
+ * @see https://tailwindcss.com/docs/top-right-bottom-left
656
+ */
657
+ right: [{
658
+ right: [inset]
659
+ }],
660
+ /**
661
+ * Bottom
662
+ * @see https://tailwindcss.com/docs/top-right-bottom-left
663
+ */
664
+ bottom: [{
665
+ bottom: [inset]
666
+ }],
667
+ /**
668
+ * Left
669
+ * @see https://tailwindcss.com/docs/top-right-bottom-left
670
+ */
671
+ left: [{
672
+ left: [inset]
673
+ }],
674
+ /**
675
+ * Visibility
676
+ * @see https://tailwindcss.com/docs/visibility
677
+ */
678
+ visibility: ["visible", "invisible", "collapse"],
679
+ /**
680
+ * Z-Index
681
+ * @see https://tailwindcss.com/docs/z-index
682
+ */
683
+ z: [{
684
+ z: ["auto", isInteger, isArbitraryValue]
685
+ }],
686
+ // Flexbox and Grid
687
+ /**
688
+ * Flex Basis
689
+ * @see https://tailwindcss.com/docs/flex-basis
690
+ */
691
+ basis: [{
692
+ basis: getSpacingWithAutoAndArbitrary()
693
+ }],
694
+ /**
695
+ * Flex Direction
696
+ * @see https://tailwindcss.com/docs/flex-direction
697
+ */
698
+ "flex-direction": [{
699
+ flex: ["row", "row-reverse", "col", "col-reverse"]
700
+ }],
701
+ /**
702
+ * Flex Wrap
703
+ * @see https://tailwindcss.com/docs/flex-wrap
704
+ */
705
+ "flex-wrap": [{
706
+ flex: ["wrap", "wrap-reverse", "nowrap"]
707
+ }],
708
+ /**
709
+ * Flex
710
+ * @see https://tailwindcss.com/docs/flex
711
+ */
712
+ flex: [{
713
+ flex: ["1", "auto", "initial", "none", isArbitraryValue]
714
+ }],
715
+ /**
716
+ * Flex Grow
717
+ * @see https://tailwindcss.com/docs/flex-grow
718
+ */
719
+ grow: [{
720
+ grow: getZeroAndEmpty()
721
+ }],
722
+ /**
723
+ * Flex Shrink
724
+ * @see https://tailwindcss.com/docs/flex-shrink
725
+ */
726
+ shrink: [{
727
+ shrink: getZeroAndEmpty()
728
+ }],
729
+ /**
730
+ * Order
731
+ * @see https://tailwindcss.com/docs/order
732
+ */
733
+ order: [{
734
+ order: ["first", "last", "none", isInteger, isArbitraryValue]
735
+ }],
736
+ /**
737
+ * Grid Template Columns
738
+ * @see https://tailwindcss.com/docs/grid-template-columns
739
+ */
740
+ "grid-cols": [{
741
+ "grid-cols": [isAny]
742
+ }],
743
+ /**
744
+ * Grid Column Start / End
745
+ * @see https://tailwindcss.com/docs/grid-column
746
+ */
747
+ "col-start-end": [{
748
+ col: ["auto", {
749
+ span: ["full", isInteger, isArbitraryValue]
750
+ }, isArbitraryValue]
751
+ }],
752
+ /**
753
+ * Grid Column Start
754
+ * @see https://tailwindcss.com/docs/grid-column
755
+ */
756
+ "col-start": [{
757
+ "col-start": getNumberWithAutoAndArbitrary()
758
+ }],
759
+ /**
760
+ * Grid Column End
761
+ * @see https://tailwindcss.com/docs/grid-column
762
+ */
763
+ "col-end": [{
764
+ "col-end": getNumberWithAutoAndArbitrary()
765
+ }],
766
+ /**
767
+ * Grid Template Rows
768
+ * @see https://tailwindcss.com/docs/grid-template-rows
769
+ */
770
+ "grid-rows": [{
771
+ "grid-rows": [isAny]
772
+ }],
773
+ /**
774
+ * Grid Row Start / End
775
+ * @see https://tailwindcss.com/docs/grid-row
776
+ */
777
+ "row-start-end": [{
778
+ row: ["auto", {
779
+ span: [isInteger, isArbitraryValue]
780
+ }, isArbitraryValue]
781
+ }],
782
+ /**
783
+ * Grid Row Start
784
+ * @see https://tailwindcss.com/docs/grid-row
785
+ */
786
+ "row-start": [{
787
+ "row-start": getNumberWithAutoAndArbitrary()
788
+ }],
789
+ /**
790
+ * Grid Row End
791
+ * @see https://tailwindcss.com/docs/grid-row
792
+ */
793
+ "row-end": [{
794
+ "row-end": getNumberWithAutoAndArbitrary()
795
+ }],
796
+ /**
797
+ * Grid Auto Flow
798
+ * @see https://tailwindcss.com/docs/grid-auto-flow
799
+ */
800
+ "grid-flow": [{
801
+ "grid-flow": ["row", "col", "dense", "row-dense", "col-dense"]
802
+ }],
803
+ /**
804
+ * Grid Auto Columns
805
+ * @see https://tailwindcss.com/docs/grid-auto-columns
806
+ */
807
+ "auto-cols": [{
808
+ "auto-cols": ["auto", "min", "max", "fr", isArbitraryValue]
809
+ }],
810
+ /**
811
+ * Grid Auto Rows
812
+ * @see https://tailwindcss.com/docs/grid-auto-rows
813
+ */
814
+ "auto-rows": [{
815
+ "auto-rows": ["auto", "min", "max", "fr", isArbitraryValue]
816
+ }],
817
+ /**
818
+ * Gap
819
+ * @see https://tailwindcss.com/docs/gap
820
+ */
821
+ gap: [{
822
+ gap: [gap]
823
+ }],
824
+ /**
825
+ * Gap X
826
+ * @see https://tailwindcss.com/docs/gap
827
+ */
828
+ "gap-x": [{
829
+ "gap-x": [gap]
830
+ }],
831
+ /**
832
+ * Gap Y
833
+ * @see https://tailwindcss.com/docs/gap
834
+ */
835
+ "gap-y": [{
836
+ "gap-y": [gap]
837
+ }],
838
+ /**
839
+ * Justify Content
840
+ * @see https://tailwindcss.com/docs/justify-content
841
+ */
842
+ "justify-content": [{
843
+ justify: ["normal", ...getAlign()]
844
+ }],
845
+ /**
846
+ * Justify Items
847
+ * @see https://tailwindcss.com/docs/justify-items
848
+ */
849
+ "justify-items": [{
850
+ "justify-items": ["start", "end", "center", "stretch"]
851
+ }],
852
+ /**
853
+ * Justify Self
854
+ * @see https://tailwindcss.com/docs/justify-self
855
+ */
856
+ "justify-self": [{
857
+ "justify-self": ["auto", "start", "end", "center", "stretch"]
858
+ }],
859
+ /**
860
+ * Align Content
861
+ * @see https://tailwindcss.com/docs/align-content
862
+ */
863
+ "align-content": [{
864
+ content: ["normal", ...getAlign(), "baseline"]
865
+ }],
866
+ /**
867
+ * Align Items
868
+ * @see https://tailwindcss.com/docs/align-items
869
+ */
870
+ "align-items": [{
871
+ items: ["start", "end", "center", "baseline", "stretch"]
872
+ }],
873
+ /**
874
+ * Align Self
875
+ * @see https://tailwindcss.com/docs/align-self
876
+ */
877
+ "align-self": [{
878
+ self: ["auto", "start", "end", "center", "stretch", "baseline"]
879
+ }],
880
+ /**
881
+ * Place Content
882
+ * @see https://tailwindcss.com/docs/place-content
883
+ */
884
+ "place-content": [{
885
+ "place-content": [...getAlign(), "baseline"]
886
+ }],
887
+ /**
888
+ * Place Items
889
+ * @see https://tailwindcss.com/docs/place-items
890
+ */
891
+ "place-items": [{
892
+ "place-items": ["start", "end", "center", "baseline", "stretch"]
893
+ }],
894
+ /**
895
+ * Place Self
896
+ * @see https://tailwindcss.com/docs/place-self
897
+ */
898
+ "place-self": [{
899
+ "place-self": ["auto", "start", "end", "center", "stretch"]
900
+ }],
901
+ // Spacing
902
+ /**
903
+ * Padding
904
+ * @see https://tailwindcss.com/docs/padding
905
+ */
906
+ p: [{
907
+ p: [padding]
908
+ }],
909
+ /**
910
+ * Padding X
911
+ * @see https://tailwindcss.com/docs/padding
912
+ */
913
+ px: [{
914
+ px: [padding]
915
+ }],
916
+ /**
917
+ * Padding Y
918
+ * @see https://tailwindcss.com/docs/padding
919
+ */
920
+ py: [{
921
+ py: [padding]
922
+ }],
923
+ /**
924
+ * Padding Start
925
+ * @see https://tailwindcss.com/docs/padding
926
+ */
927
+ ps: [{
928
+ ps: [padding]
929
+ }],
930
+ /**
931
+ * Padding End
932
+ * @see https://tailwindcss.com/docs/padding
933
+ */
934
+ pe: [{
935
+ pe: [padding]
936
+ }],
937
+ /**
938
+ * Padding Top
939
+ * @see https://tailwindcss.com/docs/padding
940
+ */
941
+ pt: [{
942
+ pt: [padding]
943
+ }],
944
+ /**
945
+ * Padding Right
946
+ * @see https://tailwindcss.com/docs/padding
947
+ */
948
+ pr: [{
949
+ pr: [padding]
950
+ }],
951
+ /**
952
+ * Padding Bottom
953
+ * @see https://tailwindcss.com/docs/padding
954
+ */
955
+ pb: [{
956
+ pb: [padding]
957
+ }],
958
+ /**
959
+ * Padding Left
960
+ * @see https://tailwindcss.com/docs/padding
961
+ */
962
+ pl: [{
963
+ pl: [padding]
964
+ }],
965
+ /**
966
+ * Margin
967
+ * @see https://tailwindcss.com/docs/margin
968
+ */
969
+ m: [{
970
+ m: [margin]
971
+ }],
972
+ /**
973
+ * Margin X
974
+ * @see https://tailwindcss.com/docs/margin
975
+ */
976
+ mx: [{
977
+ mx: [margin]
978
+ }],
979
+ /**
980
+ * Margin Y
981
+ * @see https://tailwindcss.com/docs/margin
982
+ */
983
+ my: [{
984
+ my: [margin]
985
+ }],
986
+ /**
987
+ * Margin Start
988
+ * @see https://tailwindcss.com/docs/margin
989
+ */
990
+ ms: [{
991
+ ms: [margin]
992
+ }],
993
+ /**
994
+ * Margin End
995
+ * @see https://tailwindcss.com/docs/margin
996
+ */
997
+ me: [{
998
+ me: [margin]
999
+ }],
1000
+ /**
1001
+ * Margin Top
1002
+ * @see https://tailwindcss.com/docs/margin
1003
+ */
1004
+ mt: [{
1005
+ mt: [margin]
1006
+ }],
1007
+ /**
1008
+ * Margin Right
1009
+ * @see https://tailwindcss.com/docs/margin
1010
+ */
1011
+ mr: [{
1012
+ mr: [margin]
1013
+ }],
1014
+ /**
1015
+ * Margin Bottom
1016
+ * @see https://tailwindcss.com/docs/margin
1017
+ */
1018
+ mb: [{
1019
+ mb: [margin]
1020
+ }],
1021
+ /**
1022
+ * Margin Left
1023
+ * @see https://tailwindcss.com/docs/margin
1024
+ */
1025
+ ml: [{
1026
+ ml: [margin]
1027
+ }],
1028
+ /**
1029
+ * Space Between X
1030
+ * @see https://tailwindcss.com/docs/space
1031
+ */
1032
+ "space-x": [{
1033
+ "space-x": [space]
1034
+ }],
1035
+ /**
1036
+ * Space Between X Reverse
1037
+ * @see https://tailwindcss.com/docs/space
1038
+ */
1039
+ "space-x-reverse": ["space-x-reverse"],
1040
+ /**
1041
+ * Space Between Y
1042
+ * @see https://tailwindcss.com/docs/space
1043
+ */
1044
+ "space-y": [{
1045
+ "space-y": [space]
1046
+ }],
1047
+ /**
1048
+ * Space Between Y Reverse
1049
+ * @see https://tailwindcss.com/docs/space
1050
+ */
1051
+ "space-y-reverse": ["space-y-reverse"],
1052
+ // Sizing
1053
+ /**
1054
+ * Width
1055
+ * @see https://tailwindcss.com/docs/width
1056
+ */
1057
+ w: [{
1058
+ w: ["auto", "min", "max", "fit", "svw", "lvw", "dvw", isArbitraryValue, spacing]
1059
+ }],
1060
+ /**
1061
+ * Min-Width
1062
+ * @see https://tailwindcss.com/docs/min-width
1063
+ */
1064
+ "min-w": [{
1065
+ "min-w": [isArbitraryValue, spacing, "min", "max", "fit"]
1066
+ }],
1067
+ /**
1068
+ * Max-Width
1069
+ * @see https://tailwindcss.com/docs/max-width
1070
+ */
1071
+ "max-w": [{
1072
+ "max-w": [isArbitraryValue, spacing, "none", "full", "min", "max", "fit", "prose", {
1073
+ screen: [isTshirtSize]
1074
+ }, isTshirtSize]
1075
+ }],
1076
+ /**
1077
+ * Height
1078
+ * @see https://tailwindcss.com/docs/height
1079
+ */
1080
+ h: [{
1081
+ h: [isArbitraryValue, spacing, "auto", "min", "max", "fit", "svh", "lvh", "dvh"]
1082
+ }],
1083
+ /**
1084
+ * Min-Height
1085
+ * @see https://tailwindcss.com/docs/min-height
1086
+ */
1087
+ "min-h": [{
1088
+ "min-h": [isArbitraryValue, spacing, "min", "max", "fit", "svh", "lvh", "dvh"]
1089
+ }],
1090
+ /**
1091
+ * Max-Height
1092
+ * @see https://tailwindcss.com/docs/max-height
1093
+ */
1094
+ "max-h": [{
1095
+ "max-h": [isArbitraryValue, spacing, "min", "max", "fit", "svh", "lvh", "dvh"]
1096
+ }],
1097
+ /**
1098
+ * Size
1099
+ * @see https://tailwindcss.com/docs/size
1100
+ */
1101
+ size: [{
1102
+ size: [isArbitraryValue, spacing, "auto", "min", "max", "fit"]
1103
+ }],
1104
+ // Typography
1105
+ /**
1106
+ * Font Size
1107
+ * @see https://tailwindcss.com/docs/font-size
1108
+ */
1109
+ "font-size": [{
1110
+ text: ["base", isTshirtSize, isArbitraryLength]
1111
+ }],
1112
+ /**
1113
+ * Font Smoothing
1114
+ * @see https://tailwindcss.com/docs/font-smoothing
1115
+ */
1116
+ "font-smoothing": ["antialiased", "subpixel-antialiased"],
1117
+ /**
1118
+ * Font Style
1119
+ * @see https://tailwindcss.com/docs/font-style
1120
+ */
1121
+ "font-style": ["italic", "not-italic"],
1122
+ /**
1123
+ * Font Weight
1124
+ * @see https://tailwindcss.com/docs/font-weight
1125
+ */
1126
+ "font-weight": [{
1127
+ font: ["thin", "extralight", "light", "normal", "medium", "semibold", "bold", "extrabold", "black", isArbitraryNumber]
1128
+ }],
1129
+ /**
1130
+ * Font Family
1131
+ * @see https://tailwindcss.com/docs/font-family
1132
+ */
1133
+ "font-family": [{
1134
+ font: [isAny]
1135
+ }],
1136
+ /**
1137
+ * Font Variant Numeric
1138
+ * @see https://tailwindcss.com/docs/font-variant-numeric
1139
+ */
1140
+ "fvn-normal": ["normal-nums"],
1141
+ /**
1142
+ * Font Variant Numeric
1143
+ * @see https://tailwindcss.com/docs/font-variant-numeric
1144
+ */
1145
+ "fvn-ordinal": ["ordinal"],
1146
+ /**
1147
+ * Font Variant Numeric
1148
+ * @see https://tailwindcss.com/docs/font-variant-numeric
1149
+ */
1150
+ "fvn-slashed-zero": ["slashed-zero"],
1151
+ /**
1152
+ * Font Variant Numeric
1153
+ * @see https://tailwindcss.com/docs/font-variant-numeric
1154
+ */
1155
+ "fvn-figure": ["lining-nums", "oldstyle-nums"],
1156
+ /**
1157
+ * Font Variant Numeric
1158
+ * @see https://tailwindcss.com/docs/font-variant-numeric
1159
+ */
1160
+ "fvn-spacing": ["proportional-nums", "tabular-nums"],
1161
+ /**
1162
+ * Font Variant Numeric
1163
+ * @see https://tailwindcss.com/docs/font-variant-numeric
1164
+ */
1165
+ "fvn-fraction": ["diagonal-fractions", "stacked-fractions"],
1166
+ /**
1167
+ * Letter Spacing
1168
+ * @see https://tailwindcss.com/docs/letter-spacing
1169
+ */
1170
+ tracking: [{
1171
+ tracking: ["tighter", "tight", "normal", "wide", "wider", "widest", isArbitraryValue]
1172
+ }],
1173
+ /**
1174
+ * Line Clamp
1175
+ * @see https://tailwindcss.com/docs/line-clamp
1176
+ */
1177
+ "line-clamp": [{
1178
+ "line-clamp": ["none", isNumber, isArbitraryNumber]
1179
+ }],
1180
+ /**
1181
+ * Line Height
1182
+ * @see https://tailwindcss.com/docs/line-height
1183
+ */
1184
+ leading: [{
1185
+ leading: ["none", "tight", "snug", "normal", "relaxed", "loose", isLength, isArbitraryValue]
1186
+ }],
1187
+ /**
1188
+ * List Style Image
1189
+ * @see https://tailwindcss.com/docs/list-style-image
1190
+ */
1191
+ "list-image": [{
1192
+ "list-image": ["none", isArbitraryValue]
1193
+ }],
1194
+ /**
1195
+ * List Style Type
1196
+ * @see https://tailwindcss.com/docs/list-style-type
1197
+ */
1198
+ "list-style-type": [{
1199
+ list: ["none", "disc", "decimal", isArbitraryValue]
1200
+ }],
1201
+ /**
1202
+ * List Style Position
1203
+ * @see https://tailwindcss.com/docs/list-style-position
1204
+ */
1205
+ "list-style-position": [{
1206
+ list: ["inside", "outside"]
1207
+ }],
1208
+ /**
1209
+ * Placeholder Color
1210
+ * @deprecated since Tailwind CSS v3.0.0
1211
+ * @see https://tailwindcss.com/docs/placeholder-color
1212
+ */
1213
+ "placeholder-color": [{
1214
+ placeholder: [colors]
1215
+ }],
1216
+ /**
1217
+ * Placeholder Opacity
1218
+ * @see https://tailwindcss.com/docs/placeholder-opacity
1219
+ */
1220
+ "placeholder-opacity": [{
1221
+ "placeholder-opacity": [opacity]
1222
+ }],
1223
+ /**
1224
+ * Text Alignment
1225
+ * @see https://tailwindcss.com/docs/text-align
1226
+ */
1227
+ "text-alignment": [{
1228
+ text: ["left", "center", "right", "justify", "start", "end"]
1229
+ }],
1230
+ /**
1231
+ * Text Color
1232
+ * @see https://tailwindcss.com/docs/text-color
1233
+ */
1234
+ "text-color": [{
1235
+ text: [colors]
1236
+ }],
1237
+ /**
1238
+ * Text Opacity
1239
+ * @see https://tailwindcss.com/docs/text-opacity
1240
+ */
1241
+ "text-opacity": [{
1242
+ "text-opacity": [opacity]
1243
+ }],
1244
+ /**
1245
+ * Text Decoration
1246
+ * @see https://tailwindcss.com/docs/text-decoration
1247
+ */
1248
+ "text-decoration": ["underline", "overline", "line-through", "no-underline"],
1249
+ /**
1250
+ * Text Decoration Style
1251
+ * @see https://tailwindcss.com/docs/text-decoration-style
1252
+ */
1253
+ "text-decoration-style": [{
1254
+ decoration: [...getLineStyles(), "wavy"]
1255
+ }],
1256
+ /**
1257
+ * Text Decoration Thickness
1258
+ * @see https://tailwindcss.com/docs/text-decoration-thickness
1259
+ */
1260
+ "text-decoration-thickness": [{
1261
+ decoration: ["auto", "from-font", isLength, isArbitraryLength]
1262
+ }],
1263
+ /**
1264
+ * Text Underline Offset
1265
+ * @see https://tailwindcss.com/docs/text-underline-offset
1266
+ */
1267
+ "underline-offset": [{
1268
+ "underline-offset": ["auto", isLength, isArbitraryValue]
1269
+ }],
1270
+ /**
1271
+ * Text Decoration Color
1272
+ * @see https://tailwindcss.com/docs/text-decoration-color
1273
+ */
1274
+ "text-decoration-color": [{
1275
+ decoration: [colors]
1276
+ }],
1277
+ /**
1278
+ * Text Transform
1279
+ * @see https://tailwindcss.com/docs/text-transform
1280
+ */
1281
+ "text-transform": ["uppercase", "lowercase", "capitalize", "normal-case"],
1282
+ /**
1283
+ * Text Overflow
1284
+ * @see https://tailwindcss.com/docs/text-overflow
1285
+ */
1286
+ "text-overflow": ["truncate", "text-ellipsis", "text-clip"],
1287
+ /**
1288
+ * Text Wrap
1289
+ * @see https://tailwindcss.com/docs/text-wrap
1290
+ */
1291
+ "text-wrap": [{
1292
+ text: ["wrap", "nowrap", "balance", "pretty"]
1293
+ }],
1294
+ /**
1295
+ * Text Indent
1296
+ * @see https://tailwindcss.com/docs/text-indent
1297
+ */
1298
+ indent: [{
1299
+ indent: getSpacingWithArbitrary()
1300
+ }],
1301
+ /**
1302
+ * Vertical Alignment
1303
+ * @see https://tailwindcss.com/docs/vertical-align
1304
+ */
1305
+ "vertical-align": [{
1306
+ align: ["baseline", "top", "middle", "bottom", "text-top", "text-bottom", "sub", "super", isArbitraryValue]
1307
+ }],
1308
+ /**
1309
+ * Whitespace
1310
+ * @see https://tailwindcss.com/docs/whitespace
1311
+ */
1312
+ whitespace: [{
1313
+ whitespace: ["normal", "nowrap", "pre", "pre-line", "pre-wrap", "break-spaces"]
1314
+ }],
1315
+ /**
1316
+ * Word Break
1317
+ * @see https://tailwindcss.com/docs/word-break
1318
+ */
1319
+ break: [{
1320
+ break: ["normal", "words", "all", "keep"]
1321
+ }],
1322
+ /**
1323
+ * Hyphens
1324
+ * @see https://tailwindcss.com/docs/hyphens
1325
+ */
1326
+ hyphens: [{
1327
+ hyphens: ["none", "manual", "auto"]
1328
+ }],
1329
+ /**
1330
+ * Content
1331
+ * @see https://tailwindcss.com/docs/content
1332
+ */
1333
+ content: [{
1334
+ content: ["none", isArbitraryValue]
1335
+ }],
1336
+ // Backgrounds
1337
+ /**
1338
+ * Background Attachment
1339
+ * @see https://tailwindcss.com/docs/background-attachment
1340
+ */
1341
+ "bg-attachment": [{
1342
+ bg: ["fixed", "local", "scroll"]
1343
+ }],
1344
+ /**
1345
+ * Background Clip
1346
+ * @see https://tailwindcss.com/docs/background-clip
1347
+ */
1348
+ "bg-clip": [{
1349
+ "bg-clip": ["border", "padding", "content", "text"]
1350
+ }],
1351
+ /**
1352
+ * Background Opacity
1353
+ * @deprecated since Tailwind CSS v3.0.0
1354
+ * @see https://tailwindcss.com/docs/background-opacity
1355
+ */
1356
+ "bg-opacity": [{
1357
+ "bg-opacity": [opacity]
1358
+ }],
1359
+ /**
1360
+ * Background Origin
1361
+ * @see https://tailwindcss.com/docs/background-origin
1362
+ */
1363
+ "bg-origin": [{
1364
+ "bg-origin": ["border", "padding", "content"]
1365
+ }],
1366
+ /**
1367
+ * Background Position
1368
+ * @see https://tailwindcss.com/docs/background-position
1369
+ */
1370
+ "bg-position": [{
1371
+ bg: [...getPositions(), isArbitraryPosition]
1372
+ }],
1373
+ /**
1374
+ * Background Repeat
1375
+ * @see https://tailwindcss.com/docs/background-repeat
1376
+ */
1377
+ "bg-repeat": [{
1378
+ bg: ["no-repeat", {
1379
+ repeat: ["", "x", "y", "round", "space"]
1380
+ }]
1381
+ }],
1382
+ /**
1383
+ * Background Size
1384
+ * @see https://tailwindcss.com/docs/background-size
1385
+ */
1386
+ "bg-size": [{
1387
+ bg: ["auto", "cover", "contain", isArbitrarySize]
1388
+ }],
1389
+ /**
1390
+ * Background Image
1391
+ * @see https://tailwindcss.com/docs/background-image
1392
+ */
1393
+ "bg-image": [{
1394
+ bg: ["none", {
1395
+ "gradient-to": ["t", "tr", "r", "br", "b", "bl", "l", "tl"]
1396
+ }, isArbitraryImage]
1397
+ }],
1398
+ /**
1399
+ * Background Color
1400
+ * @see https://tailwindcss.com/docs/background-color
1401
+ */
1402
+ "bg-color": [{
1403
+ bg: [colors]
1404
+ }],
1405
+ /**
1406
+ * Gradient Color Stops From Position
1407
+ * @see https://tailwindcss.com/docs/gradient-color-stops
1408
+ */
1409
+ "gradient-from-pos": [{
1410
+ from: [gradientColorStopPositions]
1411
+ }],
1412
+ /**
1413
+ * Gradient Color Stops Via Position
1414
+ * @see https://tailwindcss.com/docs/gradient-color-stops
1415
+ */
1416
+ "gradient-via-pos": [{
1417
+ via: [gradientColorStopPositions]
1418
+ }],
1419
+ /**
1420
+ * Gradient Color Stops To Position
1421
+ * @see https://tailwindcss.com/docs/gradient-color-stops
1422
+ */
1423
+ "gradient-to-pos": [{
1424
+ to: [gradientColorStopPositions]
1425
+ }],
1426
+ /**
1427
+ * Gradient Color Stops From
1428
+ * @see https://tailwindcss.com/docs/gradient-color-stops
1429
+ */
1430
+ "gradient-from": [{
1431
+ from: [gradientColorStops]
1432
+ }],
1433
+ /**
1434
+ * Gradient Color Stops Via
1435
+ * @see https://tailwindcss.com/docs/gradient-color-stops
1436
+ */
1437
+ "gradient-via": [{
1438
+ via: [gradientColorStops]
1439
+ }],
1440
+ /**
1441
+ * Gradient Color Stops To
1442
+ * @see https://tailwindcss.com/docs/gradient-color-stops
1443
+ */
1444
+ "gradient-to": [{
1445
+ to: [gradientColorStops]
1446
+ }],
1447
+ // Borders
1448
+ /**
1449
+ * Border Radius
1450
+ * @see https://tailwindcss.com/docs/border-radius
1451
+ */
1452
+ rounded: [{
1453
+ rounded: [borderRadius]
1454
+ }],
1455
+ /**
1456
+ * Border Radius Start
1457
+ * @see https://tailwindcss.com/docs/border-radius
1458
+ */
1459
+ "rounded-s": [{
1460
+ "rounded-s": [borderRadius]
1461
+ }],
1462
+ /**
1463
+ * Border Radius End
1464
+ * @see https://tailwindcss.com/docs/border-radius
1465
+ */
1466
+ "rounded-e": [{
1467
+ "rounded-e": [borderRadius]
1468
+ }],
1469
+ /**
1470
+ * Border Radius Top
1471
+ * @see https://tailwindcss.com/docs/border-radius
1472
+ */
1473
+ "rounded-t": [{
1474
+ "rounded-t": [borderRadius]
1475
+ }],
1476
+ /**
1477
+ * Border Radius Right
1478
+ * @see https://tailwindcss.com/docs/border-radius
1479
+ */
1480
+ "rounded-r": [{
1481
+ "rounded-r": [borderRadius]
1482
+ }],
1483
+ /**
1484
+ * Border Radius Bottom
1485
+ * @see https://tailwindcss.com/docs/border-radius
1486
+ */
1487
+ "rounded-b": [{
1488
+ "rounded-b": [borderRadius]
1489
+ }],
1490
+ /**
1491
+ * Border Radius Left
1492
+ * @see https://tailwindcss.com/docs/border-radius
1493
+ */
1494
+ "rounded-l": [{
1495
+ "rounded-l": [borderRadius]
1496
+ }],
1497
+ /**
1498
+ * Border Radius Start Start
1499
+ * @see https://tailwindcss.com/docs/border-radius
1500
+ */
1501
+ "rounded-ss": [{
1502
+ "rounded-ss": [borderRadius]
1503
+ }],
1504
+ /**
1505
+ * Border Radius Start End
1506
+ * @see https://tailwindcss.com/docs/border-radius
1507
+ */
1508
+ "rounded-se": [{
1509
+ "rounded-se": [borderRadius]
1510
+ }],
1511
+ /**
1512
+ * Border Radius End End
1513
+ * @see https://tailwindcss.com/docs/border-radius
1514
+ */
1515
+ "rounded-ee": [{
1516
+ "rounded-ee": [borderRadius]
1517
+ }],
1518
+ /**
1519
+ * Border Radius End Start
1520
+ * @see https://tailwindcss.com/docs/border-radius
1521
+ */
1522
+ "rounded-es": [{
1523
+ "rounded-es": [borderRadius]
1524
+ }],
1525
+ /**
1526
+ * Border Radius Top Left
1527
+ * @see https://tailwindcss.com/docs/border-radius
1528
+ */
1529
+ "rounded-tl": [{
1530
+ "rounded-tl": [borderRadius]
1531
+ }],
1532
+ /**
1533
+ * Border Radius Top Right
1534
+ * @see https://tailwindcss.com/docs/border-radius
1535
+ */
1536
+ "rounded-tr": [{
1537
+ "rounded-tr": [borderRadius]
1538
+ }],
1539
+ /**
1540
+ * Border Radius Bottom Right
1541
+ * @see https://tailwindcss.com/docs/border-radius
1542
+ */
1543
+ "rounded-br": [{
1544
+ "rounded-br": [borderRadius]
1545
+ }],
1546
+ /**
1547
+ * Border Radius Bottom Left
1548
+ * @see https://tailwindcss.com/docs/border-radius
1549
+ */
1550
+ "rounded-bl": [{
1551
+ "rounded-bl": [borderRadius]
1552
+ }],
1553
+ /**
1554
+ * Border Width
1555
+ * @see https://tailwindcss.com/docs/border-width
1556
+ */
1557
+ "border-w": [{
1558
+ border: [borderWidth]
1559
+ }],
1560
+ /**
1561
+ * Border Width X
1562
+ * @see https://tailwindcss.com/docs/border-width
1563
+ */
1564
+ "border-w-x": [{
1565
+ "border-x": [borderWidth]
1566
+ }],
1567
+ /**
1568
+ * Border Width Y
1569
+ * @see https://tailwindcss.com/docs/border-width
1570
+ */
1571
+ "border-w-y": [{
1572
+ "border-y": [borderWidth]
1573
+ }],
1574
+ /**
1575
+ * Border Width Start
1576
+ * @see https://tailwindcss.com/docs/border-width
1577
+ */
1578
+ "border-w-s": [{
1579
+ "border-s": [borderWidth]
1580
+ }],
1581
+ /**
1582
+ * Border Width End
1583
+ * @see https://tailwindcss.com/docs/border-width
1584
+ */
1585
+ "border-w-e": [{
1586
+ "border-e": [borderWidth]
1587
+ }],
1588
+ /**
1589
+ * Border Width Top
1590
+ * @see https://tailwindcss.com/docs/border-width
1591
+ */
1592
+ "border-w-t": [{
1593
+ "border-t": [borderWidth]
1594
+ }],
1595
+ /**
1596
+ * Border Width Right
1597
+ * @see https://tailwindcss.com/docs/border-width
1598
+ */
1599
+ "border-w-r": [{
1600
+ "border-r": [borderWidth]
1601
+ }],
1602
+ /**
1603
+ * Border Width Bottom
1604
+ * @see https://tailwindcss.com/docs/border-width
1605
+ */
1606
+ "border-w-b": [{
1607
+ "border-b": [borderWidth]
1608
+ }],
1609
+ /**
1610
+ * Border Width Left
1611
+ * @see https://tailwindcss.com/docs/border-width
1612
+ */
1613
+ "border-w-l": [{
1614
+ "border-l": [borderWidth]
1615
+ }],
1616
+ /**
1617
+ * Border Opacity
1618
+ * @see https://tailwindcss.com/docs/border-opacity
1619
+ */
1620
+ "border-opacity": [{
1621
+ "border-opacity": [opacity]
1622
+ }],
1623
+ /**
1624
+ * Border Style
1625
+ * @see https://tailwindcss.com/docs/border-style
1626
+ */
1627
+ "border-style": [{
1628
+ border: [...getLineStyles(), "hidden"]
1629
+ }],
1630
+ /**
1631
+ * Divide Width X
1632
+ * @see https://tailwindcss.com/docs/divide-width
1633
+ */
1634
+ "divide-x": [{
1635
+ "divide-x": [borderWidth]
1636
+ }],
1637
+ /**
1638
+ * Divide Width X Reverse
1639
+ * @see https://tailwindcss.com/docs/divide-width
1640
+ */
1641
+ "divide-x-reverse": ["divide-x-reverse"],
1642
+ /**
1643
+ * Divide Width Y
1644
+ * @see https://tailwindcss.com/docs/divide-width
1645
+ */
1646
+ "divide-y": [{
1647
+ "divide-y": [borderWidth]
1648
+ }],
1649
+ /**
1650
+ * Divide Width Y Reverse
1651
+ * @see https://tailwindcss.com/docs/divide-width
1652
+ */
1653
+ "divide-y-reverse": ["divide-y-reverse"],
1654
+ /**
1655
+ * Divide Opacity
1656
+ * @see https://tailwindcss.com/docs/divide-opacity
1657
+ */
1658
+ "divide-opacity": [{
1659
+ "divide-opacity": [opacity]
1660
+ }],
1661
+ /**
1662
+ * Divide Style
1663
+ * @see https://tailwindcss.com/docs/divide-style
1664
+ */
1665
+ "divide-style": [{
1666
+ divide: getLineStyles()
1667
+ }],
1668
+ /**
1669
+ * Border Color
1670
+ * @see https://tailwindcss.com/docs/border-color
1671
+ */
1672
+ "border-color": [{
1673
+ border: [borderColor]
1674
+ }],
1675
+ /**
1676
+ * Border Color X
1677
+ * @see https://tailwindcss.com/docs/border-color
1678
+ */
1679
+ "border-color-x": [{
1680
+ "border-x": [borderColor]
1681
+ }],
1682
+ /**
1683
+ * Border Color Y
1684
+ * @see https://tailwindcss.com/docs/border-color
1685
+ */
1686
+ "border-color-y": [{
1687
+ "border-y": [borderColor]
1688
+ }],
1689
+ /**
1690
+ * Border Color S
1691
+ * @see https://tailwindcss.com/docs/border-color
1692
+ */
1693
+ "border-color-s": [{
1694
+ "border-s": [borderColor]
1695
+ }],
1696
+ /**
1697
+ * Border Color E
1698
+ * @see https://tailwindcss.com/docs/border-color
1699
+ */
1700
+ "border-color-e": [{
1701
+ "border-e": [borderColor]
1702
+ }],
1703
+ /**
1704
+ * Border Color Top
1705
+ * @see https://tailwindcss.com/docs/border-color
1706
+ */
1707
+ "border-color-t": [{
1708
+ "border-t": [borderColor]
1709
+ }],
1710
+ /**
1711
+ * Border Color Right
1712
+ * @see https://tailwindcss.com/docs/border-color
1713
+ */
1714
+ "border-color-r": [{
1715
+ "border-r": [borderColor]
1716
+ }],
1717
+ /**
1718
+ * Border Color Bottom
1719
+ * @see https://tailwindcss.com/docs/border-color
1720
+ */
1721
+ "border-color-b": [{
1722
+ "border-b": [borderColor]
1723
+ }],
1724
+ /**
1725
+ * Border Color Left
1726
+ * @see https://tailwindcss.com/docs/border-color
1727
+ */
1728
+ "border-color-l": [{
1729
+ "border-l": [borderColor]
1730
+ }],
1731
+ /**
1732
+ * Divide Color
1733
+ * @see https://tailwindcss.com/docs/divide-color
1734
+ */
1735
+ "divide-color": [{
1736
+ divide: [borderColor]
1737
+ }],
1738
+ /**
1739
+ * Outline Style
1740
+ * @see https://tailwindcss.com/docs/outline-style
1741
+ */
1742
+ "outline-style": [{
1743
+ outline: ["", ...getLineStyles()]
1744
+ }],
1745
+ /**
1746
+ * Outline Offset
1747
+ * @see https://tailwindcss.com/docs/outline-offset
1748
+ */
1749
+ "outline-offset": [{
1750
+ "outline-offset": [isLength, isArbitraryValue]
1751
+ }],
1752
+ /**
1753
+ * Outline Width
1754
+ * @see https://tailwindcss.com/docs/outline-width
1755
+ */
1756
+ "outline-w": [{
1757
+ outline: [isLength, isArbitraryLength]
1758
+ }],
1759
+ /**
1760
+ * Outline Color
1761
+ * @see https://tailwindcss.com/docs/outline-color
1762
+ */
1763
+ "outline-color": [{
1764
+ outline: [colors]
1765
+ }],
1766
+ /**
1767
+ * Ring Width
1768
+ * @see https://tailwindcss.com/docs/ring-width
1769
+ */
1770
+ "ring-w": [{
1771
+ ring: getLengthWithEmptyAndArbitrary()
1772
+ }],
1773
+ /**
1774
+ * Ring Width Inset
1775
+ * @see https://tailwindcss.com/docs/ring-width
1776
+ */
1777
+ "ring-w-inset": ["ring-inset"],
1778
+ /**
1779
+ * Ring Color
1780
+ * @see https://tailwindcss.com/docs/ring-color
1781
+ */
1782
+ "ring-color": [{
1783
+ ring: [colors]
1784
+ }],
1785
+ /**
1786
+ * Ring Opacity
1787
+ * @see https://tailwindcss.com/docs/ring-opacity
1788
+ */
1789
+ "ring-opacity": [{
1790
+ "ring-opacity": [opacity]
1791
+ }],
1792
+ /**
1793
+ * Ring Offset Width
1794
+ * @see https://tailwindcss.com/docs/ring-offset-width
1795
+ */
1796
+ "ring-offset-w": [{
1797
+ "ring-offset": [isLength, isArbitraryLength]
1798
+ }],
1799
+ /**
1800
+ * Ring Offset Color
1801
+ * @see https://tailwindcss.com/docs/ring-offset-color
1802
+ */
1803
+ "ring-offset-color": [{
1804
+ "ring-offset": [colors]
1805
+ }],
1806
+ // Effects
1807
+ /**
1808
+ * Box Shadow
1809
+ * @see https://tailwindcss.com/docs/box-shadow
1810
+ */
1811
+ shadow: [{
1812
+ shadow: ["", "inner", "none", isTshirtSize, isArbitraryShadow]
1813
+ }],
1814
+ /**
1815
+ * Box Shadow Color
1816
+ * @see https://tailwindcss.com/docs/box-shadow-color
1817
+ */
1818
+ "shadow-color": [{
1819
+ shadow: [isAny]
1820
+ }],
1821
+ /**
1822
+ * Opacity
1823
+ * @see https://tailwindcss.com/docs/opacity
1824
+ */
1825
+ opacity: [{
1826
+ opacity: [opacity]
1827
+ }],
1828
+ /**
1829
+ * Mix Blend Mode
1830
+ * @see https://tailwindcss.com/docs/mix-blend-mode
1831
+ */
1832
+ "mix-blend": [{
1833
+ "mix-blend": [...getBlendModes(), "plus-lighter", "plus-darker"]
1834
+ }],
1835
+ /**
1836
+ * Background Blend Mode
1837
+ * @see https://tailwindcss.com/docs/background-blend-mode
1838
+ */
1839
+ "bg-blend": [{
1840
+ "bg-blend": getBlendModes()
1841
+ }],
1842
+ // Filters
1843
+ /**
1844
+ * Filter
1845
+ * @deprecated since Tailwind CSS v3.0.0
1846
+ * @see https://tailwindcss.com/docs/filter
1847
+ */
1848
+ filter: [{
1849
+ filter: ["", "none"]
1850
+ }],
1851
+ /**
1852
+ * Blur
1853
+ * @see https://tailwindcss.com/docs/blur
1854
+ */
1855
+ blur: [{
1856
+ blur: [blur]
1857
+ }],
1858
+ /**
1859
+ * Brightness
1860
+ * @see https://tailwindcss.com/docs/brightness
1861
+ */
1862
+ brightness: [{
1863
+ brightness: [brightness]
1864
+ }],
1865
+ /**
1866
+ * Contrast
1867
+ * @see https://tailwindcss.com/docs/contrast
1868
+ */
1869
+ contrast: [{
1870
+ contrast: [contrast]
1871
+ }],
1872
+ /**
1873
+ * Drop Shadow
1874
+ * @see https://tailwindcss.com/docs/drop-shadow
1875
+ */
1876
+ "drop-shadow": [{
1877
+ "drop-shadow": ["", "none", isTshirtSize, isArbitraryValue]
1878
+ }],
1879
+ /**
1880
+ * Grayscale
1881
+ * @see https://tailwindcss.com/docs/grayscale
1882
+ */
1883
+ grayscale: [{
1884
+ grayscale: [grayscale]
1885
+ }],
1886
+ /**
1887
+ * Hue Rotate
1888
+ * @see https://tailwindcss.com/docs/hue-rotate
1889
+ */
1890
+ "hue-rotate": [{
1891
+ "hue-rotate": [hueRotate]
1892
+ }],
1893
+ /**
1894
+ * Invert
1895
+ * @see https://tailwindcss.com/docs/invert
1896
+ */
1897
+ invert: [{
1898
+ invert: [invert]
1899
+ }],
1900
+ /**
1901
+ * Saturate
1902
+ * @see https://tailwindcss.com/docs/saturate
1903
+ */
1904
+ saturate: [{
1905
+ saturate: [saturate]
1906
+ }],
1907
+ /**
1908
+ * Sepia
1909
+ * @see https://tailwindcss.com/docs/sepia
1910
+ */
1911
+ sepia: [{
1912
+ sepia: [sepia]
1913
+ }],
1914
+ /**
1915
+ * Backdrop Filter
1916
+ * @deprecated since Tailwind CSS v3.0.0
1917
+ * @see https://tailwindcss.com/docs/backdrop-filter
1918
+ */
1919
+ "backdrop-filter": [{
1920
+ "backdrop-filter": ["", "none"]
1921
+ }],
1922
+ /**
1923
+ * Backdrop Blur
1924
+ * @see https://tailwindcss.com/docs/backdrop-blur
1925
+ */
1926
+ "backdrop-blur": [{
1927
+ "backdrop-blur": [blur]
1928
+ }],
1929
+ /**
1930
+ * Backdrop Brightness
1931
+ * @see https://tailwindcss.com/docs/backdrop-brightness
1932
+ */
1933
+ "backdrop-brightness": [{
1934
+ "backdrop-brightness": [brightness]
1935
+ }],
1936
+ /**
1937
+ * Backdrop Contrast
1938
+ * @see https://tailwindcss.com/docs/backdrop-contrast
1939
+ */
1940
+ "backdrop-contrast": [{
1941
+ "backdrop-contrast": [contrast]
1942
+ }],
1943
+ /**
1944
+ * Backdrop Grayscale
1945
+ * @see https://tailwindcss.com/docs/backdrop-grayscale
1946
+ */
1947
+ "backdrop-grayscale": [{
1948
+ "backdrop-grayscale": [grayscale]
1949
+ }],
1950
+ /**
1951
+ * Backdrop Hue Rotate
1952
+ * @see https://tailwindcss.com/docs/backdrop-hue-rotate
1953
+ */
1954
+ "backdrop-hue-rotate": [{
1955
+ "backdrop-hue-rotate": [hueRotate]
1956
+ }],
1957
+ /**
1958
+ * Backdrop Invert
1959
+ * @see https://tailwindcss.com/docs/backdrop-invert
1960
+ */
1961
+ "backdrop-invert": [{
1962
+ "backdrop-invert": [invert]
1963
+ }],
1964
+ /**
1965
+ * Backdrop Opacity
1966
+ * @see https://tailwindcss.com/docs/backdrop-opacity
1967
+ */
1968
+ "backdrop-opacity": [{
1969
+ "backdrop-opacity": [opacity]
1970
+ }],
1971
+ /**
1972
+ * Backdrop Saturate
1973
+ * @see https://tailwindcss.com/docs/backdrop-saturate
1974
+ */
1975
+ "backdrop-saturate": [{
1976
+ "backdrop-saturate": [saturate]
1977
+ }],
1978
+ /**
1979
+ * Backdrop Sepia
1980
+ * @see https://tailwindcss.com/docs/backdrop-sepia
1981
+ */
1982
+ "backdrop-sepia": [{
1983
+ "backdrop-sepia": [sepia]
1984
+ }],
1985
+ // Tables
1986
+ /**
1987
+ * Border Collapse
1988
+ * @see https://tailwindcss.com/docs/border-collapse
1989
+ */
1990
+ "border-collapse": [{
1991
+ border: ["collapse", "separate"]
1992
+ }],
1993
+ /**
1994
+ * Border Spacing
1995
+ * @see https://tailwindcss.com/docs/border-spacing
1996
+ */
1997
+ "border-spacing": [{
1998
+ "border-spacing": [borderSpacing]
1999
+ }],
2000
+ /**
2001
+ * Border Spacing X
2002
+ * @see https://tailwindcss.com/docs/border-spacing
2003
+ */
2004
+ "border-spacing-x": [{
2005
+ "border-spacing-x": [borderSpacing]
2006
+ }],
2007
+ /**
2008
+ * Border Spacing Y
2009
+ * @see https://tailwindcss.com/docs/border-spacing
2010
+ */
2011
+ "border-spacing-y": [{
2012
+ "border-spacing-y": [borderSpacing]
2013
+ }],
2014
+ /**
2015
+ * Table Layout
2016
+ * @see https://tailwindcss.com/docs/table-layout
2017
+ */
2018
+ "table-layout": [{
2019
+ table: ["auto", "fixed"]
2020
+ }],
2021
+ /**
2022
+ * Caption Side
2023
+ * @see https://tailwindcss.com/docs/caption-side
2024
+ */
2025
+ caption: [{
2026
+ caption: ["top", "bottom"]
2027
+ }],
2028
+ // Transitions and Animation
2029
+ /**
2030
+ * Tranisition Property
2031
+ * @see https://tailwindcss.com/docs/transition-property
2032
+ */
2033
+ transition: [{
2034
+ transition: ["none", "all", "", "colors", "opacity", "shadow", "transform", isArbitraryValue]
2035
+ }],
2036
+ /**
2037
+ * Transition Duration
2038
+ * @see https://tailwindcss.com/docs/transition-duration
2039
+ */
2040
+ duration: [{
2041
+ duration: getNumberAndArbitrary()
2042
+ }],
2043
+ /**
2044
+ * Transition Timing Function
2045
+ * @see https://tailwindcss.com/docs/transition-timing-function
2046
+ */
2047
+ ease: [{
2048
+ ease: ["linear", "in", "out", "in-out", isArbitraryValue]
2049
+ }],
2050
+ /**
2051
+ * Transition Delay
2052
+ * @see https://tailwindcss.com/docs/transition-delay
2053
+ */
2054
+ delay: [{
2055
+ delay: getNumberAndArbitrary()
2056
+ }],
2057
+ /**
2058
+ * Animation
2059
+ * @see https://tailwindcss.com/docs/animation
2060
+ */
2061
+ animate: [{
2062
+ animate: ["none", "spin", "ping", "pulse", "bounce", isArbitraryValue]
2063
+ }],
2064
+ // Transforms
2065
+ /**
2066
+ * Transform
2067
+ * @see https://tailwindcss.com/docs/transform
2068
+ */
2069
+ transform: [{
2070
+ transform: ["", "gpu", "none"]
2071
+ }],
2072
+ /**
2073
+ * Scale
2074
+ * @see https://tailwindcss.com/docs/scale
2075
+ */
2076
+ scale: [{
2077
+ scale: [scale]
2078
+ }],
2079
+ /**
2080
+ * Scale X
2081
+ * @see https://tailwindcss.com/docs/scale
2082
+ */
2083
+ "scale-x": [{
2084
+ "scale-x": [scale]
2085
+ }],
2086
+ /**
2087
+ * Scale Y
2088
+ * @see https://tailwindcss.com/docs/scale
2089
+ */
2090
+ "scale-y": [{
2091
+ "scale-y": [scale]
2092
+ }],
2093
+ /**
2094
+ * Rotate
2095
+ * @see https://tailwindcss.com/docs/rotate
2096
+ */
2097
+ rotate: [{
2098
+ rotate: [isInteger, isArbitraryValue]
2099
+ }],
2100
+ /**
2101
+ * Translate X
2102
+ * @see https://tailwindcss.com/docs/translate
2103
+ */
2104
+ "translate-x": [{
2105
+ "translate-x": [translate]
2106
+ }],
2107
+ /**
2108
+ * Translate Y
2109
+ * @see https://tailwindcss.com/docs/translate
2110
+ */
2111
+ "translate-y": [{
2112
+ "translate-y": [translate]
2113
+ }],
2114
+ /**
2115
+ * Skew X
2116
+ * @see https://tailwindcss.com/docs/skew
2117
+ */
2118
+ "skew-x": [{
2119
+ "skew-x": [skew]
2120
+ }],
2121
+ /**
2122
+ * Skew Y
2123
+ * @see https://tailwindcss.com/docs/skew
2124
+ */
2125
+ "skew-y": [{
2126
+ "skew-y": [skew]
2127
+ }],
2128
+ /**
2129
+ * Transform Origin
2130
+ * @see https://tailwindcss.com/docs/transform-origin
2131
+ */
2132
+ "transform-origin": [{
2133
+ origin: ["center", "top", "top-right", "right", "bottom-right", "bottom", "bottom-left", "left", "top-left", isArbitraryValue]
2134
+ }],
2135
+ // Interactivity
2136
+ /**
2137
+ * Accent Color
2138
+ * @see https://tailwindcss.com/docs/accent-color
2139
+ */
2140
+ accent: [{
2141
+ accent: ["auto", colors]
2142
+ }],
2143
+ /**
2144
+ * Appearance
2145
+ * @see https://tailwindcss.com/docs/appearance
2146
+ */
2147
+ appearance: [{
2148
+ appearance: ["none", "auto"]
2149
+ }],
2150
+ /**
2151
+ * Cursor
2152
+ * @see https://tailwindcss.com/docs/cursor
2153
+ */
2154
+ cursor: [{
2155
+ cursor: ["auto", "default", "pointer", "wait", "text", "move", "help", "not-allowed", "none", "context-menu", "progress", "cell", "crosshair", "vertical-text", "alias", "copy", "no-drop", "grab", "grabbing", "all-scroll", "col-resize", "row-resize", "n-resize", "e-resize", "s-resize", "w-resize", "ne-resize", "nw-resize", "se-resize", "sw-resize", "ew-resize", "ns-resize", "nesw-resize", "nwse-resize", "zoom-in", "zoom-out", isArbitraryValue]
2156
+ }],
2157
+ /**
2158
+ * Caret Color
2159
+ * @see https://tailwindcss.com/docs/just-in-time-mode#caret-color-utilities
2160
+ */
2161
+ "caret-color": [{
2162
+ caret: [colors]
2163
+ }],
2164
+ /**
2165
+ * Pointer Events
2166
+ * @see https://tailwindcss.com/docs/pointer-events
2167
+ */
2168
+ "pointer-events": [{
2169
+ "pointer-events": ["none", "auto"]
2170
+ }],
2171
+ /**
2172
+ * Resize
2173
+ * @see https://tailwindcss.com/docs/resize
2174
+ */
2175
+ resize: [{
2176
+ resize: ["none", "y", "x", ""]
2177
+ }],
2178
+ /**
2179
+ * Scroll Behavior
2180
+ * @see https://tailwindcss.com/docs/scroll-behavior
2181
+ */
2182
+ "scroll-behavior": [{
2183
+ scroll: ["auto", "smooth"]
2184
+ }],
2185
+ /**
2186
+ * Scroll Margin
2187
+ * @see https://tailwindcss.com/docs/scroll-margin
2188
+ */
2189
+ "scroll-m": [{
2190
+ "scroll-m": getSpacingWithArbitrary()
2191
+ }],
2192
+ /**
2193
+ * Scroll Margin X
2194
+ * @see https://tailwindcss.com/docs/scroll-margin
2195
+ */
2196
+ "scroll-mx": [{
2197
+ "scroll-mx": getSpacingWithArbitrary()
2198
+ }],
2199
+ /**
2200
+ * Scroll Margin Y
2201
+ * @see https://tailwindcss.com/docs/scroll-margin
2202
+ */
2203
+ "scroll-my": [{
2204
+ "scroll-my": getSpacingWithArbitrary()
2205
+ }],
2206
+ /**
2207
+ * Scroll Margin Start
2208
+ * @see https://tailwindcss.com/docs/scroll-margin
2209
+ */
2210
+ "scroll-ms": [{
2211
+ "scroll-ms": getSpacingWithArbitrary()
2212
+ }],
2213
+ /**
2214
+ * Scroll Margin End
2215
+ * @see https://tailwindcss.com/docs/scroll-margin
2216
+ */
2217
+ "scroll-me": [{
2218
+ "scroll-me": getSpacingWithArbitrary()
2219
+ }],
2220
+ /**
2221
+ * Scroll Margin Top
2222
+ * @see https://tailwindcss.com/docs/scroll-margin
2223
+ */
2224
+ "scroll-mt": [{
2225
+ "scroll-mt": getSpacingWithArbitrary()
2226
+ }],
2227
+ /**
2228
+ * Scroll Margin Right
2229
+ * @see https://tailwindcss.com/docs/scroll-margin
2230
+ */
2231
+ "scroll-mr": [{
2232
+ "scroll-mr": getSpacingWithArbitrary()
2233
+ }],
2234
+ /**
2235
+ * Scroll Margin Bottom
2236
+ * @see https://tailwindcss.com/docs/scroll-margin
2237
+ */
2238
+ "scroll-mb": [{
2239
+ "scroll-mb": getSpacingWithArbitrary()
2240
+ }],
2241
+ /**
2242
+ * Scroll Margin Left
2243
+ * @see https://tailwindcss.com/docs/scroll-margin
2244
+ */
2245
+ "scroll-ml": [{
2246
+ "scroll-ml": getSpacingWithArbitrary()
2247
+ }],
2248
+ /**
2249
+ * Scroll Padding
2250
+ * @see https://tailwindcss.com/docs/scroll-padding
2251
+ */
2252
+ "scroll-p": [{
2253
+ "scroll-p": getSpacingWithArbitrary()
2254
+ }],
2255
+ /**
2256
+ * Scroll Padding X
2257
+ * @see https://tailwindcss.com/docs/scroll-padding
2258
+ */
2259
+ "scroll-px": [{
2260
+ "scroll-px": getSpacingWithArbitrary()
2261
+ }],
2262
+ /**
2263
+ * Scroll Padding Y
2264
+ * @see https://tailwindcss.com/docs/scroll-padding
2265
+ */
2266
+ "scroll-py": [{
2267
+ "scroll-py": getSpacingWithArbitrary()
2268
+ }],
2269
+ /**
2270
+ * Scroll Padding Start
2271
+ * @see https://tailwindcss.com/docs/scroll-padding
2272
+ */
2273
+ "scroll-ps": [{
2274
+ "scroll-ps": getSpacingWithArbitrary()
2275
+ }],
2276
+ /**
2277
+ * Scroll Padding End
2278
+ * @see https://tailwindcss.com/docs/scroll-padding
2279
+ */
2280
+ "scroll-pe": [{
2281
+ "scroll-pe": getSpacingWithArbitrary()
2282
+ }],
2283
+ /**
2284
+ * Scroll Padding Top
2285
+ * @see https://tailwindcss.com/docs/scroll-padding
2286
+ */
2287
+ "scroll-pt": [{
2288
+ "scroll-pt": getSpacingWithArbitrary()
2289
+ }],
2290
+ /**
2291
+ * Scroll Padding Right
2292
+ * @see https://tailwindcss.com/docs/scroll-padding
2293
+ */
2294
+ "scroll-pr": [{
2295
+ "scroll-pr": getSpacingWithArbitrary()
2296
+ }],
2297
+ /**
2298
+ * Scroll Padding Bottom
2299
+ * @see https://tailwindcss.com/docs/scroll-padding
2300
+ */
2301
+ "scroll-pb": [{
2302
+ "scroll-pb": getSpacingWithArbitrary()
2303
+ }],
2304
+ /**
2305
+ * Scroll Padding Left
2306
+ * @see https://tailwindcss.com/docs/scroll-padding
2307
+ */
2308
+ "scroll-pl": [{
2309
+ "scroll-pl": getSpacingWithArbitrary()
2310
+ }],
2311
+ /**
2312
+ * Scroll Snap Align
2313
+ * @see https://tailwindcss.com/docs/scroll-snap-align
2314
+ */
2315
+ "snap-align": [{
2316
+ snap: ["start", "end", "center", "align-none"]
2317
+ }],
2318
+ /**
2319
+ * Scroll Snap Stop
2320
+ * @see https://tailwindcss.com/docs/scroll-snap-stop
2321
+ */
2322
+ "snap-stop": [{
2323
+ snap: ["normal", "always"]
2324
+ }],
2325
+ /**
2326
+ * Scroll Snap Type
2327
+ * @see https://tailwindcss.com/docs/scroll-snap-type
2328
+ */
2329
+ "snap-type": [{
2330
+ snap: ["none", "x", "y", "both"]
2331
+ }],
2332
+ /**
2333
+ * Scroll Snap Type Strictness
2334
+ * @see https://tailwindcss.com/docs/scroll-snap-type
2335
+ */
2336
+ "snap-strictness": [{
2337
+ snap: ["mandatory", "proximity"]
2338
+ }],
2339
+ /**
2340
+ * Touch Action
2341
+ * @see https://tailwindcss.com/docs/touch-action
2342
+ */
2343
+ touch: [{
2344
+ touch: ["auto", "none", "manipulation"]
2345
+ }],
2346
+ /**
2347
+ * Touch Action X
2348
+ * @see https://tailwindcss.com/docs/touch-action
2349
+ */
2350
+ "touch-x": [{
2351
+ "touch-pan": ["x", "left", "right"]
2352
+ }],
2353
+ /**
2354
+ * Touch Action Y
2355
+ * @see https://tailwindcss.com/docs/touch-action
2356
+ */
2357
+ "touch-y": [{
2358
+ "touch-pan": ["y", "up", "down"]
2359
+ }],
2360
+ /**
2361
+ * Touch Action Pinch Zoom
2362
+ * @see https://tailwindcss.com/docs/touch-action
2363
+ */
2364
+ "touch-pz": ["touch-pinch-zoom"],
2365
+ /**
2366
+ * User Select
2367
+ * @see https://tailwindcss.com/docs/user-select
2368
+ */
2369
+ select: [{
2370
+ select: ["none", "text", "all", "auto"]
2371
+ }],
2372
+ /**
2373
+ * Will Change
2374
+ * @see https://tailwindcss.com/docs/will-change
2375
+ */
2376
+ "will-change": [{
2377
+ "will-change": ["auto", "scroll", "contents", "transform", isArbitraryValue]
2378
+ }],
2379
+ // SVG
2380
+ /**
2381
+ * Fill
2382
+ * @see https://tailwindcss.com/docs/fill
2383
+ */
2384
+ fill: [{
2385
+ fill: [colors, "none"]
2386
+ }],
2387
+ /**
2388
+ * Stroke Width
2389
+ * @see https://tailwindcss.com/docs/stroke-width
2390
+ */
2391
+ "stroke-w": [{
2392
+ stroke: [isLength, isArbitraryLength, isArbitraryNumber]
2393
+ }],
2394
+ /**
2395
+ * Stroke
2396
+ * @see https://tailwindcss.com/docs/stroke
2397
+ */
2398
+ stroke: [{
2399
+ stroke: [colors, "none"]
2400
+ }],
2401
+ // Accessibility
2402
+ /**
2403
+ * Screen Readers
2404
+ * @see https://tailwindcss.com/docs/screen-readers
2405
+ */
2406
+ sr: ["sr-only", "not-sr-only"],
2407
+ /**
2408
+ * Forced Color Adjust
2409
+ * @see https://tailwindcss.com/docs/forced-color-adjust
2410
+ */
2411
+ "forced-color-adjust": [{
2412
+ "forced-color-adjust": ["auto", "none"]
2413
+ }]
2414
+ },
2415
+ conflictingClassGroups: {
2416
+ overflow: ["overflow-x", "overflow-y"],
2417
+ overscroll: ["overscroll-x", "overscroll-y"],
2418
+ inset: ["inset-x", "inset-y", "start", "end", "top", "right", "bottom", "left"],
2419
+ "inset-x": ["right", "left"],
2420
+ "inset-y": ["top", "bottom"],
2421
+ flex: ["basis", "grow", "shrink"],
2422
+ gap: ["gap-x", "gap-y"],
2423
+ p: ["px", "py", "ps", "pe", "pt", "pr", "pb", "pl"],
2424
+ px: ["pr", "pl"],
2425
+ py: ["pt", "pb"],
2426
+ m: ["mx", "my", "ms", "me", "mt", "mr", "mb", "ml"],
2427
+ mx: ["mr", "ml"],
2428
+ my: ["mt", "mb"],
2429
+ size: ["w", "h"],
2430
+ "font-size": ["leading"],
2431
+ "fvn-normal": ["fvn-ordinal", "fvn-slashed-zero", "fvn-figure", "fvn-spacing", "fvn-fraction"],
2432
+ "fvn-ordinal": ["fvn-normal"],
2433
+ "fvn-slashed-zero": ["fvn-normal"],
2434
+ "fvn-figure": ["fvn-normal"],
2435
+ "fvn-spacing": ["fvn-normal"],
2436
+ "fvn-fraction": ["fvn-normal"],
2437
+ "line-clamp": ["display", "overflow"],
2438
+ rounded: ["rounded-s", "rounded-e", "rounded-t", "rounded-r", "rounded-b", "rounded-l", "rounded-ss", "rounded-se", "rounded-ee", "rounded-es", "rounded-tl", "rounded-tr", "rounded-br", "rounded-bl"],
2439
+ "rounded-s": ["rounded-ss", "rounded-es"],
2440
+ "rounded-e": ["rounded-se", "rounded-ee"],
2441
+ "rounded-t": ["rounded-tl", "rounded-tr"],
2442
+ "rounded-r": ["rounded-tr", "rounded-br"],
2443
+ "rounded-b": ["rounded-br", "rounded-bl"],
2444
+ "rounded-l": ["rounded-tl", "rounded-bl"],
2445
+ "border-spacing": ["border-spacing-x", "border-spacing-y"],
2446
+ "border-w": ["border-w-s", "border-w-e", "border-w-t", "border-w-r", "border-w-b", "border-w-l"],
2447
+ "border-w-x": ["border-w-r", "border-w-l"],
2448
+ "border-w-y": ["border-w-t", "border-w-b"],
2449
+ "border-color": ["border-color-s", "border-color-e", "border-color-t", "border-color-r", "border-color-b", "border-color-l"],
2450
+ "border-color-x": ["border-color-r", "border-color-l"],
2451
+ "border-color-y": ["border-color-t", "border-color-b"],
2452
+ "scroll-m": ["scroll-mx", "scroll-my", "scroll-ms", "scroll-me", "scroll-mt", "scroll-mr", "scroll-mb", "scroll-ml"],
2453
+ "scroll-mx": ["scroll-mr", "scroll-ml"],
2454
+ "scroll-my": ["scroll-mt", "scroll-mb"],
2455
+ "scroll-p": ["scroll-px", "scroll-py", "scroll-ps", "scroll-pe", "scroll-pt", "scroll-pr", "scroll-pb", "scroll-pl"],
2456
+ "scroll-px": ["scroll-pr", "scroll-pl"],
2457
+ "scroll-py": ["scroll-pt", "scroll-pb"],
2458
+ touch: ["touch-x", "touch-y", "touch-pz"],
2459
+ "touch-x": ["touch"],
2460
+ "touch-y": ["touch"],
2461
+ "touch-pz": ["touch"]
2462
+ },
2463
+ conflictingClassGroupModifiers: {
2464
+ "font-size": ["leading"]
2465
+ }
2466
+ };
2467
+ };
2468
+ var twMerge = /* @__PURE__ */ createTailwindMerge(getDefaultConfig);
2469
+
2470
+ // src/lib/utils.ts
2471
+ function cn(...inputs) {
2472
+ return twMerge(clsx(inputs));
2473
+ }
2474
+
2475
+ // src/components/ui/button.tsx
2476
+ import { jsx } from "react/jsx-runtime";
2477
+ var Button = React.forwardRef(
2478
+ ({ className, variant = "default", size = "default", ...props }, ref) => {
2479
+ return /* @__PURE__ */ jsx(
2480
+ "button",
2481
+ {
2482
+ className: cn(
2483
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
2484
+ {
2485
+ "bg-primary text-primary-foreground hover:bg-primary/90": variant === "default",
2486
+ "bg-destructive text-destructive-foreground hover:bg-destructive/90": variant === "destructive",
2487
+ "border border-input bg-background hover:bg-accent hover:text-accent-foreground": variant === "outline",
2488
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80": variant === "secondary",
2489
+ "hover:bg-accent hover:text-accent-foreground": variant === "ghost",
2490
+ "text-primary underline-offset-4 hover:underline": variant === "link"
2491
+ },
2492
+ {
2493
+ "h-10 px-4 py-2": size === "default",
2494
+ "h-9 rounded-md px-3": size === "sm",
2495
+ "h-11 rounded-md px-8": size === "lg",
2496
+ "h-10 w-10": size === "icon"
2497
+ },
2498
+ className
2499
+ ),
2500
+ ref,
2501
+ ...props
2502
+ }
2503
+ );
2504
+ }
2505
+ );
2506
+ Button.displayName = "Button";
2507
+
2508
+ // src/components/ui/card.tsx
2509
+ import * as React2 from "react";
2510
+ import { jsx as jsx2 } from "react/jsx-runtime";
2511
+ var Card = React2.forwardRef(
2512
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx2(
2513
+ "div",
2514
+ {
2515
+ ref,
2516
+ className: cn(
2517
+ "rounded-lg border bg-card text-card-foreground shadow-sm",
2518
+ className
2519
+ ),
2520
+ ...props
2521
+ }
2522
+ )
2523
+ );
2524
+ Card.displayName = "Card";
2525
+ var CardHeader = React2.forwardRef(
2526
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx2("div", { ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })
2527
+ );
2528
+ CardHeader.displayName = "CardHeader";
2529
+ var CardTitle = React2.forwardRef(
2530
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx2("h3", { ref, className: cn("text-2xl font-semibold leading-none tracking-tight", className), ...props })
2531
+ );
2532
+ CardTitle.displayName = "CardTitle";
2533
+ var CardDescription = React2.forwardRef(
2534
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx2("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props })
2535
+ );
2536
+ CardDescription.displayName = "CardDescription";
2537
+ var CardContent = React2.forwardRef(
2538
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx2("div", { ref, className: cn("p-6 pt-0", className), ...props })
2539
+ );
2540
+ CardContent.displayName = "CardContent";
2541
+ var CardFooter = React2.forwardRef(
2542
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx2("div", { ref, className: cn("flex items-center p-6 pt-0", className), ...props })
2543
+ );
2544
+ CardFooter.displayName = "CardFooter";
2545
+
2546
+ // src/components/seo/SEORecordForm.tsx
2547
+ import { useState as useState2 } from "react";
2548
+ import { useForm } from "react-hook-form";
2549
+ import { zodResolver } from "@hookform/resolvers/zod";
2550
+
2551
+ // src/lib/validation/seo-schema.ts
2552
+ import { z } from "zod";
2553
+ var ogTypeSchema = z.enum([
2554
+ "website",
2555
+ "article",
2556
+ "product",
2557
+ "book",
2558
+ "profile",
2559
+ "music",
2560
+ "video"
2561
+ ]);
2562
+ var twitterCardSchema = z.enum([
2563
+ "summary",
2564
+ "summary_large_image",
2565
+ "app",
2566
+ "player"
2567
+ ]);
2568
+ var validationStatusSchema = z.enum([
2569
+ "pending",
2570
+ "valid",
2571
+ "invalid",
2572
+ "warning"
2573
+ ]);
2574
+ var seoMetadataSchema = z.object({
2575
+ // Basic metadata
2576
+ title: z.string().max(60, "Title must be 60 characters or less").optional(),
2577
+ description: z.string().max(160, "Description must be 160 characters or less").optional(),
2578
+ keywords: z.array(z.string()).optional(),
2579
+ // Open Graph
2580
+ ogTitle: z.string().max(60).optional(),
2581
+ ogDescription: z.string().max(200).optional(),
2582
+ ogImageUrl: z.string().url("Must be a valid URL").optional(),
2583
+ ogImageWidth: z.number().int().positive().max(1200).optional(),
2584
+ ogImageHeight: z.number().int().positive().max(1200).optional(),
2585
+ ogType: ogTypeSchema.optional(),
2586
+ ogUrl: z.string().url("Must be a valid URL").optional(),
2587
+ ogSiteName: z.string().optional(),
2588
+ // Twitter Card
2589
+ twitterCard: twitterCardSchema.optional(),
2590
+ twitterTitle: z.string().max(70).optional(),
2591
+ twitterDescription: z.string().max(200).optional(),
2592
+ twitterImageUrl: z.string().url("Must be a valid URL").optional(),
2593
+ twitterSite: z.string().optional(),
2594
+ twitterCreator: z.string().optional(),
2595
+ // Additional metadata
2596
+ canonicalUrl: z.string().url("Must be a valid URL").optional(),
2597
+ robots: z.string().optional(),
2598
+ author: z.string().optional(),
2599
+ publishedTime: z.coerce.date().optional(),
2600
+ modifiedTime: z.coerce.date().optional(),
2601
+ // Structured data
2602
+ structuredData: z.record(z.unknown()).optional()
2603
+ });
2604
+ var seoRecordSchema = seoMetadataSchema.extend({
2605
+ id: z.string().uuid().optional(),
2606
+ userId: z.string().uuid(),
2607
+ routePath: z.string().min(1, "Route path is required").regex(/^\/.*/, "Route path must start with /"),
2608
+ validationStatus: validationStatusSchema.optional(),
2609
+ lastValidatedAt: z.coerce.date().optional(),
2610
+ validationErrors: z.record(z.unknown()).optional(),
2611
+ createdAt: z.coerce.date().optional(),
2612
+ updatedAt: z.coerce.date().optional()
2613
+ });
2614
+ var createSEORecordSchema = seoRecordSchema.omit({
2615
+ id: true,
2616
+ validationStatus: true,
2617
+ lastValidatedAt: true,
2618
+ validationErrors: true,
2619
+ createdAt: true,
2620
+ updatedAt: true
2621
+ });
2622
+ var updateSEORecordSchema = seoRecordSchema.partial().required({ id: true }).omit({
2623
+ userId: true,
2624
+ createdAt: true
2625
+ });
2626
+
2627
+ // src/components/ui/input.tsx
2628
+ import * as React3 from "react";
2629
+ import { jsx as jsx3 } from "react/jsx-runtime";
2630
+ var Input = React3.forwardRef(
2631
+ ({ className, type, ...props }, ref) => {
2632
+ return /* @__PURE__ */ jsx3(
2633
+ "input",
2634
+ {
2635
+ type,
2636
+ className: cn(
2637
+ "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
2638
+ className
2639
+ ),
2640
+ ref,
2641
+ ...props
2642
+ }
2643
+ );
2644
+ }
2645
+ );
2646
+ Input.displayName = "Input";
2647
+
2648
+ // src/components/seo/OGImagePreview.tsx
2649
+ import { useState, useEffect } from "react";
2650
+
2651
+ // src/components/ui/spinner.tsx
2652
+ import { jsx as jsx4 } from "react/jsx-runtime";
2653
+ function Spinner({ className, size = "default" }) {
2654
+ return /* @__PURE__ */ jsx4(
2655
+ "div",
2656
+ {
2657
+ className: cn(
2658
+ "animate-spin rounded-full border-2 border-current border-t-transparent",
2659
+ {
2660
+ "h-4 w-4": size === "sm",
2661
+ "h-6 w-6": size === "default",
2662
+ "h-8 w-8": size === "lg"
2663
+ },
2664
+ className
2665
+ )
2666
+ }
2667
+ );
2668
+ }
2669
+
2670
+ // src/components/seo/OGImagePreview.tsx
2671
+ import { jsx as jsx5, jsxs } from "react/jsx-runtime";
2672
+ function OGImagePreview({
2673
+ imageUrl,
2674
+ expectedWidth,
2675
+ expectedHeight,
2676
+ title,
2677
+ description
2678
+ }) {
2679
+ const [selectedPlatform, setSelectedPlatform] = useState("facebook");
2680
+ const [imageError, setImageError] = useState(false);
2681
+ const [validationResult, setValidationResult] = useState(null);
2682
+ const [validating, setValidating] = useState(false);
2683
+ useEffect(() => {
2684
+ if (imageUrl) {
2685
+ validateImage();
2686
+ }
2687
+ }, [imageUrl, expectedWidth, expectedHeight]);
2688
+ const validateImage = async () => {
2689
+ if (!imageUrl) return;
2690
+ setValidating(true);
2691
+ try {
2692
+ const response = await fetch("/api/validate-image", {
2693
+ method: "POST",
2694
+ headers: { "Content-Type": "application/json" },
2695
+ body: JSON.stringify({
2696
+ imageUrl,
2697
+ expectedWidth,
2698
+ expectedHeight
2699
+ })
2700
+ });
2701
+ if (response.ok) {
2702
+ const result = await response.json();
2703
+ setValidationResult(result);
2704
+ }
2705
+ } catch {
2706
+ } finally {
2707
+ setValidating(false);
2708
+ }
2709
+ };
2710
+ const platformSpecs = {
2711
+ facebook: {
2712
+ name: "Facebook",
2713
+ width: 1200,
2714
+ height: 630,
2715
+ aspectRatio: "1.91:1",
2716
+ color: "bg-blue-50 border-blue-200"
2717
+ },
2718
+ twitter: {
2719
+ name: "Twitter",
2720
+ width: 1200,
2721
+ height: 675,
2722
+ aspectRatio: "16:9",
2723
+ color: "bg-sky-50 border-sky-200"
2724
+ },
2725
+ linkedin: {
2726
+ name: "LinkedIn",
2727
+ width: 1200,
2728
+ height: 627,
2729
+ aspectRatio: "1.91:1",
2730
+ color: "bg-blue-50 border-blue-200"
2731
+ }
2732
+ };
2733
+ const spec = platformSpecs[selectedPlatform];
2734
+ return /* @__PURE__ */ jsxs(Card, { children: [
2735
+ /* @__PURE__ */ jsxs(CardHeader, { children: [
2736
+ /* @__PURE__ */ jsx5(CardTitle, { children: "OG Image Preview" }),
2737
+ /* @__PURE__ */ jsx5(CardDescription, { children: "Preview how your image appears on social platforms" })
2738
+ ] }),
2739
+ /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
2740
+ /* @__PURE__ */ jsx5("div", { className: "flex gap-2", children: ["facebook", "twitter", "linkedin"].map((platform) => /* @__PURE__ */ jsx5(
2741
+ "button",
2742
+ {
2743
+ onClick: () => setSelectedPlatform(platform),
2744
+ className: `px-4 py-2 rounded-lg text-sm font-medium transition-colors ${selectedPlatform === platform ? "bg-blue-600 text-white" : "bg-gray-100 text-gray-700 hover:bg-gray-200"}`,
2745
+ "aria-pressed": selectedPlatform === platform,
2746
+ children: platformSpecs[platform].name
2747
+ },
2748
+ platform
2749
+ )) }),
2750
+ /* @__PURE__ */ jsx5("div", { className: `p-3 rounded-lg border ${spec.color}`, children: /* @__PURE__ */ jsxs("div", { className: "text-sm", children: [
2751
+ /* @__PURE__ */ jsxs("div", { className: "font-medium mb-1", children: [
2752
+ spec.name,
2753
+ " Recommended Size"
2754
+ ] }),
2755
+ /* @__PURE__ */ jsxs("div", { className: "text-gray-600", children: [
2756
+ spec.width,
2757
+ " \xD7 ",
2758
+ spec.height,
2759
+ "px (",
2760
+ spec.aspectRatio,
2761
+ ")"
2762
+ ] })
2763
+ ] }) }),
2764
+ /* @__PURE__ */ jsx5("div", { className: "relative", children: /* @__PURE__ */ jsxs(
2765
+ "div",
2766
+ {
2767
+ className: "relative border-2 border-gray-300 rounded-lg overflow-hidden bg-gray-100",
2768
+ style: {
2769
+ aspectRatio: `${spec.width} / ${spec.height}`,
2770
+ maxWidth: "100%"
2771
+ },
2772
+ children: [
2773
+ imageUrl && !imageError ? /* @__PURE__ */ jsx5(
2774
+ "img",
2775
+ {
2776
+ src: imageUrl,
2777
+ alt: title || "OG Image",
2778
+ className: "w-full h-full object-cover",
2779
+ onError: () => setImageError(true),
2780
+ onLoad: () => setImageError(false)
2781
+ }
2782
+ ) : /* @__PURE__ */ jsx5("div", { className: "flex items-center justify-center h-full text-gray-400", children: imageError ? /* @__PURE__ */ jsxs("div", { className: "text-center p-4", children: [
2783
+ /* @__PURE__ */ jsx5("div", { className: "text-sm font-medium", children: "Image failed to load" }),
2784
+ /* @__PURE__ */ jsx5("div", { className: "text-xs mt-1", children: "Check the URL is accessible" })
2785
+ ] }) : /* @__PURE__ */ jsx5(Spinner, {}) }),
2786
+ title && !imageError && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/70 to-transparent p-4 text-white", children: [
2787
+ title && /* @__PURE__ */ jsx5("div", { className: "font-semibold text-sm mb-1 line-clamp-2", children: title }),
2788
+ description && /* @__PURE__ */ jsx5("div", { className: "text-xs opacity-90 line-clamp-2", children: description })
2789
+ ] })
2790
+ ]
2791
+ }
2792
+ ) }),
2793
+ validating && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-gray-600", children: [
2794
+ /* @__PURE__ */ jsx5(Spinner, { size: "sm" }),
2795
+ /* @__PURE__ */ jsx5("span", { children: "Validating image..." })
2796
+ ] }),
2797
+ validationResult && !validating && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2798
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2799
+ /* @__PURE__ */ jsx5("span", { className: "text-sm font-medium", children: "Validation Status" }),
2800
+ /* @__PURE__ */ jsx5(
2801
+ "span",
2802
+ {
2803
+ className: `text-xs px-2 py-1 rounded ${validationResult.isValid ? "bg-green-100 text-green-800" : "bg-red-100 text-red-800"}`,
2804
+ children: validationResult.isValid ? "Valid" : "Issues Found"
2805
+ }
2806
+ )
2807
+ ] }),
2808
+ validationResult.metadata && /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-600 space-y-1", children: [
2809
+ /* @__PURE__ */ jsxs("div", { children: [
2810
+ "Dimensions: ",
2811
+ validationResult.metadata.width,
2812
+ " \xD7 ",
2813
+ validationResult.metadata.height,
2814
+ "px"
2815
+ ] }),
2816
+ /* @__PURE__ */ jsxs("div", { children: [
2817
+ "Format: ",
2818
+ validationResult.metadata.format.toUpperCase()
2819
+ ] }),
2820
+ validationResult.metadata.size && /* @__PURE__ */ jsxs("div", { children: [
2821
+ "Size: ",
2822
+ (validationResult.metadata.size / 1024).toFixed(1),
2823
+ " KB"
2824
+ ] })
2825
+ ] }),
2826
+ validationResult.issues.length > 0 && /* @__PURE__ */ jsx5("div", { className: "space-y-2 mt-3", children: validationResult.issues.map((issue, idx) => /* @__PURE__ */ jsxs(
2827
+ "div",
2828
+ {
2829
+ className: `p-2 rounded text-xs border ${issue.severity === "critical" ? "bg-red-50 border-red-200 text-red-800" : issue.severity === "warning" ? "bg-yellow-50 border-yellow-200 text-yellow-800" : "bg-blue-50 border-blue-200 text-blue-800"}`,
2830
+ children: [
2831
+ /* @__PURE__ */ jsx5("div", { className: "font-medium", children: issue.field }),
2832
+ /* @__PURE__ */ jsx5("div", { className: "mt-1", children: issue.message }),
2833
+ issue.expected && /* @__PURE__ */ jsxs("div", { className: "mt-1", children: [
2834
+ "Expected: ",
2835
+ /* @__PURE__ */ jsx5("code", { className: "bg-white/50 px-1 rounded", children: issue.expected })
2836
+ ] }),
2837
+ issue.actual && /* @__PURE__ */ jsxs("div", { className: "mt-1", children: [
2838
+ "Actual: ",
2839
+ /* @__PURE__ */ jsx5("code", { className: "bg-white/50 px-1 rounded", children: issue.actual })
2840
+ ] })
2841
+ ]
2842
+ },
2843
+ idx
2844
+ )) })
2845
+ ] }),
2846
+ /* @__PURE__ */ jsxs("div", { className: "pt-2 border-t", children: [
2847
+ /* @__PURE__ */ jsx5("div", { className: "text-xs text-gray-500 mb-1", children: "Image URL" }),
2848
+ /* @__PURE__ */ jsx5("div", { className: "text-xs font-mono text-gray-700 break-all", children: imageUrl || "No image URL provided" })
2849
+ ] })
2850
+ ] })
2851
+ ] });
2852
+ }
2853
+
2854
+ // src/components/seo/SEORecordForm.tsx
2855
+ import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
2856
+ function SEORecordForm({ record, onSuccess, onCancel }) {
2857
+ const [loading, setLoading] = useState2(false);
2858
+ const [error, setError] = useState2(null);
2859
+ const isEditing = !!record;
2860
+ const schema = isEditing ? updateSEORecordSchema : createSEORecordSchema;
2861
+ const {
2862
+ register,
2863
+ handleSubmit,
2864
+ formState: { errors },
2865
+ reset,
2866
+ watch
2867
+ } = useForm({
2868
+ resolver: zodResolver(schema),
2869
+ defaultValues: record ? {
2870
+ id: record.id,
2871
+ routePath: record.routePath,
2872
+ title: record.title,
2873
+ description: record.description,
2874
+ keywords: record.keywords,
2875
+ ogTitle: record.ogTitle,
2876
+ ogDescription: record.ogDescription,
2877
+ ogImageUrl: record.ogImageUrl,
2878
+ ogImageWidth: record.ogImageWidth,
2879
+ ogImageHeight: record.ogImageHeight,
2880
+ ogType: record.ogType,
2881
+ ogUrl: record.ogUrl,
2882
+ ogSiteName: record.ogSiteName,
2883
+ twitterCard: record.twitterCard,
2884
+ twitterTitle: record.twitterTitle,
2885
+ twitterDescription: record.twitterDescription,
2886
+ twitterImageUrl: record.twitterImageUrl,
2887
+ twitterSite: record.twitterSite,
2888
+ twitterCreator: record.twitterCreator,
2889
+ canonicalUrl: record.canonicalUrl,
2890
+ robots: record.robots,
2891
+ author: record.author,
2892
+ publishedTime: record.publishedTime,
2893
+ modifiedTime: record.modifiedTime
2894
+ } : {
2895
+ routePath: ""
2896
+ }
2897
+ });
2898
+ const titleValue = watch("title");
2899
+ const descriptionValue = watch("description");
2900
+ const ogTitleValue = watch("ogTitle");
2901
+ const ogDescriptionValue = watch("ogDescription");
2902
+ const onSubmit = async (data) => {
2903
+ setLoading(true);
2904
+ setError(null);
2905
+ try {
2906
+ const url = isEditing ? `/api/seo-records/${data.id}` : "/api/seo-records";
2907
+ const method = isEditing ? "PATCH" : "POST";
2908
+ const response = await fetch(url, {
2909
+ method,
2910
+ headers: { "Content-Type": "application/json" },
2911
+ body: JSON.stringify(data)
2912
+ });
2913
+ if (!response.ok) {
2914
+ const errorData = await response.json();
2915
+ throw new Error(errorData.error || "Failed to save SEO record");
2916
+ }
2917
+ onSuccess?.();
2918
+ if (!isEditing) {
2919
+ reset();
2920
+ }
2921
+ } catch (err) {
2922
+ setError(err instanceof Error ? err.message : "An error occurred");
2923
+ } finally {
2924
+ setLoading(false);
2925
+ }
2926
+ };
2927
+ return /* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-6", children: [
2928
+ error && /* @__PURE__ */ jsx6(
2929
+ "div",
2930
+ {
2931
+ className: "bg-red-50 border border-red-200 text-red-600 px-4 py-3 rounded-lg text-sm",
2932
+ role: "alert",
2933
+ "aria-live": "polite",
2934
+ children: error
2935
+ }
2936
+ ),
2937
+ /* @__PURE__ */ jsxs2(Card, { children: [
2938
+ /* @__PURE__ */ jsxs2(CardHeader, { children: [
2939
+ /* @__PURE__ */ jsx6(CardTitle, { children: "Basic Information" }),
2940
+ /* @__PURE__ */ jsx6(CardDescription, { children: "Core SEO metadata" })
2941
+ ] }),
2942
+ /* @__PURE__ */ jsxs2(CardContent, { className: "space-y-4", children: [
2943
+ /* @__PURE__ */ jsxs2("div", { children: [
2944
+ /* @__PURE__ */ jsxs2("label", { htmlFor: "routePath", className: "block text-sm font-medium text-gray-700 mb-1", children: [
2945
+ "Route Path ",
2946
+ /* @__PURE__ */ jsx6("span", { className: "text-red-500", children: "*" })
2947
+ ] }),
2948
+ /* @__PURE__ */ jsx6(
2949
+ Input,
2950
+ {
2951
+ id: "routePath",
2952
+ ...register("routePath"),
2953
+ placeholder: "/about",
2954
+ "aria-describedby": errors.routePath ? "routePath-error" : void 0,
2955
+ "aria-invalid": errors.routePath ? "true" : "false"
2956
+ }
2957
+ ),
2958
+ errors.routePath && /* @__PURE__ */ jsx6("p", { id: "routePath-error", className: "mt-1 text-sm text-red-600", role: "alert", children: errors.routePath.message })
2959
+ ] }),
2960
+ /* @__PURE__ */ jsxs2("div", { children: [
2961
+ /* @__PURE__ */ jsx6("label", { htmlFor: "title", className: "block text-sm font-medium text-gray-700 mb-1", children: "Title" }),
2962
+ /* @__PURE__ */ jsx6(
2963
+ Input,
2964
+ {
2965
+ id: "title",
2966
+ ...register("title"),
2967
+ placeholder: "Page Title",
2968
+ maxLength: 60,
2969
+ "aria-describedby": "title-help title-count"
2970
+ }
2971
+ ),
2972
+ /* @__PURE__ */ jsxs2("div", { className: "flex justify-between mt-1", children: [
2973
+ /* @__PURE__ */ jsx6("p", { id: "title-help", className: "text-xs text-gray-500", children: "Recommended: 50-60 characters" }),
2974
+ /* @__PURE__ */ jsxs2("span", { id: "title-count", className: "text-xs text-gray-500", "aria-live": "polite", children: [
2975
+ titleValue?.length || 0,
2976
+ "/60"
2977
+ ] })
2978
+ ] }),
2979
+ errors.title && /* @__PURE__ */ jsx6("p", { className: "mt-1 text-sm text-red-600", role: "alert", children: errors.title.message })
2980
+ ] }),
2981
+ /* @__PURE__ */ jsxs2("div", { children: [
2982
+ /* @__PURE__ */ jsx6("label", { htmlFor: "description", className: "block text-sm font-medium text-gray-700 mb-1", children: "Description" }),
2983
+ /* @__PURE__ */ jsx6(
2984
+ "textarea",
2985
+ {
2986
+ id: "description",
2987
+ ...register("description"),
2988
+ rows: 3,
2989
+ placeholder: "Page description",
2990
+ maxLength: 160,
2991
+ className: "w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500",
2992
+ "aria-describedby": "description-help description-count"
2993
+ }
2994
+ ),
2995
+ /* @__PURE__ */ jsxs2("div", { className: "flex justify-between mt-1", children: [
2996
+ /* @__PURE__ */ jsx6("p", { id: "description-help", className: "text-xs text-gray-500", children: "Recommended: 150-160 characters" }),
2997
+ /* @__PURE__ */ jsxs2("span", { id: "description-count", className: "text-xs text-gray-500", "aria-live": "polite", children: [
2998
+ descriptionValue?.length || 0,
2999
+ "/160"
3000
+ ] })
3001
+ ] }),
3002
+ errors.description && /* @__PURE__ */ jsx6("p", { className: "mt-1 text-sm text-red-600", role: "alert", children: errors.description.message })
3003
+ ] }),
3004
+ /* @__PURE__ */ jsxs2("div", { children: [
3005
+ /* @__PURE__ */ jsx6("label", { htmlFor: "canonicalUrl", className: "block text-sm font-medium text-gray-700 mb-1", children: "Canonical URL" }),
3006
+ /* @__PURE__ */ jsx6(
3007
+ Input,
3008
+ {
3009
+ id: "canonicalUrl",
3010
+ type: "url",
3011
+ ...register("canonicalUrl"),
3012
+ placeholder: "https://example.com/page"
3013
+ }
3014
+ ),
3015
+ errors.canonicalUrl && /* @__PURE__ */ jsx6("p", { className: "mt-1 text-sm text-red-600", role: "alert", children: errors.canonicalUrl.message })
3016
+ ] })
3017
+ ] })
3018
+ ] }),
3019
+ /* @__PURE__ */ jsxs2(Card, { children: [
3020
+ /* @__PURE__ */ jsxs2(CardHeader, { children: [
3021
+ /* @__PURE__ */ jsx6(CardTitle, { children: "Open Graph" }),
3022
+ /* @__PURE__ */ jsx6(CardDescription, { children: "Social media sharing metadata" })
3023
+ ] }),
3024
+ /* @__PURE__ */ jsxs2(CardContent, { className: "space-y-4", children: [
3025
+ /* @__PURE__ */ jsxs2("div", { children: [
3026
+ /* @__PURE__ */ jsx6("label", { htmlFor: "ogType", className: "block text-sm font-medium text-gray-700 mb-1", children: "OG Type" }),
3027
+ /* @__PURE__ */ jsxs2(
3028
+ "select",
3029
+ {
3030
+ id: "ogType",
3031
+ ...register("ogType"),
3032
+ className: "w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500",
3033
+ children: [
3034
+ /* @__PURE__ */ jsx6("option", { value: "", children: "Select type" }),
3035
+ /* @__PURE__ */ jsx6("option", { value: "website", children: "Website" }),
3036
+ /* @__PURE__ */ jsx6("option", { value: "article", children: "Article" }),
3037
+ /* @__PURE__ */ jsx6("option", { value: "product", children: "Product" }),
3038
+ /* @__PURE__ */ jsx6("option", { value: "book", children: "Book" }),
3039
+ /* @__PURE__ */ jsx6("option", { value: "profile", children: "Profile" }),
3040
+ /* @__PURE__ */ jsx6("option", { value: "music", children: "Music" }),
3041
+ /* @__PURE__ */ jsx6("option", { value: "video", children: "Video" })
3042
+ ]
3043
+ }
3044
+ )
3045
+ ] }),
3046
+ /* @__PURE__ */ jsxs2("div", { children: [
3047
+ /* @__PURE__ */ jsx6("label", { htmlFor: "ogTitle", className: "block text-sm font-medium text-gray-700 mb-1", children: "OG Title" }),
3048
+ /* @__PURE__ */ jsx6(
3049
+ Input,
3050
+ {
3051
+ id: "ogTitle",
3052
+ ...register("ogTitle"),
3053
+ placeholder: "Open Graph title",
3054
+ maxLength: 60,
3055
+ "aria-describedby": "ogTitle-count"
3056
+ }
3057
+ ),
3058
+ /* @__PURE__ */ jsxs2("span", { id: "ogTitle-count", className: "text-xs text-gray-500 mt-1 block", "aria-live": "polite", children: [
3059
+ ogTitleValue?.length || 0,
3060
+ "/60"
3061
+ ] })
3062
+ ] }),
3063
+ /* @__PURE__ */ jsxs2("div", { children: [
3064
+ /* @__PURE__ */ jsx6("label", { htmlFor: "ogDescription", className: "block text-sm font-medium text-gray-700 mb-1", children: "OG Description" }),
3065
+ /* @__PURE__ */ jsx6(
3066
+ "textarea",
3067
+ {
3068
+ id: "ogDescription",
3069
+ ...register("ogDescription"),
3070
+ rows: 3,
3071
+ placeholder: "Open Graph description",
3072
+ maxLength: 200,
3073
+ className: "w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500",
3074
+ "aria-describedby": "ogDescription-count"
3075
+ }
3076
+ ),
3077
+ /* @__PURE__ */ jsxs2("span", { id: "ogDescription-count", className: "text-xs text-gray-500 mt-1 block", "aria-live": "polite", children: [
3078
+ ogDescriptionValue?.length || 0,
3079
+ "/200"
3080
+ ] })
3081
+ ] }),
3082
+ /* @__PURE__ */ jsxs2("div", { children: [
3083
+ /* @__PURE__ */ jsx6("label", { htmlFor: "ogImageUrl", className: "block text-sm font-medium text-gray-700 mb-1", children: "OG Image URL" }),
3084
+ /* @__PURE__ */ jsx6(
3085
+ Input,
3086
+ {
3087
+ id: "ogImageUrl",
3088
+ type: "url",
3089
+ ...register("ogImageUrl"),
3090
+ placeholder: "https://example.com/image.jpg"
3091
+ }
3092
+ ),
3093
+ errors.ogImageUrl && /* @__PURE__ */ jsx6("p", { className: "mt-1 text-sm text-red-600", role: "alert", children: errors.ogImageUrl.message }),
3094
+ watch("ogImageUrl") && /* @__PURE__ */ jsx6("div", { className: "mt-4", children: /* @__PURE__ */ jsx6(
3095
+ OGImagePreview,
3096
+ {
3097
+ imageUrl: watch("ogImageUrl") || "",
3098
+ expectedWidth: watch("ogImageWidth"),
3099
+ expectedHeight: watch("ogImageHeight"),
3100
+ title: watch("ogTitle") || watch("title"),
3101
+ description: watch("ogDescription") || watch("description")
3102
+ }
3103
+ ) })
3104
+ ] }),
3105
+ /* @__PURE__ */ jsxs2("div", { className: "grid grid-cols-2 gap-4", children: [
3106
+ /* @__PURE__ */ jsxs2("div", { children: [
3107
+ /* @__PURE__ */ jsx6("label", { htmlFor: "ogImageWidth", className: "block text-sm font-medium text-gray-700 mb-1", children: "OG Image Width" }),
3108
+ /* @__PURE__ */ jsx6(
3109
+ Input,
3110
+ {
3111
+ id: "ogImageWidth",
3112
+ type: "number",
3113
+ ...register("ogImageWidth", { valueAsNumber: true }),
3114
+ placeholder: "1200"
3115
+ }
3116
+ )
3117
+ ] }),
3118
+ /* @__PURE__ */ jsxs2("div", { children: [
3119
+ /* @__PURE__ */ jsx6("label", { htmlFor: "ogImageHeight", className: "block text-sm font-medium text-gray-700 mb-1", children: "OG Image Height" }),
3120
+ /* @__PURE__ */ jsx6(
3121
+ Input,
3122
+ {
3123
+ id: "ogImageHeight",
3124
+ type: "number",
3125
+ ...register("ogImageHeight", { valueAsNumber: true }),
3126
+ placeholder: "630"
3127
+ }
3128
+ )
3129
+ ] })
3130
+ ] }),
3131
+ /* @__PURE__ */ jsxs2("div", { children: [
3132
+ /* @__PURE__ */ jsx6("label", { htmlFor: "ogSiteName", className: "block text-sm font-medium text-gray-700 mb-1", children: "OG Site Name" }),
3133
+ /* @__PURE__ */ jsx6(Input, { id: "ogSiteName", ...register("ogSiteName"), placeholder: "Site Name" })
3134
+ ] })
3135
+ ] })
3136
+ ] }),
3137
+ /* @__PURE__ */ jsxs2(Card, { children: [
3138
+ /* @__PURE__ */ jsxs2(CardHeader, { children: [
3139
+ /* @__PURE__ */ jsx6(CardTitle, { children: "Twitter Card" }),
3140
+ /* @__PURE__ */ jsx6(CardDescription, { children: "Twitter sharing metadata" })
3141
+ ] }),
3142
+ /* @__PURE__ */ jsxs2(CardContent, { className: "space-y-4", children: [
3143
+ /* @__PURE__ */ jsxs2("div", { children: [
3144
+ /* @__PURE__ */ jsx6("label", { htmlFor: "twitterCard", className: "block text-sm font-medium text-gray-700 mb-1", children: "Twitter Card Type" }),
3145
+ /* @__PURE__ */ jsxs2(
3146
+ "select",
3147
+ {
3148
+ id: "twitterCard",
3149
+ ...register("twitterCard"),
3150
+ className: "w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500",
3151
+ children: [
3152
+ /* @__PURE__ */ jsx6("option", { value: "", children: "Select type" }),
3153
+ /* @__PURE__ */ jsx6("option", { value: "summary", children: "Summary" }),
3154
+ /* @__PURE__ */ jsx6("option", { value: "summary_large_image", children: "Summary Large Image" }),
3155
+ /* @__PURE__ */ jsx6("option", { value: "app", children: "App" }),
3156
+ /* @__PURE__ */ jsx6("option", { value: "player", children: "Player" })
3157
+ ]
3158
+ }
3159
+ )
3160
+ ] }),
3161
+ /* @__PURE__ */ jsxs2("div", { children: [
3162
+ /* @__PURE__ */ jsx6("label", { htmlFor: "twitterTitle", className: "block text-sm font-medium text-gray-700 mb-1", children: "Twitter Title" }),
3163
+ /* @__PURE__ */ jsx6(
3164
+ Input,
3165
+ {
3166
+ id: "twitterTitle",
3167
+ ...register("twitterTitle"),
3168
+ placeholder: "Twitter title",
3169
+ maxLength: 70
3170
+ }
3171
+ )
3172
+ ] }),
3173
+ /* @__PURE__ */ jsxs2("div", { children: [
3174
+ /* @__PURE__ */ jsx6("label", { htmlFor: "twitterDescription", className: "block text-sm font-medium text-gray-700 mb-1", children: "Twitter Description" }),
3175
+ /* @__PURE__ */ jsx6(
3176
+ "textarea",
3177
+ {
3178
+ id: "twitterDescription",
3179
+ ...register("twitterDescription"),
3180
+ rows: 3,
3181
+ placeholder: "Twitter description",
3182
+ maxLength: 200,
3183
+ className: "w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
3184
+ }
3185
+ )
3186
+ ] }),
3187
+ /* @__PURE__ */ jsxs2("div", { children: [
3188
+ /* @__PURE__ */ jsx6("label", { htmlFor: "twitterImageUrl", className: "block text-sm font-medium text-gray-700 mb-1", children: "Twitter Image URL" }),
3189
+ /* @__PURE__ */ jsx6(
3190
+ Input,
3191
+ {
3192
+ id: "twitterImageUrl",
3193
+ type: "url",
3194
+ ...register("twitterImageUrl"),
3195
+ placeholder: "https://example.com/twitter-image.jpg"
3196
+ }
3197
+ )
3198
+ ] })
3199
+ ] })
3200
+ ] }),
3201
+ /* @__PURE__ */ jsxs2("div", { className: "flex gap-4 justify-end", children: [
3202
+ onCancel && /* @__PURE__ */ jsx6(Button, { type: "button", variant: "outline", onClick: onCancel, children: "Cancel" }),
3203
+ /* @__PURE__ */ jsxs2(Button, { type: "submit", disabled: loading, children: [
3204
+ loading ? "Saving..." : isEditing ? "Update" : "Create",
3205
+ " SEO Record"
3206
+ ] })
3207
+ ] })
3208
+ ] });
3209
+ }
3210
+
3211
+ // src/components/seo/SEORecordList.tsx
3212
+ import { Fragment, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
3213
+ function SEORecordList() {
3214
+ const [records, setRecords] = useState3([]);
3215
+ const [loading, setLoading] = useState3(true);
3216
+ const [error, setError] = useState3(null);
3217
+ const [editingId, setEditingId] = useState3(null);
3218
+ const [showForm, setShowForm] = useState3(false);
3219
+ const fetchRecords = async () => {
3220
+ setLoading(true);
3221
+ setError(null);
3222
+ try {
3223
+ const response = await fetch("/api/seo-records");
3224
+ if (!response.ok) {
3225
+ throw new Error("Failed to fetch SEO records");
3226
+ }
3227
+ const data = await response.json();
3228
+ setRecords(data.data || []);
3229
+ } catch (err) {
3230
+ setError(err instanceof Error ? err.message : "An error occurred");
3231
+ } finally {
3232
+ setLoading(false);
3233
+ }
3234
+ };
3235
+ useEffect2(() => {
3236
+ fetchRecords();
3237
+ }, []);
3238
+ const handleDelete = async (id) => {
3239
+ if (!confirm("Are you sure you want to delete this SEO record?")) {
3240
+ return;
3241
+ }
3242
+ try {
3243
+ const response = await fetch(`/api/seo-records/${id}`, {
3244
+ method: "DELETE"
3245
+ });
3246
+ if (!response.ok) {
3247
+ throw new Error("Failed to delete SEO record");
3248
+ }
3249
+ await fetchRecords();
3250
+ } catch (err) {
3251
+ alert(err instanceof Error ? err.message : "Failed to delete record");
3252
+ }
3253
+ };
3254
+ const handleEdit = (id) => {
3255
+ setEditingId(id);
3256
+ setShowForm(true);
3257
+ };
3258
+ const handleFormSuccess = () => {
3259
+ setShowForm(false);
3260
+ setEditingId(null);
3261
+ fetchRecords();
3262
+ };
3263
+ const handleCancel = () => {
3264
+ setShowForm(false);
3265
+ setEditingId(null);
3266
+ };
3267
+ const editingRecord = editingId ? records.find((r) => r.id === editingId) || void 0 : void 0;
3268
+ if (showForm) {
3269
+ return /* @__PURE__ */ jsxs3("div", { children: [
3270
+ /* @__PURE__ */ jsx7(
3271
+ Button,
3272
+ {
3273
+ variant: "outline",
3274
+ onClick: handleCancel,
3275
+ className: "mb-4",
3276
+ children: "\u2190 Back to List"
3277
+ }
3278
+ ),
3279
+ /* @__PURE__ */ jsx7(
3280
+ SEORecordForm,
3281
+ {
3282
+ record: editingRecord,
3283
+ onSuccess: handleFormSuccess,
3284
+ onCancel: handleCancel
3285
+ }
3286
+ )
3287
+ ] });
3288
+ }
3289
+ if (loading) {
3290
+ return /* @__PURE__ */ jsx7("div", { className: "text-center py-8", children: /* @__PURE__ */ jsx7("p", { className: "text-gray-600", children: "Loading SEO records..." }) });
3291
+ }
3292
+ if (error) {
3293
+ return /* @__PURE__ */ jsxs3("div", { className: "bg-red-50 border border-red-200 text-red-600 px-4 py-3 rounded-lg", children: [
3294
+ /* @__PURE__ */ jsxs3("p", { children: [
3295
+ "Error: ",
3296
+ error
3297
+ ] }),
3298
+ /* @__PURE__ */ jsx7(Button, { onClick: fetchRecords, variant: "outline", className: "mt-2", children: "Retry" })
3299
+ ] });
3300
+ }
3301
+ return /* @__PURE__ */ jsxs3("div", { className: "space-y-4", children: [
3302
+ /* @__PURE__ */ jsxs3("div", { className: "flex justify-between items-center", children: [
3303
+ /* @__PURE__ */ jsx7("h2", { className: "text-2xl font-bold text-gray-900", children: "SEO Records" }),
3304
+ /* @__PURE__ */ jsx7(Button, { onClick: () => setShowForm(true), children: "Create New Record" })
3305
+ ] }),
3306
+ records.length === 0 ? /* @__PURE__ */ jsx7(Card, { children: /* @__PURE__ */ jsxs3(CardContent, { className: "py-8 text-center", children: [
3307
+ /* @__PURE__ */ jsx7("p", { className: "text-gray-600 mb-4", children: "No SEO records yet." }),
3308
+ /* @__PURE__ */ jsx7(Button, { onClick: () => setShowForm(true), children: "Create Your First Record" })
3309
+ ] }) }) : /* @__PURE__ */ jsx7("div", { className: "grid gap-4", children: records.map((record) => /* @__PURE__ */ jsxs3(Card, { children: [
3310
+ /* @__PURE__ */ jsx7(CardHeader, { children: /* @__PURE__ */ jsxs3("div", { className: "flex justify-between items-start", children: [
3311
+ /* @__PURE__ */ jsxs3("div", { children: [
3312
+ /* @__PURE__ */ jsx7(CardTitle, { className: "text-lg", children: record.routePath }),
3313
+ record.title && /* @__PURE__ */ jsx7("p", { className: "text-sm text-gray-600 mt-1", children: record.title })
3314
+ ] }),
3315
+ /* @__PURE__ */ jsxs3("div", { className: "flex gap-2", children: [
3316
+ /* @__PURE__ */ jsx7(
3317
+ Button,
3318
+ {
3319
+ variant: "outline",
3320
+ size: "sm",
3321
+ onClick: () => record.id && handleEdit(record.id),
3322
+ children: "Edit"
3323
+ }
3324
+ ),
3325
+ /* @__PURE__ */ jsx7(
3326
+ Button,
3327
+ {
3328
+ variant: "outline",
3329
+ size: "sm",
3330
+ onClick: () => record.id && handleDelete(record.id),
3331
+ children: "Delete"
3332
+ }
3333
+ )
3334
+ ] })
3335
+ ] }) }),
3336
+ /* @__PURE__ */ jsx7(CardContent, { children: /* @__PURE__ */ jsxs3("dl", { className: "grid grid-cols-2 gap-4 text-sm", children: [
3337
+ record.description && /* @__PURE__ */ jsxs3(Fragment, { children: [
3338
+ /* @__PURE__ */ jsx7("dt", { className: "text-gray-500", children: "Description" }),
3339
+ /* @__PURE__ */ jsx7("dd", { className: "text-gray-900", children: record.description })
3340
+ ] }),
3341
+ record.ogType && /* @__PURE__ */ jsxs3(Fragment, { children: [
3342
+ /* @__PURE__ */ jsx7("dt", { className: "text-gray-500", children: "OG Type" }),
3343
+ /* @__PURE__ */ jsx7("dd", { className: "text-gray-900", children: record.ogType })
3344
+ ] }),
3345
+ record.twitterCard && /* @__PURE__ */ jsxs3(Fragment, { children: [
3346
+ /* @__PURE__ */ jsx7("dt", { className: "text-gray-500", children: "Twitter Card" }),
3347
+ /* @__PURE__ */ jsx7("dd", { className: "text-gray-900", children: record.twitterCard })
3348
+ ] }),
3349
+ record.validationStatus && /* @__PURE__ */ jsxs3(Fragment, { children: [
3350
+ /* @__PURE__ */ jsx7("dt", { className: "text-gray-500", children: "Status" }),
3351
+ /* @__PURE__ */ jsx7("dd", { className: "text-gray-900", children: /* @__PURE__ */ jsx7(
3352
+ "span",
3353
+ {
3354
+ className: `inline-flex px-2 py-1 rounded text-xs font-medium ${record.validationStatus === "valid" ? "bg-green-100 text-green-800" : record.validationStatus === "invalid" ? "bg-red-100 text-red-800" : record.validationStatus === "warning" ? "bg-yellow-100 text-yellow-800" : "bg-gray-100 text-gray-800"}`,
3355
+ children: record.validationStatus
3356
+ }
3357
+ ) })
3358
+ ] })
3359
+ ] }) })
3360
+ ] }, record.id)) })
3361
+ ] });
3362
+ }
3363
+
3364
+ // src/components/seo/ValidationDashboard.tsx
3365
+ import { useState as useState4, useEffect as useEffect3 } from "react";
3366
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
3367
+ var Link = ({ href, children, ...props }) => /* @__PURE__ */ jsx8("a", { href, ...props, children });
3368
+ function ValidationDashboard() {
3369
+ const [records, setRecords] = useState4([]);
3370
+ const [loading, setLoading] = useState4(true);
3371
+ const [validating, setValidating] = useState4({});
3372
+ const [validationResults, setValidationResults] = useState4({});
3373
+ useEffect3(() => {
3374
+ fetchRecords();
3375
+ }, []);
3376
+ const fetchRecords = async () => {
3377
+ setLoading(true);
3378
+ try {
3379
+ const response = await fetch("/api/seo-records");
3380
+ if (response.ok) {
3381
+ const data = await response.json();
3382
+ setRecords(data.data || []);
3383
+ }
3384
+ } catch {
3385
+ } finally {
3386
+ setLoading(false);
3387
+ }
3388
+ };
3389
+ const validateRecord = async (record) => {
3390
+ if (!record.id) return;
3391
+ setValidating((prev) => ({ ...prev, [record.id]: true }));
3392
+ try {
3393
+ const url = record.canonicalUrl || `https://example.com${record.routePath}`;
3394
+ const response = await fetch(`/api/seo-records/${record.id}/validate`, {
3395
+ method: "POST",
3396
+ headers: { "Content-Type": "application/json" },
3397
+ body: JSON.stringify({ url })
3398
+ });
3399
+ if (response.ok) {
3400
+ const data = await response.json();
3401
+ setValidationResults((prev) => ({
3402
+ ...prev,
3403
+ [record.id]: data
3404
+ }));
3405
+ const allIssues2 = data.validations.flatMap((v) => v.result.issues);
3406
+ const hasCritical = allIssues2.some((i) => i.severity === "critical");
3407
+ const hasWarnings = allIssues2.some((i) => i.severity === "warning");
3408
+ const validationStatus = hasCritical ? "invalid" : hasWarnings ? "warning" : "valid";
3409
+ await fetch(`/api/seo-records/${record.id}/update-validation`, {
3410
+ method: "PATCH",
3411
+ headers: { "Content-Type": "application/json" },
3412
+ body: JSON.stringify({
3413
+ validationStatus,
3414
+ validationErrors: allIssues2.reduce((acc, issue) => {
3415
+ acc[issue.field] = issue;
3416
+ return acc;
3417
+ }, {}),
3418
+ lastValidatedAt: (/* @__PURE__ */ new Date()).toISOString()
3419
+ })
3420
+ });
3421
+ fetchRecords();
3422
+ }
3423
+ } catch {
3424
+ } finally {
3425
+ setValidating((prev) => ({ ...prev, [record.id]: false }));
3426
+ }
3427
+ };
3428
+ const getSeverityColor = (severity) => {
3429
+ switch (severity) {
3430
+ case "critical":
3431
+ return "bg-red-100 text-red-800 border-red-200";
3432
+ case "warning":
3433
+ return "bg-yellow-100 text-yellow-800 border-yellow-200";
3434
+ case "info":
3435
+ return "bg-blue-100 text-blue-800 border-blue-200";
3436
+ default:
3437
+ return "bg-gray-100 text-gray-800 border-gray-200";
3438
+ }
3439
+ };
3440
+ const getSeverityIcon = (severity) => {
3441
+ switch (severity) {
3442
+ case "critical":
3443
+ return "\u274C";
3444
+ case "warning":
3445
+ return "\u26A0\uFE0F";
3446
+ case "info":
3447
+ return "\u2139\uFE0F";
3448
+ default:
3449
+ return "\u2022";
3450
+ }
3451
+ };
3452
+ if (loading) {
3453
+ return /* @__PURE__ */ jsxs4("div", { className: "text-center py-8", children: [
3454
+ /* @__PURE__ */ jsx8(Spinner, {}),
3455
+ /* @__PURE__ */ jsx8("p", { className: "text-gray-600 mt-4", children: "Loading records..." })
3456
+ ] });
3457
+ }
3458
+ const allIssues = [];
3459
+ Object.entries(validationResults).forEach(([recordId, validation]) => {
3460
+ const record = records.find((r) => r.id === recordId);
3461
+ if (record) {
3462
+ validation.validations.forEach((val) => {
3463
+ val.result.issues.forEach((issue) => {
3464
+ allIssues.push({
3465
+ record,
3466
+ issue,
3467
+ validationType: val.type
3468
+ });
3469
+ });
3470
+ });
3471
+ }
3472
+ });
3473
+ const criticalIssues = allIssues.filter((i) => i.issue.severity === "critical");
3474
+ const warningIssues = allIssues.filter((i) => i.issue.severity === "warning");
3475
+ const infoIssues = allIssues.filter((i) => i.issue.severity === "info");
3476
+ return /* @__PURE__ */ jsxs4("div", { className: "space-y-6", children: [
3477
+ /* @__PURE__ */ jsxs4("div", { className: "flex justify-between items-center", children: [
3478
+ /* @__PURE__ */ jsxs4("div", { children: [
3479
+ /* @__PURE__ */ jsx8("h2", { className: "text-2xl font-bold text-gray-900", children: "Validation Dashboard" }),
3480
+ /* @__PURE__ */ jsx8("p", { className: "text-gray-600 mt-1", children: "Validate your SEO records against live pages" })
3481
+ ] }),
3482
+ /* @__PURE__ */ jsx8(Button, { onClick: fetchRecords, variant: "outline", children: "Refresh Records" })
3483
+ ] }),
3484
+ /* @__PURE__ */ jsxs4("div", { className: "grid gap-4 md:grid-cols-4", children: [
3485
+ /* @__PURE__ */ jsx8(Card, { children: /* @__PURE__ */ jsx8(CardContent, { className: "pt-6", children: /* @__PURE__ */ jsxs4("div", { className: "text-center", children: [
3486
+ /* @__PURE__ */ jsx8("div", { className: "text-3xl font-bold text-gray-900", children: records.length }),
3487
+ /* @__PURE__ */ jsx8("div", { className: "text-sm text-gray-600 mt-1", children: "Total Records" })
3488
+ ] }) }) }),
3489
+ /* @__PURE__ */ jsx8(Card, { children: /* @__PURE__ */ jsx8(CardContent, { className: "pt-6", children: /* @__PURE__ */ jsxs4("div", { className: "text-center", children: [
3490
+ /* @__PURE__ */ jsx8("div", { className: "text-3xl font-bold text-red-600", children: criticalIssues.length }),
3491
+ /* @__PURE__ */ jsx8("div", { className: "text-sm text-gray-600 mt-1", children: "Critical Issues" })
3492
+ ] }) }) }),
3493
+ /* @__PURE__ */ jsx8(Card, { children: /* @__PURE__ */ jsx8(CardContent, { className: "pt-6", children: /* @__PURE__ */ jsxs4("div", { className: "text-center", children: [
3494
+ /* @__PURE__ */ jsx8("div", { className: "text-3xl font-bold text-yellow-600", children: warningIssues.length }),
3495
+ /* @__PURE__ */ jsx8("div", { className: "text-sm text-gray-600 mt-1", children: "Warnings" })
3496
+ ] }) }) }),
3497
+ /* @__PURE__ */ jsx8(Card, { children: /* @__PURE__ */ jsx8(CardContent, { className: "pt-6", children: /* @__PURE__ */ jsxs4("div", { className: "text-center", children: [
3498
+ /* @__PURE__ */ jsx8("div", { className: "text-3xl font-bold text-blue-600", children: infoIssues.length }),
3499
+ /* @__PURE__ */ jsx8("div", { className: "text-sm text-gray-600 mt-1", children: "Info" })
3500
+ ] }) }) })
3501
+ ] }),
3502
+ /* @__PURE__ */ jsxs4("div", { className: "space-y-4", children: [
3503
+ /* @__PURE__ */ jsx8("h3", { className: "text-lg font-semibold text-gray-900", children: "SEO Records" }),
3504
+ records.length === 0 ? /* @__PURE__ */ jsx8(Card, { children: /* @__PURE__ */ jsxs4(CardContent, { className: "py-8 text-center", children: [
3505
+ /* @__PURE__ */ jsx8("p", { className: "text-gray-600", children: "No SEO records found." }),
3506
+ /* @__PURE__ */ jsx8(Link, { href: "/dashboard", children: /* @__PURE__ */ jsx8(Button, { className: "mt-4", children: "Create Your First Record" }) })
3507
+ ] }) }) : records.map((record) => {
3508
+ const result = record.id ? validationResults[record.id] : void 0;
3509
+ const hasIssues = result?.validations.some((v) => v.result.issues.length > 0);
3510
+ return /* @__PURE__ */ jsxs4(Card, { children: [
3511
+ /* @__PURE__ */ jsx8(CardHeader, { children: /* @__PURE__ */ jsxs4("div", { className: "flex justify-between items-start", children: [
3512
+ /* @__PURE__ */ jsxs4("div", { children: [
3513
+ /* @__PURE__ */ jsx8(CardTitle, { className: "text-lg", children: record.routePath }),
3514
+ record.title && /* @__PURE__ */ jsx8(CardDescription, { className: "mt-1", children: record.title })
3515
+ ] }),
3516
+ /* @__PURE__ */ jsx8(
3517
+ Button,
3518
+ {
3519
+ onClick: () => validateRecord(record),
3520
+ disabled: validating[record.id],
3521
+ size: "sm",
3522
+ children: validating[record.id] ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
3523
+ /* @__PURE__ */ jsx8(Spinner, { className: "mr-2" }),
3524
+ "Validating..."
3525
+ ] }) : "Validate"
3526
+ }
3527
+ )
3528
+ ] }) }),
3529
+ result && /* @__PURE__ */ jsxs4(CardContent, { children: [
3530
+ /* @__PURE__ */ jsx8("div", { className: "space-y-4", children: result.validations.map((validation, idx) => /* @__PURE__ */ jsxs4("div", { className: "border-t pt-4", children: [
3531
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 mb-2", children: [
3532
+ /* @__PURE__ */ jsxs4("span", { className: "font-medium text-sm text-gray-700", children: [
3533
+ validation.type.toUpperCase(),
3534
+ " Validation"
3535
+ ] }),
3536
+ validation.result.isValid ? /* @__PURE__ */ jsx8("span", { className: "text-xs bg-green-100 text-green-800 px-2 py-1 rounded", children: "Valid" }) : /* @__PURE__ */ jsx8("span", { className: "text-xs bg-red-100 text-red-800 px-2 py-1 rounded", children: "Issues Found" })
3537
+ ] }),
3538
+ validation.result.issues.length > 0 && /* @__PURE__ */ jsx8("div", { className: "space-y-2", children: validation.result.issues.map((issue, issueIdx) => /* @__PURE__ */ jsx8(
3539
+ "div",
3540
+ {
3541
+ className: `p-3 rounded border ${getSeverityColor(issue.severity)}`,
3542
+ children: /* @__PURE__ */ jsxs4("div", { className: "flex items-start gap-2", children: [
3543
+ /* @__PURE__ */ jsx8("span", { children: getSeverityIcon(issue.severity) }),
3544
+ /* @__PURE__ */ jsxs4("div", { className: "flex-1", children: [
3545
+ /* @__PURE__ */ jsx8("div", { className: "font-medium text-sm", children: issue.field }),
3546
+ /* @__PURE__ */ jsx8("div", { className: "text-sm mt-1", children: issue.message }),
3547
+ issue.expected && /* @__PURE__ */ jsxs4("div", { className: "text-xs mt-1", children: [
3548
+ "Expected: ",
3549
+ /* @__PURE__ */ jsx8("code", { className: "bg-white/50 px-1 rounded", children: issue.expected })
3550
+ ] }),
3551
+ issue.actual && /* @__PURE__ */ jsxs4("div", { className: "text-xs mt-1", children: [
3552
+ "Actual: ",
3553
+ /* @__PURE__ */ jsx8("code", { className: "bg-white/50 px-1 rounded", children: issue.actual })
3554
+ ] })
3555
+ ] })
3556
+ ] })
3557
+ },
3558
+ issueIdx
3559
+ )) }),
3560
+ validation.result.metadata && /* @__PURE__ */ jsxs4("div", { className: "mt-2 text-xs text-gray-600", children: [
3561
+ "Image: ",
3562
+ validation.result.metadata.width,
3563
+ "x",
3564
+ validation.result.metadata.height,
3565
+ " (",
3566
+ validation.result.metadata.format,
3567
+ validation.result.metadata.size ? `, ${(validation.result.metadata.size / 1024).toFixed(1)}KB` : "",
3568
+ ")"
3569
+ ] })
3570
+ ] }, idx)) }),
3571
+ hasIssues && /* @__PURE__ */ jsx8("div", { className: "mt-4", children: /* @__PURE__ */ jsx8(Link, { href: `/dashboard?edit=${record.id}`, children: /* @__PURE__ */ jsx8(Button, { variant: "outline", size: "sm", children: "Edit Record" }) }) })
3572
+ ] })
3573
+ ] }, record.id);
3574
+ })
3575
+ ] })
3576
+ ] });
3577
+ }
3578
+ export {
3579
+ Button,
3580
+ Card,
3581
+ CardContent,
3582
+ CardDescription,
3583
+ CardFooter,
3584
+ CardHeader,
3585
+ CardTitle,
3586
+ Input,
3587
+ OGImagePreview,
3588
+ SEORecordForm,
3589
+ SEORecordList,
3590
+ Spinner,
3591
+ ValidationDashboard
3592
+ };
3593
+ //# sourceMappingURL=index.mjs.map