diff --git a/examples/server-islands/public/assets/css/main.css b/examples/server-islands/public/assets/css/main.css index e30382e7c3..5b49f60e1f 100644 --- a/examples/server-islands/public/assets/css/main.css +++ b/examples/server-islands/public/assets/css/main.css @@ -11,19 +11,19 @@ *, ::before, ::after { - box-sizing: border-box; - /* 1 */ - border-width: 0; - /* 2 */ - border-style: solid; - /* 2 */ - border-color: #e5e7eb; - /* 2 */ + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ } ::before, ::after { - --tw-content: ''; + --tw-content: ''; } /* @@ -34,17 +34,31 @@ */ html { - line-height: 1.5; - /* 1 */ - -webkit-text-size-adjust: 100%; - /* 2 */ - -moz-tab-size: 4; - /* 3 */ - -o-tab-size: 4; - tab-size: 4; - /* 3 */ - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - /* 4 */ + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: + ui-sans-serif, + system-ui, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + 'Helvetica Neue', + Arial, + 'Noto Sans', + sans-serif, + 'Apple Color Emoji', + 'Segoe UI Emoji', + 'Segoe UI Symbol', + 'Noto Color Emoji'; + /* 4 */ } /* @@ -53,10 +67,10 @@ html { */ body { - margin: 0; - /* 1 */ - line-height: inherit; - /* 2 */ + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ } /* @@ -66,12 +80,12 @@ body { */ hr { - height: 0; - /* 1 */ - color: inherit; - /* 2 */ - border-top-width: 1px; - /* 3 */ + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ } /* @@ -79,8 +93,8 @@ Add the correct text decoration in Chrome, Edge, and Safari. */ abbr:where([title]) { - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; } /* @@ -93,8 +107,8 @@ h3, h4, h5, h6 { - font-size: inherit; - font-weight: inherit; + font-size: inherit; + font-weight: inherit; } /* @@ -102,8 +116,8 @@ Reset links to optimize for opt-in styling instead of opt-out. */ a { - color: inherit; - text-decoration: inherit; + color: inherit; + text-decoration: inherit; } /* @@ -112,7 +126,7 @@ Add the correct font weight in Edge and Safari. b, strong { - font-weight: bolder; + font-weight: bolder; } /* @@ -124,10 +138,11 @@ code, kbd, samp, pre { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; - /* 1 */ - font-size: 1em; - /* 2 */ + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', + 'Courier New', monospace; + /* 1 */ + font-size: 1em; + /* 2 */ } /* @@ -135,7 +150,7 @@ Add the correct font size in all browsers. */ small { - font-size: 80%; + font-size: 80%; } /* @@ -144,18 +159,18 @@ Prevent `sub` and `sup` elements from affecting the line height in all browsers. sub, sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; } sub { - bottom: -0.25em; + bottom: -0.25em; } sup { - top: -0.5em; + top: -0.5em; } /* @@ -165,12 +180,12 @@ sup { */ table { - text-indent: 0; - /* 1 */ - border-color: inherit; - /* 2 */ - border-collapse: collapse; - /* 3 */ + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ } /* @@ -184,18 +199,18 @@ input, optgroup, select, textarea { - font-family: inherit; - /* 1 */ - font-size: 100%; - /* 1 */ - line-height: inherit; - /* 1 */ - color: inherit; - /* 1 */ - margin: 0; - /* 2 */ - padding: 0; - /* 3 */ + font-family: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + line-height: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ } /* @@ -204,7 +219,7 @@ Remove the inheritance of text transform in Edge and Firefox. button, select { - text-transform: none; + text-transform: none; } /* @@ -216,12 +231,12 @@ button, [type='button'], [type='reset'], [type='submit'] { - -webkit-appearance: button; - /* 1 */ - background-color: transparent; - /* 2 */ - background-image: none; - /* 2 */ + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ } /* @@ -229,7 +244,7 @@ Use the modern Firefox focus style for all focusable elements. */ :-moz-focusring { - outline: auto; + outline: auto; } /* @@ -237,7 +252,7 @@ Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/ */ :-moz-ui-invalid { - box-shadow: none; + box-shadow: none; } /* @@ -245,7 +260,7 @@ Add the correct vertical alignment in Chrome and Firefox. */ progress { - vertical-align: baseline; + vertical-align: baseline; } /* @@ -254,7 +269,7 @@ Correct the cursor style of increment and decrement buttons in Safari. ::-webkit-inner-spin-button, ::-webkit-outer-spin-button { - height: auto; + height: auto; } /* @@ -263,10 +278,10 @@ Correct the cursor style of increment and decrement buttons in Safari. */ [type='search'] { - -webkit-appearance: textfield; - /* 1 */ - outline-offset: -2px; - /* 2 */ + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ } /* @@ -274,7 +289,7 @@ Remove the inner padding in Chrome and Safari on macOS. */ ::-webkit-search-decoration { - -webkit-appearance: none; + -webkit-appearance: none; } /* @@ -283,10 +298,10 @@ Remove the inner padding in Chrome and Safari on macOS. */ ::-webkit-file-upload-button { - -webkit-appearance: button; - /* 1 */ - font: inherit; - /* 2 */ + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ } /* @@ -294,7 +309,7 @@ Add the correct display in Chrome and Safari. */ summary { - display: list-item; + display: list-item; } /* @@ -314,24 +329,24 @@ hr, figure, p, pre { - margin: 0; + margin: 0; } fieldset { - margin: 0; - padding: 0; + margin: 0; + padding: 0; } legend { - padding: 0; + padding: 0; } ol, ul, menu { - list-style: none; - margin: 0; - padding: 0; + list-style: none; + margin: 0; + padding: 0; } /* @@ -339,7 +354,7 @@ Prevent resizing textareas horizontally by default. */ textarea { - resize: vertical; + resize: vertical; } /* @@ -347,26 +362,28 @@ textarea { 2. Set the default placeholder color to the user's configured gray 400 color. */ -input::-moz-placeholder, textarea::-moz-placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ +input::-moz-placeholder, +textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ } -input:-ms-input-placeholder, textarea:-ms-input-placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ } input::placeholder, textarea::placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ } /* @@ -374,8 +391,8 @@ Set the default cursor for buttons. */ button, -[role="button"] { - cursor: pointer; +[role='button'] { + cursor: pointer; } /* @@ -383,7 +400,7 @@ Make sure disabled buttons don't get the pointer cursor. */ :disabled { - cursor: default; + cursor: default; } /* @@ -400,10 +417,10 @@ audio, iframe, embed, object { - display: block; - /* 1 */ - vertical-align: middle; - /* 2 */ + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ } /* @@ -412,8 +429,8 @@ Constrain images and videos to the parent width and preserve their intrinsic asp img, video { - max-width: 100%; - height: auto; + max-width: 100%; + height: auto; } /* @@ -421,1346 +438,1437 @@ Ensure the default browser behavior of the `hidden` attribute. */ [hidden] { - display: none; + display: none; } -[type='text'],[type='email'],[type='url'],[type='password'],[type='number'],[type='date'],[type='datetime-local'],[type='month'],[type='search'],[type='tel'],[type='time'],[type='week'],[multiple],textarea,select { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background-color: #fff; - border-color: #6b7280; - border-width: 1px; - border-radius: 0px; - padding-top: 0.5rem; - padding-right: 0.75rem; - padding-bottom: 0.5rem; - padding-left: 0.75rem; - font-size: 1rem; - line-height: 1.5rem; - --tw-shadow: 0 0 #0000; +[type='text'], +[type='email'], +[type='url'], +[type='password'], +[type='number'], +[type='date'], +[type='datetime-local'], +[type='month'], +[type='search'], +[type='tel'], +[type='time'], +[type='week'], +[multiple], +textarea, +select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #6b7280; + border-width: 1px; + border-radius: 0px; + padding-top: 0.5rem; + padding-right: 0.75rem; + padding-bottom: 0.5rem; + padding-left: 0.75rem; + font-size: 1rem; + line-height: 1.5rem; + --tw-shadow: 0 0 #0000; } -[type='text']:focus, [type='email']:focus, [type='url']:focus, [type='password']:focus, [type='number']:focus, [type='date']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='week']:focus, [multiple]:focus, textarea:focus, select:focus { - outline: 2px solid transparent; - outline-offset: 2px; - --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #2563eb; - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - border-color: #2563eb; +[type='text']:focus, +[type='email']:focus, +[type='url']:focus, +[type='password']:focus, +[type='number']:focus, +[type='date']:focus, +[type='datetime-local']:focus, +[type='month']:focus, +[type='search']:focus, +[type='tel']:focus, +[type='time']:focus, +[type='week']:focus, +[multiple]:focus, +textarea:focus, +select:focus { + outline: 2px solid transparent; + outline-offset: 2px; + --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #2563eb; + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + border-color: #2563eb; } -input::-moz-placeholder, textarea::-moz-placeholder { - color: #6b7280; - opacity: 1; +input::-moz-placeholder, +textarea::-moz-placeholder { + color: #6b7280; + opacity: 1; } -input:-ms-input-placeholder, textarea:-ms-input-placeholder { - color: #6b7280; - opacity: 1; +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: #6b7280; + opacity: 1; } -input::placeholder,textarea::placeholder { - color: #6b7280; - opacity: 1; +input::placeholder, +textarea::placeholder { + color: #6b7280; + opacity: 1; } ::-webkit-datetime-edit-fields-wrapper { - padding: 0; + padding: 0; } ::-webkit-date-and-time-value { - min-height: 1.5em; + min-height: 1.5em; } -::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field { - padding-top: 0; - padding-bottom: 0; +::-webkit-datetime-edit, +::-webkit-datetime-edit-year-field, +::-webkit-datetime-edit-month-field, +::-webkit-datetime-edit-day-field, +::-webkit-datetime-edit-hour-field, +::-webkit-datetime-edit-minute-field, +::-webkit-datetime-edit-second-field, +::-webkit-datetime-edit-millisecond-field, +::-webkit-datetime-edit-meridiem-field { + padding-top: 0; + padding-bottom: 0; } select { - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); - background-position: right 0.5rem center; - background-repeat: no-repeat; - background-size: 1.5em 1.5em; - padding-right: 2.5rem; - -webkit-print-color-adjust: exact; - color-adjust: exact; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); + background-position: right 0.5rem center; + background-repeat: no-repeat; + background-size: 1.5em 1.5em; + padding-right: 2.5rem; + -webkit-print-color-adjust: exact; + color-adjust: exact; } [multiple] { - background-image: initial; - background-position: initial; - background-repeat: unset; - background-size: initial; - padding-right: 0.75rem; - -webkit-print-color-adjust: unset; - color-adjust: unset; + background-image: initial; + background-position: initial; + background-repeat: unset; + background-size: initial; + padding-right: 0.75rem; + -webkit-print-color-adjust: unset; + color-adjust: unset; } -[type='checkbox'],[type='radio'] { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - padding: 0; - -webkit-print-color-adjust: exact; - color-adjust: exact; - display: inline-block; - vertical-align: middle; - background-origin: border-box; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - flex-shrink: 0; - height: 1rem; - width: 1rem; - color: #2563eb; - background-color: #fff; - border-color: #6b7280; - border-width: 1px; - --tw-shadow: 0 0 #0000; +[type='checkbox'], +[type='radio'] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + padding: 0; + -webkit-print-color-adjust: exact; + color-adjust: exact; + display: inline-block; + vertical-align: middle; + background-origin: border-box; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + flex-shrink: 0; + height: 1rem; + width: 1rem; + color: #2563eb; + background-color: #fff; + border-color: #6b7280; + border-width: 1px; + --tw-shadow: 0 0 #0000; } [type='checkbox'] { - border-radius: 0px; + border-radius: 0px; } [type='radio'] { - border-radius: 100%; + border-radius: 100%; } -[type='checkbox']:focus,[type='radio']:focus { - outline: 2px solid transparent; - outline-offset: 2px; - --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); - --tw-ring-offset-width: 2px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #2563eb; - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); +[type='checkbox']:focus, +[type='radio']:focus { + outline: 2px solid transparent; + outline-offset: 2px; + --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); + --tw-ring-offset-width: 2px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #2563eb; + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } -[type='checkbox']:checked,[type='radio']:checked { - border-color: transparent; - background-color: currentColor; - background-size: 100% 100%; - background-position: center; - background-repeat: no-repeat; +[type='checkbox']:checked, +[type='radio']:checked { + border-color: transparent; + background-color: currentColor; + background-size: 100% 100%; + background-position: center; + background-repeat: no-repeat; } [type='checkbox']:checked { - background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); } [type='radio']:checked { - background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); } -[type='checkbox']:checked:hover,[type='checkbox']:checked:focus,[type='radio']:checked:hover,[type='radio']:checked:focus { - border-color: transparent; - background-color: currentColor; +[type='checkbox']:checked:hover, +[type='checkbox']:checked:focus, +[type='radio']:checked:hover, +[type='radio']:checked:focus { + border-color: transparent; + background-color: currentColor; } [type='checkbox']:indeterminate { - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e"); - border-color: transparent; - background-color: currentColor; - background-size: 100% 100%; - background-position: center; - background-repeat: no-repeat; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e"); + border-color: transparent; + background-color: currentColor; + background-size: 100% 100%; + background-position: center; + background-repeat: no-repeat; } -[type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus { - border-color: transparent; - background-color: currentColor; +[type='checkbox']:indeterminate:hover, +[type='checkbox']:indeterminate:focus { + border-color: transparent; + background-color: currentColor; } [type='file'] { - background: unset; - border-color: inherit; - border-width: 0; - border-radius: 0; - padding: 0; - font-size: unset; - line-height: inherit; + background: unset; + border-color: inherit; + border-width: 0; + border-radius: 0; + padding: 0; + font-size: unset; + line-height: inherit; } [type='file']:focus { - outline: 1px auto -webkit-focus-ring-color; + outline: 1px auto -webkit-focus-ring-color; } body { - font-family: Poppins, sans-serif; + font-family: Poppins, sans-serif; } -h1, h2, h3, h4, h5, h6 { - font-family: Roboto, sans-serif; +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: Roboto, sans-serif; } -*, ::before, ::after { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; +*, +::before, +::after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; } .container { - width: 100%; - margin-right: auto; - margin-left: auto; - padding-right: 1rem; - padding-left: 1rem; + width: 100%; + margin-right: auto; + margin-left: auto; + padding-right: 1rem; + padding-left: 1rem; } @media (min-width: 640px) { - .container { - max-width: 640px; - } + .container { + max-width: 640px; + } } @media (min-width: 768px) { - .container { - max-width: 768px; - } + .container { + max-width: 768px; + } } @media (min-width: 1024px) { - .container { - max-width: 1024px; - } + .container { + max-width: 1024px; + } } @media (min-width: 1280px) { - .container { - max-width: 1280px; - } + .container { + max-width: 1280px; + } } @media (min-width: 1536px) { - .container { - max-width: 1536px; - } + .container { + max-width: 1536px; + } } .size-selector input:checked + label { - --tw-bg-opacity: 1; - background-color: rgb(253 61 87 / var(--tw-bg-opacity)); - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(253 61 87 / var(--tw-bg-opacity)); + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); } .color-selector input:checked + label { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); - --tw-ring-opacity: 1; - --tw-ring-color: rgb(253 61 87 / var(--tw-ring-opacity)); + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + --tw-ring-opacity: 1; + --tw-ring-color: rgb(253 61 87 / var(--tw-ring-opacity)); } .input-box { - display: block; - width: 100%; - border-radius: 0.25rem; - border-width: 1px; - --tw-border-opacity: 1; - border-color: rgb(209 213 219 / var(--tw-border-opacity)); - padding-left: 1rem; - padding-right: 1rem; - padding-top: 0.75rem; - padding-bottom: 0.75rem; - font-size: 0.875rem; - line-height: 1.25rem; - --tw-text-opacity: 1; - color: rgb(75 85 99 / var(--tw-text-opacity)); + display: block; + width: 100%; + border-radius: 0.25rem; + border-width: 1px; + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity)); + padding-left: 1rem; + padding-right: 1rem; + padding-top: 0.75rem; + padding-bottom: 0.75rem; + font-size: 0.875rem; + line-height: 1.25rem; + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); } .input-box::-moz-placeholder { - --tw-placeholder-opacity: 1; - color: rgb(156 163 175 / var(--tw-placeholder-opacity)); + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity)); } .input-box:-ms-input-placeholder { - --tw-placeholder-opacity: 1; - color: rgb(156 163 175 / var(--tw-placeholder-opacity)); + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity)); } .input-box::placeholder { - --tw-placeholder-opacity: 1; - color: rgb(156 163 175 / var(--tw-placeholder-opacity)); + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity)); } .input-box:focus { - --tw-border-opacity: 1; - border-color: rgb(253 61 87 / var(--tw-border-opacity)); - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + --tw-border-opacity: 1; + border-color: rgb(253 61 87 / var(--tw-border-opacity)); + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); } .invisible { - visibility: hidden; + visibility: hidden; } .absolute { - position: absolute; + position: absolute; } .relative { - position: relative; + position: relative; } .inset-0 { - top: 0px; - right: 0px; - bottom: 0px; - left: 0px; + top: 0px; + right: 0px; + bottom: 0px; + left: 0px; } .left-4 { - left: 1rem; + left: 1rem; } .top-3 { - top: 0.75rem; + top: 0.75rem; } .right-0 { - right: 0px; + right: 0px; } .-top-1 { - top: -0.25rem; + top: -0.25rem; } .-right-3 { - right: -0.75rem; + right: -0.75rem; } .left-0 { - left: 0px; + left: 0px; } .top-full { - top: 100%; + top: 100%; } .-left-8 { - left: -2rem; + left: -2rem; } .top-0 { - top: 0px; + top: 0px; } .z-10 { - z-index: 10; + z-index: 10; } .col-span-1 { - grid-column: span 1 / span 1; + grid-column: span 1 / span 1; } .col-span-2 { - grid-column: span 2 / span 2; + grid-column: span 2 / span 2; } .col-span-3 { - grid-column: span 3 / span 3; + grid-column: span 3 / span 3; } .col-span-9 { - grid-column: span 9 / span 9; + grid-column: span 9 / span 9; } .col-span-8 { - grid-column: span 8 / span 8; + grid-column: span 8 / span 8; } .col-span-4 { - grid-column: span 4 / span 4; + grid-column: span 4 / span 4; } .mx-auto { - margin-left: auto; - margin-right: auto; + margin-left: auto; + margin-right: auto; } .mx-3 { - margin-left: 0.75rem; - margin-right: 0.75rem; + margin-left: 0.75rem; + margin-right: 0.75rem; } .ml-2 { - margin-left: 0.5rem; + margin-left: 0.5rem; } .ml-6 { - margin-left: 1.5rem; + margin-left: 1.5rem; } .mb-4 { - margin-bottom: 1rem; + margin-bottom: 1rem; } .mt-12 { - margin-top: 3rem; + margin-top: 3rem; } .mb-6 { - margin-bottom: 1.5rem; + margin-bottom: 1.5rem; } .mb-2 { - margin-bottom: 0.5rem; + margin-bottom: 0.5rem; } .mb-1 { - margin-bottom: 0.25rem; + margin-bottom: 0.25rem; } .ml-3 { - margin-left: 0.75rem; + margin-left: 0.75rem; } .mr-2 { - margin-right: 0.5rem; + margin-right: 0.5rem; } .mt-4 { - margin-top: 1rem; + margin-top: 1rem; } .mt-6 { - margin-top: 1.5rem; + margin-top: 1.5rem; } .mt-1 { - margin-top: 0.25rem; + margin-top: 0.25rem; } .mt-2 { - margin-top: 0.5rem; + margin-top: 0.5rem; } .mb-3 { - margin-bottom: 0.75rem; + margin-bottom: 0.75rem; } .ml-auto { - margin-left: auto; + margin-left: auto; } .block { - display: block; + display: block; } .flex { - display: flex; + display: flex; } .table { - display: table; + display: table; } .grid { - display: grid; + display: grid; } .hidden { - display: none; + display: none; } .h-5 { - height: 1.25rem; + height: 1.25rem; } .h-12 { - height: 3rem; + height: 3rem; } .h-8 { - height: 2rem; + height: 2rem; } .h-14 { - height: 3.5rem; + height: 3.5rem; } .h-3 { - height: 0.75rem; + height: 0.75rem; } .h-6 { - height: 1.5rem; + height: 1.5rem; } .h-9 { - height: 2.25rem; + height: 2.25rem; } .w-32 { - width: 8rem; + width: 8rem; } .w-full { - width: 100%; + width: 100%; } .w-5 { - width: 1.25rem; + width: 1.25rem; } .w-10\/12 { - width: 83.333333%; + width: 83.333333%; } .w-12 { - width: 3rem; + width: 3rem; } .w-9 { - width: 2.25rem; + width: 2.25rem; } .w-14 { - width: 3.5rem; + width: 3.5rem; } .w-3 { - width: 0.75rem; + width: 0.75rem; } .w-1\/2 { - width: 50%; + width: 50%; } .w-6 { - width: 1.5rem; + width: 1.5rem; } .w-max { - width: -webkit-max-content; - width: -moz-max-content; - width: max-content; + width: -webkit-max-content; + width: -moz-max-content; + width: max-content; } .w-8 { - width: 2rem; + width: 2rem; } .w-3\/5 { - width: 60%; + width: 60%; } .w-40 { - width: 10rem; + width: 10rem; } .w-44 { - width: 11rem; + width: 11rem; } .w-10 { - width: 2.5rem; + width: 2.5rem; } .w-28 { - width: 7rem; + width: 7rem; } .w-1\/3 { - width: 33.333333%; + width: 33.333333%; } .max-w-xl { - max-width: 36rem; + max-width: 36rem; } .max-w-lg { - max-width: 32rem; + max-width: 32rem; } .flex-shrink-0 { - flex-shrink: 0; + flex-shrink: 0; } .flex-grow { - flex-grow: 1; + flex-grow: 1; } .table-auto { - table-layout: auto; + table-layout: auto; } .border-collapse { - border-collapse: collapse; + border-collapse: collapse; } .cursor-pointer { - cursor: pointer; + cursor: pointer; } .cursor-not-allowed { - cursor: not-allowed; + cursor: not-allowed; } .select-none { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } .grid-cols-1 { - grid-template-columns: repeat(1, minmax(0, 1fr)); + grid-template-columns: repeat(1, minmax(0, 1fr)); } .grid-cols-3 { - grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-template-columns: repeat(3, minmax(0, 1fr)); } .grid-cols-2 { - grid-template-columns: repeat(2, minmax(0, 1fr)); + grid-template-columns: repeat(2, minmax(0, 1fr)); } .grid-cols-12 { - grid-template-columns: repeat(12, minmax(0, 1fr)); + grid-template-columns: repeat(12, minmax(0, 1fr)); } .grid-cols-5 { - grid-template-columns: repeat(5, minmax(0, 1fr)); + grid-template-columns: repeat(5, minmax(0, 1fr)); } .grid-cols-4 { - grid-template-columns: repeat(4, minmax(0, 1fr)); + grid-template-columns: repeat(4, minmax(0, 1fr)); } .items-start { - align-items: flex-start; + align-items: flex-start; } .items-center { - align-items: center; + align-items: center; } .items-baseline { - align-items: baseline; + align-items: baseline; } .justify-center { - justify-content: center; + justify-content: center; } .justify-between { - justify-content: space-between; + justify-content: space-between; } .gap-6 { - gap: 1.5rem; + gap: 1.5rem; } .gap-5 { - gap: 1.25rem; + gap: 1.25rem; } .gap-3 { - gap: 0.75rem; + gap: 0.75rem; } .gap-2 { - gap: 0.5rem; + gap: 0.5rem; } .gap-1 { - gap: 0.25rem; + gap: 0.25rem; } .gap-4 { - gap: 1rem; + gap: 1rem; } .gap-8 { - gap: 2rem; + gap: 2rem; } .space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(1rem * var(--tw-space-x-reverse)); - margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); + --tw-space-x-reverse: 0; + margin-right: calc(1rem * var(--tw-space-x-reverse)); + margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); } .space-x-6 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(1.5rem * var(--tw-space-x-reverse)); - margin-left: calc(1.5rem * calc(1 - var(--tw-space-x-reverse))); + --tw-space-x-reverse: 0; + margin-right: calc(1.5rem * var(--tw-space-x-reverse)); + margin-left: calc(1.5rem * calc(1 - var(--tw-space-x-reverse))); } .space-x-2 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(0.5rem * var(--tw-space-x-reverse)); - margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); + --tw-space-x-reverse: 0; + margin-right: calc(0.5rem * var(--tw-space-x-reverse)); + margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); } .space-y-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(1rem * var(--tw-space-y-reverse)); + --tw-space-y-reverse: 0; + margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(1rem * var(--tw-space-y-reverse)); } .space-x-5 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(1.25rem * var(--tw-space-x-reverse)); - margin-left: calc(1.25rem * calc(1 - var(--tw-space-x-reverse))); + --tw-space-x-reverse: 0; + margin-right: calc(1.25rem * var(--tw-space-x-reverse)); + margin-left: calc(1.25rem * calc(1 - var(--tw-space-x-reverse))); } .space-y-1 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.25rem * var(--tw-space-y-reverse)); + --tw-space-y-reverse: 0; + margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(0.25rem * var(--tw-space-y-reverse)); } .space-y-8 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(2rem * var(--tw-space-y-reverse)); + --tw-space-y-reverse: 0; + margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(2rem * var(--tw-space-y-reverse)); } .space-y-2 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.5rem * var(--tw-space-y-reverse)); + --tw-space-y-reverse: 0; + margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(0.5rem * var(--tw-space-y-reverse)); } .space-y-5 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(1.25rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(1.25rem * var(--tw-space-y-reverse)); + --tw-space-y-reverse: 0; + margin-top: calc(1.25rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(1.25rem * var(--tw-space-y-reverse)); } .divide-y > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); } .divide-x > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-right-width: calc(1px * var(--tw-divide-x-reverse)); - border-left-width: calc(1px * calc(1 - var(--tw-divide-x-reverse))); + --tw-divide-x-reverse: 0; + border-right-width: calc(1px * var(--tw-divide-x-reverse)); + border-left-width: calc(1px * calc(1 - var(--tw-divide-x-reverse))); } .divide-dashed > :not([hidden]) ~ :not([hidden]) { - border-style: dashed; + border-style: dashed; } .divide-gray-300 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 1; - border-color: rgb(209 213 219 / var(--tw-divide-opacity)); + --tw-divide-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-divide-opacity)); } .divide-gray-200 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 1; - border-color: rgb(229 231 235 / var(--tw-divide-opacity)); + --tw-divide-opacity: 1; + border-color: rgb(229 231 235 / var(--tw-divide-opacity)); } .overflow-hidden { - overflow: hidden; + overflow: hidden; } .rounded-full { - border-radius: 9999px; + border-radius: 9999px; } .rounded-md { - border-radius: 0.375rem; + border-radius: 0.375rem; } .rounded-sm { - border-radius: 0.125rem; + border-radius: 0.125rem; } .rounded { - border-radius: 0.25rem; + border-radius: 0.25rem; } .rounded-l-md { - border-top-left-radius: 0.375rem; - border-bottom-left-radius: 0.375rem; + border-top-left-radius: 0.375rem; + border-bottom-left-radius: 0.375rem; } .rounded-r-md { - border-top-right-radius: 0.375rem; - border-bottom-right-radius: 0.375rem; + border-top-right-radius: 0.375rem; + border-bottom-right-radius: 0.375rem; } .rounded-b { - border-bottom-right-radius: 0.25rem; - border-bottom-left-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; } .border { - border-width: 1px; + border-width: 1px; } .border-r-0 { - border-right-width: 0px; + border-right-width: 0px; } .border-t { - border-top-width: 1px; + border-top-width: 1px; } .border-b { - border-bottom-width: 1px; + border-bottom-width: 1px; } .border-b-2 { - border-bottom-width: 2px; + border-bottom-width: 2px; } .border-primary { - --tw-border-opacity: 1; - border-color: rgb(253 61 87 / var(--tw-border-opacity)); + --tw-border-opacity: 1; + border-color: rgb(253 61 87 / var(--tw-border-opacity)); } .border-gray-100 { - --tw-border-opacity: 1; - border-color: rgb(243 244 246 / var(--tw-border-opacity)); + --tw-border-opacity: 1; + border-color: rgb(243 244 246 / var(--tw-border-opacity)); } .border-gray-200 { - --tw-border-opacity: 1; - border-color: rgb(229 231 235 / var(--tw-border-opacity)); + --tw-border-opacity: 1; + border-color: rgb(229 231 235 / var(--tw-border-opacity)); } .border-gray-300 { - --tw-border-opacity: 1; - border-color: rgb(209 213 219 / var(--tw-border-opacity)); + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity)); } .border-red-400 { - --tw-border-opacity: 1; - border-color: rgb(248 113 113 / var(--tw-border-opacity)); + --tw-border-opacity: 1; + border-color: rgb(248 113 113 / var(--tw-border-opacity)); } .bg-white { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); } .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(253 61 87 / var(--tw-bg-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(253 61 87 / var(--tw-bg-opacity)); } .bg-gray-800 { - --tw-bg-opacity: 1; - background-color: rgb(31 41 55 / var(--tw-bg-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(31 41 55 / var(--tw-bg-opacity)); } .bg-black { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); } .bg-blue-800 { - --tw-bg-opacity: 1; - background-color: rgb(30 64 175 / var(--tw-bg-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(30 64 175 / var(--tw-bg-opacity)); } .bg-red-600 { - --tw-bg-opacity: 1; - background-color: rgb(220 38 38 / var(--tw-bg-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(220 38 38 / var(--tw-bg-opacity)); } .bg-red-400 { - --tw-bg-opacity: 1; - background-color: rgb(248 113 113 / var(--tw-bg-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(248 113 113 / var(--tw-bg-opacity)); } .bg-opacity-40 { - --tw-bg-opacity: 0.4; + --tw-bg-opacity: 0.4; } .bg-cover { - background-size: cover; + background-size: cover; } .bg-center { - background-position: center; + background-position: center; } .bg-no-repeat { - background-repeat: no-repeat; + background-repeat: no-repeat; } .object-contain { - -o-object-fit: contain; - object-fit: contain; + -o-object-fit: contain; + object-fit: contain; } .object-cover { - -o-object-fit: cover; - object-fit: cover; + -o-object-fit: cover; + object-fit: cover; } .p-1 { - padding: 0.25rem; + padding: 0.25rem; } .p-4 { - padding: 1rem; + padding: 1rem; } .py-4 { - padding-top: 1rem; - padding-bottom: 1rem; + padding-top: 1rem; + padding-bottom: 1rem; } .py-3 { - padding-top: 0.75rem; - padding-bottom: 0.75rem; + padding-top: 0.75rem; + padding-bottom: 0.75rem; } .px-8 { - padding-left: 2rem; - padding-right: 2rem; + padding-left: 2rem; + padding-right: 2rem; } .px-6 { - padding-left: 1.5rem; - padding-right: 1.5rem; + padding-left: 1.5rem; + padding-right: 1.5rem; } .py-5 { - padding-top: 1.25rem; - padding-bottom: 1.25rem; + padding-top: 1.25rem; + padding-bottom: 1.25rem; } .py-36 { - padding-top: 9rem; - padding-bottom: 9rem; + padding-top: 9rem; + padding-bottom: 9rem; } .py-16 { - padding-top: 4rem; - padding-bottom: 4rem; + padding-top: 4rem; + padding-bottom: 4rem; } .px-3 { - padding-left: 0.75rem; - padding-right: 0.75rem; + padding-left: 0.75rem; + padding-right: 0.75rem; } .py-6 { - padding-top: 1.5rem; - padding-bottom: 1.5rem; + padding-top: 1.5rem; + padding-bottom: 1.5rem; } .px-4 { - padding-left: 1rem; - padding-right: 1rem; + padding-left: 1rem; + padding-right: 1rem; } .py-1 { - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding-top: 0.25rem; + padding-bottom: 0.25rem; } .py-7 { - padding-top: 1.75rem; - padding-bottom: 1.75rem; + padding-top: 1.75rem; + padding-bottom: 1.75rem; } .py-2 { - padding-top: 0.5rem; - padding-bottom: 0.5rem; + padding-top: 0.5rem; + padding-bottom: 0.5rem; } .pl-12 { - padding-left: 3rem; + padding-left: 3rem; } .pr-3 { - padding-right: 0.75rem; + padding-right: 0.75rem; } .pb-16 { - padding-bottom: 4rem; + padding-bottom: 4rem; } .pt-4 { - padding-top: 1rem; + padding-top: 1rem; } .pb-3 { - padding-bottom: 0.75rem; + padding-bottom: 0.75rem; } .pt-16 { - padding-top: 4rem; + padding-top: 4rem; } .pb-12 { - padding-bottom: 3rem; + padding-bottom: 3rem; } .pl-8 { - padding-left: 2rem; + padding-left: 2rem; } .pt-6 { - padding-top: 1.5rem; + padding-top: 1.5rem; } .pb-8 { - padding-bottom: 2rem; + padding-bottom: 2rem; } .pb-5 { - padding-bottom: 1.25rem; + padding-bottom: 1.25rem; } .pt-5 { - padding-top: 1.25rem; + padding-top: 1.25rem; } .pb-7 { - padding-bottom: 1.75rem; + padding-bottom: 1.75rem; } .pb-6 { - padding-bottom: 1.5rem; + padding-bottom: 1.5rem; } .text-left { - text-align: left; + text-align: left; } .text-center { - text-align: center; + text-align: center; } .font-roboto { - font-family: Roboto, sans-serif; + font-family: Roboto, sans-serif; } .text-lg { - font-size: 1.125rem; - line-height: 1.75rem; + font-size: 1.125rem; + line-height: 1.75rem; } .text-2xl { - font-size: 1.5rem; - line-height: 2rem; + font-size: 1.5rem; + line-height: 2rem; } .text-xs { - font-size: 0.75rem; - line-height: 1rem; + font-size: 0.75rem; + line-height: 1rem; } .text-sm { - font-size: 0.875rem; - line-height: 1.25rem; + font-size: 0.875rem; + line-height: 1.25rem; } .text-6xl { - font-size: 3.75rem; - line-height: 1; + font-size: 3.75rem; + line-height: 1; } .text-xl { - font-size: 1.25rem; - line-height: 1.75rem; + font-size: 1.25rem; + line-height: 1.75rem; } .text-base { - font-size: 1rem; - line-height: 1.5rem; + font-size: 1rem; + line-height: 1.5rem; } .text-3xl { - font-size: 1.875rem; - line-height: 2.25rem; + font-size: 1.875rem; + line-height: 2.25rem; } .font-medium { - font-weight: 500; + font-weight: 500; } .font-semibold { - font-weight: 600; + font-weight: 600; } .uppercase { - text-transform: uppercase; + text-transform: uppercase; } .capitalize { - text-transform: capitalize; + text-transform: capitalize; } .leading-3 { - line-height: .75rem; + line-height: 0.75rem; } .tracking-wider { - letter-spacing: 0.05em; + letter-spacing: 0.05em; } .text-gray-400 { - --tw-text-opacity: 1; - color: rgb(156 163 175 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); } .text-white { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); } .text-gray-700 { - --tw-text-opacity: 1; - color: rgb(55 65 81 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(55 65 81 / var(--tw-text-opacity)); } .text-gray-600 { - --tw-text-opacity: 1; - color: rgb(75 85 99 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); } .text-gray-200 { - --tw-text-opacity: 1; - color: rgb(229 231 235 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(229 231 235 / var(--tw-text-opacity)); } .text-gray-800 { - --tw-text-opacity: 1; - color: rgb(31 41 55 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(31 41 55 / var(--tw-text-opacity)); } .text-gray-500 { - --tw-text-opacity: 1; - color: rgb(107 114 128 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(107 114 128 / var(--tw-text-opacity)); } .text-primary { - --tw-text-opacity: 1; - color: rgb(253 61 87 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(253 61 87 / var(--tw-text-opacity)); } .text-yellow-400 { - --tw-text-opacity: 1; - color: rgb(250 204 21 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(250 204 21 / var(--tw-text-opacity)); } .text-green-600 { - --tw-text-opacity: 1; - color: rgb(22 163 74 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(22 163 74 / var(--tw-text-opacity)); } .text-red-600 { - --tw-text-opacity: 1; - color: rgb(220 38 38 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(220 38 38 / var(--tw-text-opacity)); } .line-through { - -webkit-text-decoration-line: line-through; - text-decoration-line: line-through; + -webkit-text-decoration-line: line-through; + text-decoration-line: line-through; } .placeholder-gray-400::-moz-placeholder { - --tw-placeholder-opacity: 1; - color: rgb(156 163 175 / var(--tw-placeholder-opacity)); + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity)); } .placeholder-gray-400:-ms-input-placeholder { - --tw-placeholder-opacity: 1; - color: rgb(156 163 175 / var(--tw-placeholder-opacity)); + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity)); } .placeholder-gray-400::placeholder { - --tw-placeholder-opacity: 1; - color: rgb(156 163 175 / var(--tw-placeholder-opacity)); + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity)); } .opacity-0 { - opacity: 0; + opacity: 0; } .shadow-sm { - --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); - --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); } .shadow-md { - --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); } .shadow { - --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); } .transition { - transition-property: color, background-color, border-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-text-decoration-color, -webkit-backdrop-filter; - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-text-decoration-color, -webkit-backdrop-filter; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; + transition-property: + color, + background-color, + border-color, + fill, + stroke, + opacity, + box-shadow, + transform, + filter, + -webkit-text-decoration-color, + -webkit-backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, + opacity, box-shadow, transform, filter, backdrop-filter; + transition-property: + color, + background-color, + border-color, + text-decoration-color, + fill, + stroke, + opacity, + box-shadow, + transform, + filter, + backdrop-filter, + -webkit-text-decoration-color, + -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; } .duration-300 { - transition-duration: 300ms; + transition-duration: 300ms; } .hover\:bg-transparent:hover { - background-color: transparent; + background-color: transparent; } .hover\:bg-gray-100:hover { - --tw-bg-opacity: 1; - background-color: rgb(243 244 246 / var(--tw-bg-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); } .hover\:bg-gray-800:hover { - --tw-bg-opacity: 1; - background-color: rgb(31 41 55 / var(--tw-bg-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(31 41 55 / var(--tw-bg-opacity)); } .hover\:bg-blue-700:hover { - --tw-bg-opacity: 1; - background-color: rgb(29 78 216 / var(--tw-bg-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(29 78 216 / var(--tw-bg-opacity)); } .hover\:bg-red-500:hover { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + --tw-bg-opacity: 1; + background-color: rgb(239 68 68 / var(--tw-bg-opacity)); } .hover\:text-primary:hover { - --tw-text-opacity: 1; - color: rgb(253 61 87 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(253 61 87 / var(--tw-text-opacity)); } .hover\:text-white:hover { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); } .hover\:text-gray-500:hover { - --tw-text-opacity: 1; - color: rgb(107 114 128 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(107 114 128 / var(--tw-text-opacity)); } .hover\:text-gray-900:hover { - --tw-text-opacity: 1; - color: rgb(17 24 39 / var(--tw-text-opacity)); + --tw-text-opacity: 1; + color: rgb(17 24 39 / var(--tw-text-opacity)); } .focus\:border-primary:focus { - --tw-border-opacity: 1; - border-color: rgb(253 61 87 / var(--tw-border-opacity)); + --tw-border-opacity: 1; + border-color: rgb(253 61 87 / var(--tw-border-opacity)); } .focus\:outline-none:focus { - outline: 2px solid transparent; - outline-offset: 2px; + outline: 2px solid transparent; + outline-offset: 2px; } .focus\:ring-0:focus { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); } .focus\:ring-primary:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(253 61 87 / var(--tw-ring-opacity)); + --tw-ring-opacity: 1; + --tw-ring-color: rgb(253 61 87 / var(--tw-ring-opacity)); } .group:hover .group-hover\:visible { - visibility: visible; + visibility: visible; } .group:hover .group-hover\:bg-opacity-60 { - --tw-bg-opacity: 0.6; + --tw-bg-opacity: 0.6; } .group:hover .group-hover\:opacity-100 { - opacity: 1; + opacity: 1; } @media (min-width: 768px) { - .md\:block { - display: block; - } + .md\:block { + display: block; + } - .md\:flex { - display: flex; - } + .md\:flex { + display: flex; + } - .md\:grid-cols-3 { - grid-template-columns: repeat(3, minmax(0, 1fr)); - } + .md\:grid-cols-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } - .md\:grid-cols-4 { - grid-template-columns: repeat(4, minmax(0, 1fr)); - } + .md\:grid-cols-4 { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } - .md\:gap-8 { - gap: 2rem; - } + .md\:gap-8 { + gap: 2rem; + } - .md\:pl-12 { - padding-left: 3rem; - } + .md\:pl-12 { + padding-left: 3rem; + } } diff --git a/examples/server-islands/public/assets/images/favicon/site.webmanifest b/examples/server-islands/public/assets/images/favicon/site.webmanifest index 45dc8a2065..52a2fe3f61 100644 --- a/examples/server-islands/public/assets/images/favicon/site.webmanifest +++ b/examples/server-islands/public/assets/images/favicon/site.webmanifest @@ -1 +1,11 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file +{ + "name": "", + "short_name": "", + "icons": [ + { "src": "/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" }, + { "src": "/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/examples/server-islands/src/base.css b/examples/server-islands/src/base.css index 90e97c7ff1..d0ae7cae47 100644 --- a/examples/server-islands/src/base.css +++ b/examples/server-islands/src/base.css @@ -1,32 +1,32 @@ -@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap"); +@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap'); @tailwind base; @tailwind components; @tailwind utilities; @layer base { - body { - @apply font-poppins; - } - h1, - h2, - h3, - h4, - h5, - h6 { - @apply font-roboto; - } + body { + @apply font-poppins; + } + h1, + h2, + h3, + h4, + h5, + h6 { + @apply font-roboto; + } } @layer components { - .size-selector input:checked + label { - @apply bg-primary text-white; - } - .color-selector input:checked + label { - @apply ring-2 ring-primary; - } + .size-selector input:checked + label { + @apply bg-primary text-white; + } + .color-selector input:checked + label { + @apply ring-2 ring-primary; + } - .input-box { - @apply block w-full border border-gray-300 px-4 py-3 text-gray-600 text-sm rounded placeholder-gray-400 focus:border-primary focus:ring-0; - } + .input-box { + @apply block w-full border border-gray-300 px-4 py-3 text-gray-600 text-sm rounded placeholder-gray-400 focus:border-primary focus:ring-0; + } } diff --git a/examples/server-islands/src/components/PersonalBar.astro b/examples/server-islands/src/components/PersonalBar.astro index 197ade1297..afff16d607 100644 --- a/examples/server-islands/src/components/PersonalBar.astro +++ b/examples/server-islands/src/components/PersonalBar.astro @@ -5,28 +5,32 @@ const { placeholder } = Astro.props; let wishlist = 0; let cart = 0; -if(!placeholder) { - await new Promise(resolve => setTimeout(resolve, 3000)); +if (!placeholder) { + await new Promise((resolve) => setTimeout(resolve, 3000)); } --- + <a href="#" class="text-center text-gray-700 hover:text-primary transition relative"> <div class="text-2xl"> - <i class="fa-regular fa-heart"></i> + <i class="fa-regular fa-heart"></i> </div> <div class="text-xs leading-3">Wishlist</div> <div - class="absolute right-0 -top-1 w-5 h-5 rounded-full flex items-center justify-center bg-primary text-white text-xs">{ wishlist }</div> + class="absolute right-0 -top-1 w-5 h-5 rounded-full flex items-center justify-center bg-primary text-white text-xs" + > + {wishlist} + </div> </a> <a href="#" class="text-center text-gray-700 hover:text-primary transition relative"> <div class="text-2xl"> - <i class="fa-solid fa-bag-shopping"></i> + <i class="fa-solid fa-bag-shopping"></i> </div> <div class="text-xs leading-3">Cart</div> <CartCount client:load count={cart} /> </a> <a href="#" class="text-center text-gray-700 hover:text-primary transition relative"> <div class="text-2xl"> - <i class="fa-regular fa-user"></i> + <i class="fa-regular fa-user"></i> </div> <div class="text-xs leading-3">Account</div> </a> diff --git a/examples/server-islands/src/pages/index.astro b/examples/server-islands/src/pages/index.astro index a36d5df05f..b12fb0c5e7 100644 --- a/examples/server-islands/src/pages/index.astro +++ b/examples/server-islands/src/pages/index.astro @@ -4,540 +4,675 @@ import AddToCart from '../components/AddToCart'; import PersonalBar from '../components/PersonalBar.astro'; import '@fortawesome/fontawesome-free/css/all.min.css'; --- -<!DOCTYPE html> + +<!doctype html> <html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Product - Ecommerce Tailwind</title> -<head> - <meta charset="UTF-8"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Product - Ecommerce Tailwind</title> + <link rel="shortcut icon" href="../assets/images/favicon/favicon.ico" type="image/x-icon" /> - <link rel="shortcut icon" href="../assets/images/favicon/favicon.ico" type="image/x-icon"> + <link rel="preconnect" href="https://fonts.googleapis.com" /> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> + <link + href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&family=Roboto:wght@400;500;700&display=swap" + rel="stylesheet" + /> + </head> - <link rel="preconnect" href="https://fonts.googleapis.com"> - <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> - <link - href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&family=Roboto:wght@400;500;700&display=swap" - rel="stylesheet"> -</head> + <body> + <!-- header --> + <header class="py-4 shadow-sm bg-white"> + <div class="container flex items-center justify-between"> + <a href="index.html"> + <img src="../assets/images/logo.svg" alt="Logo" class="w-32" /> + </a> -<body> - <!-- header --> - <header class="py-4 shadow-sm bg-white"> - <div class="container flex items-center justify-between"> - <a href="index.html"> - <img src="../assets/images/logo.svg" alt="Logo" class="w-32"> - </a> + <div class="w-full max-w-xl relative flex"> + <span class="absolute left-4 top-3 text-lg text-gray-400"> + <i class="fa-solid fa-magnifying-glass"></i> + </span> + <input + type="text" + name="search" + id="search" + class="w-full border border-primary border-r-0 pl-12 py-3 pr-3 rounded-l-md focus:outline-none" + placeholder="search" + /> + <button + class="bg-primary border border-primary text-white px-8 rounded-r-md hover:bg-transparent hover:text-primary transition" + >Search</button + > + </div> - <div class="w-full max-w-xl relative flex"> - <span class="absolute left-4 top-3 text-lg text-gray-400"> - <i class="fa-solid fa-magnifying-glass"></i> - </span> - <input type="text" name="search" id="search" - class="w-full border border-primary border-r-0 pl-12 py-3 pr-3 rounded-l-md focus:outline-none" - placeholder="search"> - <button - class="bg-primary border border-primary text-white px-8 rounded-r-md hover:bg-transparent hover:text-primary transition">Search</button> - </div> + <div class="flex items-center space-x-4"> + <PersonalBar server:defer> + <PersonalBar placeholder slot="fallback" /> + </PersonalBar> + </div> + </div> + </header> + <!-- ./header --> - <div class="flex items-center space-x-4"> - <PersonalBar server:defer> - <PersonalBar placeholder slot="fallback" /> - </PersonalBar> - </div> - </div> - </header> - <!-- ./header --> + <!-- navbar --> + <nav class="bg-gray-800"> + <div class="container flex"> + <div class="px-8 py-4 bg-primary flex items-center cursor-pointer relative group"> + <span class="text-white"> + <i class="fa-solid fa-bars"></i> + </span> + <span class="capitalize ml-2 text-white">All Categories</span> - <!-- navbar --> - <nav class="bg-gray-800"> - <div class="container flex"> - <div class="px-8 py-4 bg-primary flex items-center cursor-pointer relative group"> - <span class="text-white"> - <i class="fa-solid fa-bars"></i> - </span> - <span class="capitalize ml-2 text-white">All Categories</span> + <!-- dropdown --> + <div + class="absolute w-full left-0 top-full bg-white shadow-md py-3 divide-y divide-gray-300 divide-dashed opacity-0 group-hover:opacity-100 transition duration-300 invisible group-hover:visible" + > + <a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition"> + <img + src="../assets/images/icons/sofa.svg" + alt="sofa" + class="w-5 h-5 object-contain" + /> + <span class="ml-6 text-gray-600 text-sm">Sofa</span> + </a> + <a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition"> + <img + src="../assets/images/icons/terrace.svg" + alt="terrace" + class="w-5 h-5 object-contain" + /> + <span class="ml-6 text-gray-600 text-sm">Terarce</span> + </a> + <a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition"> + <img src="../assets/images/icons/bed.svg" alt="bed" class="w-5 h-5 object-contain" /> + <span class="ml-6 text-gray-600 text-sm">Bed</span> + </a> + <a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition"> + <img + src="../assets/images/icons/office.svg" + alt="office" + class="w-5 h-5 object-contain" + /> + <span class="ml-6 text-gray-600 text-sm">office</span> + </a> + <a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition"> + <img + src="../assets/images/icons/outdoor-cafe.svg" + alt="outdoor" + class="w-5 h-5 object-contain" + /> + <span class="ml-6 text-gray-600 text-sm">Outdoor</span> + </a> + <a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition"> + <img + src="../assets/images/icons/bed-2.svg" + alt="Mattress" + class="w-5 h-5 object-contain" + /> + <span class="ml-6 text-gray-600 text-sm">Mattress</span> + </a> + </div> + </div> - <!-- dropdown --> - <div - class="absolute w-full left-0 top-full bg-white shadow-md py-3 divide-y divide-gray-300 divide-dashed opacity-0 group-hover:opacity-100 transition duration-300 invisible group-hover:visible"> - <a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition"> - <img src="../assets/images/icons/sofa.svg" alt="sofa" class="w-5 h-5 object-contain"> - <span class="ml-6 text-gray-600 text-sm">Sofa</span> - </a> - <a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition"> - <img src="../assets/images/icons/terrace.svg" alt="terrace" class="w-5 h-5 object-contain"> - <span class="ml-6 text-gray-600 text-sm">Terarce</span> - </a> - <a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition"> - <img src="../assets/images/icons/bed.svg" alt="bed" class="w-5 h-5 object-contain"> - <span class="ml-6 text-gray-600 text-sm">Bed</span> - </a> - <a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition"> - <img src="../assets/images/icons/office.svg" alt="office" class="w-5 h-5 object-contain"> - <span class="ml-6 text-gray-600 text-sm">office</span> - </a> - <a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition"> - <img src="../assets/images/icons/outdoor-cafe.svg" alt="outdoor" class="w-5 h-5 object-contain"> - <span class="ml-6 text-gray-600 text-sm">Outdoor</span> - </a> - <a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition"> - <img src="../assets/images/icons/bed-2.svg" alt="Mattress" class="w-5 h-5 object-contain"> - <span class="ml-6 text-gray-600 text-sm">Mattress</span> - </a> - </div> - </div> + <div class="flex items-center justify-between flex-grow pl-12"> + <div class="flex items-center space-x-6 capitalize"> + <a href="../index.html" class="text-gray-200 hover:text-white transition">Home</a> + <a href="pages/shop.html" class="text-gray-200 hover:text-white transition">Shop</a> + <a href="#" class="text-gray-200 hover:text-white transition">About us</a> + <a href="#" class="text-gray-200 hover:text-white transition">Contact us</a> + </div> + <a href="#" class="text-gray-200 hover:text-white transition">Login/Register</a> + </div> + </div> + </nav> + <!-- ./navbar --> - <div class="flex items-center justify-between flex-grow pl-12"> - <div class="flex items-center space-x-6 capitalize"> - <a href="../index.html" class="text-gray-200 hover:text-white transition">Home</a> - <a href="pages/shop.html" class="text-gray-200 hover:text-white transition">Shop</a> - <a href="#" class="text-gray-200 hover:text-white transition">About us</a> - <a href="#" class="text-gray-200 hover:text-white transition">Contact us</a> - </div> - <a href="#" class="text-gray-200 hover:text-white transition">Login/Register</a> - </div> - </div> - </nav> - <!-- ./navbar --> + <!-- breadcrumb --> + <div class="container py-4 flex items-center gap-3"> + <a href="../index.html" class="text-primary text-base"> + <i class="fa-solid fa-house"></i> + </a> + <span class="text-sm text-gray-400"> + <i class="fa-solid fa-chevron-right"></i> + </span> + <p class="text-gray-600 font-medium">Product</p> + </div> + <!-- ./breadcrumb --> - <!-- breadcrumb --> - <div class="container py-4 flex items-center gap-3"> - <a href="../index.html" class="text-primary text-base"> - <i class="fa-solid fa-house"></i> - </a> - <span class="text-sm text-gray-400"> - <i class="fa-solid fa-chevron-right"></i> - </span> - <p class="text-gray-600 font-medium">Product</p> - </div> - <!-- ./breadcrumb --> + <!-- product-detail --> + <div class="container grid grid-cols-2 gap-6"> + <div> + <img src="../assets/images/products/product1.jpg" alt="product" class="w-full" /> + <div class="grid grid-cols-5 gap-4 mt-4"> + <img + src="../assets/images/products/product2.jpg" + alt="product2" + class="w-full cursor-pointer border border-primary" + /> + <img + src="../assets/images/products/product3.jpg" + alt="product2" + class="w-full cursor-pointer border" + /> + <img + src="../assets/images/products/product4.jpg" + alt="product2" + class="w-full cursor-pointer border" + /> + <img + src="../assets/images/products/product5.jpg" + alt="product2" + class="w-full cursor-pointer border" + /> + <img + src="../assets/images/products/product6.jpg" + alt="product2" + class="w-full cursor-pointer border" + /> + </div> + </div> - <!-- product-detail --> - <div class="container grid grid-cols-2 gap-6"> - <div> - <img src="../assets/images/products/product1.jpg" alt="product" class="w-full"> - <div class="grid grid-cols-5 gap-4 mt-4"> - <img src="../assets/images/products/product2.jpg" alt="product2" - class="w-full cursor-pointer border border-primary"> - <img src="../assets/images/products/product3.jpg" alt="product2" class="w-full cursor-pointer border"> - <img src="../assets/images/products/product4.jpg" alt="product2" class="w-full cursor-pointer border"> - <img src="../assets/images/products/product5.jpg" alt="product2" class="w-full cursor-pointer border"> - <img src="../assets/images/products/product6.jpg" alt="product2" class="w-full cursor-pointer border"> - </div> - </div> + <div> + <h2 class="text-3xl font-medium uppercase mb-2">Italian L Shape Sofa</h2> + <div class="flex items-center mb-4"> + <div class="flex gap-1 text-sm text-yellow-400"> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + </div> + <div class="text-xs text-gray-500 ml-3">(150 Reviews)</div> + </div> + <div class="space-y-2"> + <p class="text-gray-800 font-semibold space-x-2"> + <span>Availability: </span> + <span class="text-green-600">In Stock</span> + </p> + <p class="space-x-2"> + <span class="text-gray-800 font-semibold">Brand: </span> + <span class="text-gray-600">Apex</span> + </p> + <p class="space-x-2"> + <span class="text-gray-800 font-semibold">Category: </span> + <span class="text-gray-600">Sofa</span> + </p> + <p class="space-x-2"> + <span class="text-gray-800 font-semibold">SKU: </span> + <span class="text-gray-600">BE45VGRT</span> + </p> + </div> + <div class="flex items-baseline mb-1 space-x-2 font-roboto mt-4"> + <p class="text-xl text-primary font-semibold">$45.00</p> + <p class="text-base text-gray-400 line-through">$55.00</p> + </div> - <div> - <h2 class="text-3xl font-medium uppercase mb-2">Italian L Shape Sofa</h2> - <div class="flex items-center mb-4"> - <div class="flex gap-1 text-sm text-yellow-400"> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - </div> - <div class="text-xs text-gray-500 ml-3">(150 Reviews)</div> - </div> - <div class="space-y-2"> - <p class="text-gray-800 font-semibold space-x-2"> - <span>Availability: </span> - <span class="text-green-600">In Stock</span> - </p> - <p class="space-x-2"> - <span class="text-gray-800 font-semibold">Brand: </span> - <span class="text-gray-600">Apex</span> - </p> - <p class="space-x-2"> - <span class="text-gray-800 font-semibold">Category: </span> - <span class="text-gray-600">Sofa</span> - </p> - <p class="space-x-2"> - <span class="text-gray-800 font-semibold">SKU: </span> - <span class="text-gray-600">BE45VGRT</span> - </p> - </div> - <div class="flex items-baseline mb-1 space-x-2 font-roboto mt-4"> - <p class="text-xl text-primary font-semibold">$45.00</p> - <p class="text-base text-gray-400 line-through">$55.00</p> - </div> + <p class="mt-4 text-gray-600"> + Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos eius eum reprehenderit dolore + vel mollitia optio consequatur hic asperiores inventore suscipit, velit consequuntur, + voluptate doloremque iure necessitatibus adipisci magnam porro. + </p> - <p class="mt-4 text-gray-600">Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos eius eum - reprehenderit dolore vel mollitia optio consequatur hic asperiores inventore suscipit, velit - consequuntur, voluptate doloremque iure necessitatibus adipisci magnam porro.</p> + <div class="pt-4"> + <h3 class="text-sm text-gray-800 uppercase mb-1">Size</h3> + <div class="flex items-center gap-2"> + <div class="size-selector"> + <input type="radio" name="size" id="size-xs" class="hidden" /> + <label + for="size-xs" + class="text-xs border border-gray-200 rounded-sm h-6 w-6 flex items-center justify-center cursor-pointer shadow-sm text-gray-600" + >XS</label + > + </div> + <div class="size-selector"> + <input type="radio" name="size" id="size-sm" class="hidden" /> + <label + for="size-sm" + class="text-xs border border-gray-200 rounded-sm h-6 w-6 flex items-center justify-center cursor-pointer shadow-sm text-gray-600" + >S</label + > + </div> + <div class="size-selector"> + <input type="radio" name="size" id="size-m" class="hidden" /> + <label + for="size-m" + class="text-xs border border-gray-200 rounded-sm h-6 w-6 flex items-center justify-center cursor-pointer shadow-sm text-gray-600" + >M</label + > + </div> + <div class="size-selector"> + <input type="radio" name="size" id="size-l" class="hidden" /> + <label + for="size-l" + class="text-xs border border-gray-200 rounded-sm h-6 w-6 flex items-center justify-center cursor-pointer shadow-sm text-gray-600" + >L</label + > + </div> + <div class="size-selector"> + <input type="radio" name="size" id="size-xl" class="hidden" /> + <label + for="size-xl" + class="text-xs border border-gray-200 rounded-sm h-6 w-6 flex items-center justify-center cursor-pointer shadow-sm text-gray-600" + >XL</label + > + </div> + </div> + </div> - <div class="pt-4"> - <h3 class="text-sm text-gray-800 uppercase mb-1">Size</h3> - <div class="flex items-center gap-2"> - <div class="size-selector"> - <input type="radio" name="size" id="size-xs" class="hidden"> - <label for="size-xs" - class="text-xs border border-gray-200 rounded-sm h-6 w-6 flex items-center justify-center cursor-pointer shadow-sm text-gray-600">XS</label> - </div> - <div class="size-selector"> - <input type="radio" name="size" id="size-sm" class="hidden"> - <label for="size-sm" - class="text-xs border border-gray-200 rounded-sm h-6 w-6 flex items-center justify-center cursor-pointer shadow-sm text-gray-600">S</label> - </div> - <div class="size-selector"> - <input type="radio" name="size" id="size-m" class="hidden"> - <label for="size-m" - class="text-xs border border-gray-200 rounded-sm h-6 w-6 flex items-center justify-center cursor-pointer shadow-sm text-gray-600">M</label> - </div> - <div class="size-selector"> - <input type="radio" name="size" id="size-l" class="hidden"> - <label for="size-l" - class="text-xs border border-gray-200 rounded-sm h-6 w-6 flex items-center justify-center cursor-pointer shadow-sm text-gray-600">L</label> - </div> - <div class="size-selector"> - <input type="radio" name="size" id="size-xl" class="hidden"> - <label for="size-xl" - class="text-xs border border-gray-200 rounded-sm h-6 w-6 flex items-center justify-center cursor-pointer shadow-sm text-gray-600">XL</label> - </div> - </div> - </div> + <div class="pt-4"> + <h3 class="text-xl text-gray-800 mb-3 uppercase font-medium">Color</h3> + <div class="flex items-center gap-2"> + <div class="color-selector"> + <input type="radio" name="color" id="red" class="hidden" /> + <label + for="red" + class="border border-gray-200 rounded-sm h-6 w-6 cursor-pointer shadow-sm block" + style="background-color: #fc3d57;"></label> + </div> + <div class="color-selector"> + <input type="radio" name="color" id="black" class="hidden" /> + <label + for="black" + class="border border-gray-200 rounded-sm h-6 w-6 cursor-pointer shadow-sm block" + style="background-color: #000;"></label> + </div> + <div class="color-selector"> + <input type="radio" name="color" id="white" class="hidden" /> + <label + for="white" + class="border border-gray-200 rounded-sm h-6 w-6 cursor-pointer shadow-sm block" + style="background-color: #fff;"></label> + </div> + </div> + </div> - <div class="pt-4"> - <h3 class="text-xl text-gray-800 mb-3 uppercase font-medium">Color</h3> - <div class="flex items-center gap-2"> - <div class="color-selector"> - <input type="radio" name="color" id="red" class="hidden"> - <label for="red" - class="border border-gray-200 rounded-sm h-6 w-6 cursor-pointer shadow-sm block" - style="background-color: #fc3d57;"></label> - </div> - <div class="color-selector"> - <input type="radio" name="color" id="black" class="hidden"> - <label for="black" - class="border border-gray-200 rounded-sm h-6 w-6 cursor-pointer shadow-sm block" - style="background-color: #000;"></label> - </div> - <div class="color-selector"> - <input type="radio" name="color" id="white" class="hidden"> - <label for="white" - class="border border-gray-200 rounded-sm h-6 w-6 cursor-pointer shadow-sm block" - style="background-color: #fff;"></label> - </div> + <div class="mt-4"> + <h3 class="text-sm text-gray-800 uppercase mb-1">Quantity</h3> + <div class="flex border border-gray-300 text-gray-600 divide-x divide-gray-300 w-max"> + <div + class="h-8 w-8 text-xl flex items-center justify-center cursor-pointer select-none" + > + - + </div> + <div class="h-8 w-8 text-base flex items-center justify-center">4</div> + <div + class="h-8 w-8 text-xl flex items-center justify-center cursor-pointer select-none" + > + + + </div> + </div> + </div> - </div> - </div> + <div class="mt-6 flex gap-3 border-b border-gray-200 pb-5 pt-5"> + <AddToCart client:load /> + <a + href="#" + class="border border-gray-300 text-gray-600 px-8 py-2 font-medium rounded uppercase flex items-center gap-2 hover:text-primary transition" + > + <i class="fa-solid fa-heart"></i> Wishlist + </a> + </div> - <div class="mt-4"> - <h3 class="text-sm text-gray-800 uppercase mb-1">Quantity</h3> - <div class="flex border border-gray-300 text-gray-600 divide-x divide-gray-300 w-max"> - <div class="h-8 w-8 text-xl flex items-center justify-center cursor-pointer select-none">-</div> - <div class="h-8 w-8 text-base flex items-center justify-center">4</div> - <div class="h-8 w-8 text-xl flex items-center justify-center cursor-pointer select-none">+</div> - </div> - </div> + <div class="flex gap-3 mt-4"> + <a + href="#" + class="text-gray-400 hover:text-gray-500 h-8 w-8 rounded-full border border-gray-300 flex items-center justify-center" + > + <i class="fa-brands fa-facebook-f"></i> + </a> + <a + href="#" + class="text-gray-400 hover:text-gray-500 h-8 w-8 rounded-full border border-gray-300 flex items-center justify-center" + > + <i class="fa-brands fa-twitter"></i> + </a> + <a + href="#" + class="text-gray-400 hover:text-gray-500 h-8 w-8 rounded-full border border-gray-300 flex items-center justify-center" + > + <i class="fa-brands fa-instagram"></i> + </a> + </div> + </div> + </div> + <!-- ./product-detail --> - <div class="mt-6 flex gap-3 border-b border-gray-200 pb-5 pt-5"> - <AddToCart client:load /> - <a href="#" - class="border border-gray-300 text-gray-600 px-8 py-2 font-medium rounded uppercase flex items-center gap-2 hover:text-primary transition"> - <i class="fa-solid fa-heart"></i> Wishlist - </a> - </div> + <!-- description --> + <div class="container pb-16"> + <h3 class="border-b border-gray-200 font-roboto text-gray-800 pb-3 font-medium"> + Product details + </h3> + <div class="w-3/5 pt-6"> + <div class="text-gray-600"> + <p> + Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tenetur necessitatibus + deleniti natus dolore cum maiores suscipit optio itaque voluptatibus veritatis tempora + iste facilis non aut sapiente dolor quisquam, ex ab. + </p> + <p> + Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorum, quae accusantium + voluptatem blanditiis sapiente voluptatum. Autem ab, dolorum assumenda earum veniam eius + illo fugiat possimus illum dolor totam, ducimus excepturi. + </p> + <p> + Lorem ipsum dolor sit amet consectetur adipisicing elit. Error quia modi ut expedita! + Iure molestiae labore cumque nobis quasi fuga, quibusdam rem? Temporibus consectetur + corrupti rerum veritatis numquam labore amet. + </p> + </div> - <div class="flex gap-3 mt-4"> - <a href="#" - class="text-gray-400 hover:text-gray-500 h-8 w-8 rounded-full border border-gray-300 flex items-center justify-center"> - <i class="fa-brands fa-facebook-f"></i> - </a> - <a href="#" - class="text-gray-400 hover:text-gray-500 h-8 w-8 rounded-full border border-gray-300 flex items-center justify-center"> - <i class="fa-brands fa-twitter"></i> - </a> - <a href="#" - class="text-gray-400 hover:text-gray-500 h-8 w-8 rounded-full border border-gray-300 flex items-center justify-center"> - <i class="fa-brands fa-instagram"></i> - </a> - </div> - </div> - </div> - <!-- ./product-detail --> + <table class="table-auto border-collapse w-full text-left text-gray-600 text-sm mt-6"> + <tr> + <th class="py-2 px-4 border border-gray-300 w-40 font-medium">Color</th> + <th class="py-2 px-4 border border-gray-300">Blank, Brown, Red</th> + </tr> + <tr> + <th class="py-2 px-4 border border-gray-300 w-40 font-medium">Material</th> + <th class="py-2 px-4 border border-gray-300">Latex</th> + </tr> + <tr> + <th class="py-2 px-4 border border-gray-300 w-40 font-medium">Weight</th> + <th class="py-2 px-4 border border-gray-300">55kg</th> + </tr> + </table> + </div> + </div> + <!-- ./description --> - <!-- description --> - <div class="container pb-16"> - <h3 class="border-b border-gray-200 font-roboto text-gray-800 pb-3 font-medium">Product details</h3> - <div class="w-3/5 pt-6"> - <div class="text-gray-600"> - <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tenetur necessitatibus deleniti natus - dolore cum maiores suscipit optio itaque voluptatibus veritatis tempora iste facilis non aut - sapiente dolor quisquam, ex ab.</p> - <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorum, quae accusantium voluptatem - blanditiis sapiente voluptatum. Autem ab, dolorum assumenda earum veniam eius illo fugiat possimus - illum dolor totam, ducimus excepturi.</p> - <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Error quia modi ut expedita! Iure molestiae - labore cumque nobis quasi fuga, quibusdam rem? Temporibus consectetur corrupti rerum veritatis - numquam labore amet.</p> - </div> + <!-- related product --> + <div class="container pb-16"> + <h2 class="text-2xl font-medium text-gray-800 uppercase mb-6">Related products</h2> + <div class="grid grid-cols-4 gap-6"> + <div class="bg-white shadow rounded overflow-hidden group"> + <div class="relative"> + <img src="../assets/images/products/product1.jpg" alt="product 1" class="w-full" /> + <div + class="absolute inset-0 bg-black bg-opacity-40 flex items-center + justify-center gap-2 opacity-0 group-hover:opacity-100 transition" + > + <a + href="#" + class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" + title="view product" + > + <i class="fa-solid fa-magnifying-glass"></i> + </a> + <a + href="#" + class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" + title="add to wishlist" + > + <i class="fa-solid fa-heart"></i> + </a> + </div> + </div> + <div class="pt-4 pb-3 px-4"> + <a href="#"> + <h4 + class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition" + > + Guyer Chair + </h4> + </a> + <div class="flex items-baseline mb-1 space-x-2"> + <p class="text-xl text-primary font-semibold">$45.00</p> + <p class="text-sm text-gray-400 line-through">$55.90</p> + </div> + <div class="flex items-center"> + <div class="flex gap-1 text-sm text-yellow-400"> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + </div> + <div class="text-xs text-gray-500 ml-3">(150)</div> + </div> + </div> + <AddToCart small client:load /> + </div> + <div class="bg-white shadow rounded overflow-hidden group"> + <div class="relative"> + <img src="../assets/images/products/product4.jpg" alt="product 1" class="w-full" /> + <div + class="absolute inset-0 bg-black bg-opacity-40 flex items-center + justify-center gap-2 opacity-0 group-hover:opacity-100 transition" + > + <a + href="#" + class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" + title="view product" + > + <i class="fa-solid fa-magnifying-glass"></i> + </a> + <a + href="#" + class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" + title="add to wishlist" + > + <i class="fa-solid fa-heart"></i> + </a> + </div> + </div> + <div class="pt-4 pb-3 px-4"> + <a href="#"> + <h4 + class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition" + > + Bed King Size + </h4> + </a> + <div class="flex items-baseline mb-1 space-x-2"> + <p class="text-xl text-primary font-semibold">$45.00</p> + <p class="text-sm text-gray-400 line-through">$55.90</p> + </div> + <div class="flex items-center"> + <div class="flex gap-1 text-sm text-yellow-400"> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + </div> + <div class="text-xs text-gray-500 ml-3">(150)</div> + </div> + </div> + <AddToCart small client:load /> + </div> + <div class="bg-white shadow rounded overflow-hidden group"> + <div class="relative"> + <img src="../assets/images/products/product2.jpg" alt="product 1" class="w-full" /> + <div + class="absolute inset-0 bg-black bg-opacity-40 flex items-center + justify-center gap-2 opacity-0 group-hover:opacity-100 transition" + > + <a + href="#" + class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" + title="view product" + > + <i class="fa-solid fa-magnifying-glass"></i> + </a> + <a + href="#" + class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" + title="add to wishlist" + > + <i class="fa-solid fa-heart"></i> + </a> + </div> + </div> + <div class="pt-4 pb-3 px-4"> + <a href="#"> + <h4 + class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition" + > + Couple Sofa + </h4> + </a> + <div class="flex items-baseline mb-1 space-x-2"> + <p class="text-xl text-primary font-semibold">$45.00</p> + <p class="text-sm text-gray-400 line-through">$55.90</p> + </div> + <div class="flex items-center"> + <div class="flex gap-1 text-sm text-yellow-400"> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + </div> + <div class="text-xs text-gray-500 ml-3">(150)</div> + </div> + </div> + <AddToCart small client:load /> + </div> + <div class="bg-white shadow rounded overflow-hidden group"> + <div class="relative"> + <img src="../assets/images/products/product3.jpg" alt="product 1" class="w-full" /> + <div + class="absolute inset-0 bg-black bg-opacity-40 flex items-center + justify-center gap-2 opacity-0 group-hover:opacity-100 transition" + > + <a + href="#" + class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" + title="view product" + > + <i class="fa-solid fa-magnifying-glass"></i> + </a> + <a + href="#" + class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" + title="add to wishlist" + > + <i class="fa-solid fa-heart"></i> + </a> + </div> + </div> + <div class="pt-4 pb-3 px-4"> + <a href="#"> + <h4 + class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition" + > + Mattrass X + </h4> + </a> + <div class="flex items-baseline mb-1 space-x-2"> + <p class="text-xl text-primary font-semibold">$45.00</p> + <p class="text-sm text-gray-400 line-through">$55.90</p> + </div> + <div class="flex items-center"> + <div class="flex gap-1 text-sm text-yellow-400"> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + <span><i class="fa-solid fa-star"></i></span> + </div> + <div class="text-xs text-gray-500 ml-3">(150)</div> + </div> + </div> + <AddToCart small client:load /> + </div> + </div> + </div> + <!-- ./related product --> - <table class="table-auto border-collapse w-full text-left text-gray-600 text-sm mt-6"> - <tr> - <th class="py-2 px-4 border border-gray-300 w-40 font-medium">Color</th> - <th class="py-2 px-4 border border-gray-300 ">Blank, Brown, Red</th> - </tr> - <tr> - <th class="py-2 px-4 border border-gray-300 w-40 font-medium">Material</th> - <th class="py-2 px-4 border border-gray-300 ">Latex</th> - </tr> - <tr> - <th class="py-2 px-4 border border-gray-300 w-40 font-medium">Weight</th> - <th class="py-2 px-4 border border-gray-300 ">55kg</th> - </tr> - </table> - </div> - </div> - <!-- ./description --> + <!-- footer --> + <footer class="bg-white pt-16 pb-12 border-t border-gray-100"> + <div class="container grid grid-cols-3"> + <div class="col-span-1 space-y-8 mr-2"> + <img src="../assets/images/logo.svg" alt="logo" class="w-30" /> + <div class="mr-2"> + <p class="text-gray-500"> + Lorem ipsum dolor sit amet consectetur adipisicing elit. Quia, hic? + </p> + </div> + <div class="flex space-x-6"> + <a href="#" class="text-gray-400 hover:text-gray-500" + ><i class="fa-brands fa-facebook-square"></i></a + > + <a href="#" class="text-gray-400 hover:text-gray-500" + ><i class="fa-brands fa-instagram-square"></i></a + > + <a href="#" class="text-gray-400 hover:text-gray-500" + ><i class="fa-brands fa-twitter-square"></i></a + > + <a href="#" class="text-gray-400 hover:text-gray-500"> + <i class="fa-brands fa-github-square"></i> + </a> + </div> + </div> - <!-- related product --> - <div class="container pb-16"> - <h2 class="text-2xl font-medium text-gray-800 uppercase mb-6">Related products</h2> - <div class="grid grid-cols-4 gap-6"> - <div class="bg-white shadow rounded overflow-hidden group"> - <div class="relative"> - <img src="../assets/images/products/product1.jpg" alt="product 1" class="w-full"> - <div class="absolute inset-0 bg-black bg-opacity-40 flex items-center - justify-center gap-2 opacity-0 group-hover:opacity-100 transition"> - <a href="#" - class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" - title="view product"> - <i class="fa-solid fa-magnifying-glass"></i> - </a> - <a href="#" - class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" - title="add to wishlist"> - <i class="fa-solid fa-heart"></i> - </a> - </div> - </div> - <div class="pt-4 pb-3 px-4"> - <a href="#"> - <h4 class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition">Guyer - Chair</h4> - </a> - <div class="flex items-baseline mb-1 space-x-2"> - <p class="text-xl text-primary font-semibold">$45.00</p> - <p class="text-sm text-gray-400 line-through">$55.90</p> - </div> - <div class="flex items-center"> - <div class="flex gap-1 text-sm text-yellow-400"> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - </div> - <div class="text-xs text-gray-500 ml-3">(150)</div> - </div> - </div> - <AddToCart small client:load /> - </div> - <div class="bg-white shadow rounded overflow-hidden group"> - <div class="relative"> - <img src="../assets/images/products/product4.jpg" alt="product 1" class="w-full"> - <div class="absolute inset-0 bg-black bg-opacity-40 flex items-center - justify-center gap-2 opacity-0 group-hover:opacity-100 transition"> - <a href="#" - class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" - title="view product"> - <i class="fa-solid fa-magnifying-glass"></i> - </a> - <a href="#" - class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" - title="add to wishlist"> - <i class="fa-solid fa-heart"></i> - </a> - </div> - </div> - <div class="pt-4 pb-3 px-4"> - <a href="#"> - <h4 class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition">Bed - King Size</h4> - </a> - <div class="flex items-baseline mb-1 space-x-2"> - <p class="text-xl text-primary font-semibold">$45.00</p> - <p class="text-sm text-gray-400 line-through">$55.90</p> - </div> - <div class="flex items-center"> - <div class="flex gap-1 text-sm text-yellow-400"> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - </div> - <div class="text-xs text-gray-500 ml-3">(150)</div> - </div> - </div> - <AddToCart small client:load /> - </div> - <div class="bg-white shadow rounded overflow-hidden group"> - <div class="relative"> - <img src="../assets/images/products/product2.jpg" alt="product 1" class="w-full"> - <div class="absolute inset-0 bg-black bg-opacity-40 flex items-center - justify-center gap-2 opacity-0 group-hover:opacity-100 transition"> - <a href="#" - class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" - title="view product"> - <i class="fa-solid fa-magnifying-glass"></i> - </a> - <a href="#" - class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" - title="add to wishlist"> - <i class="fa-solid fa-heart"></i> - </a> - </div> - </div> - <div class="pt-4 pb-3 px-4"> - <a href="#"> - <h4 class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition"> - Couple Sofa</h4> - </a> - <div class="flex items-baseline mb-1 space-x-2"> - <p class="text-xl text-primary font-semibold">$45.00</p> - <p class="text-sm text-gray-400 line-through">$55.90</p> - </div> - <div class="flex items-center"> - <div class="flex gap-1 text-sm text-yellow-400"> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - </div> - <div class="text-xs text-gray-500 ml-3">(150)</div> - </div> - </div> - <AddToCart small client:load /> - </div> - <div class="bg-white shadow rounded overflow-hidden group"> - <div class="relative"> - <img src="../assets/images/products/product3.jpg" alt="product 1" class="w-full"> - <div class="absolute inset-0 bg-black bg-opacity-40 flex items-center - justify-center gap-2 opacity-0 group-hover:opacity-100 transition"> - <a href="#" - class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" - title="view product"> - <i class="fa-solid fa-magnifying-glass"></i> - </a> - <a href="#" - class="text-white text-lg w-9 h-8 rounded-full bg-primary flex items-center justify-center hover:bg-gray-800 transition" - title="add to wishlist"> - <i class="fa-solid fa-heart"></i> - </a> - </div> - </div> - <div class="pt-4 pb-3 px-4"> - <a href="#"> - <h4 class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition"> - Mattrass X</h4> - </a> - <div class="flex items-baseline mb-1 space-x-2"> - <p class="text-xl text-primary font-semibold">$45.00</p> - <p class="text-sm text-gray-400 line-through">$55.90</p> - </div> - <div class="flex items-center"> - <div class="flex gap-1 text-sm text-yellow-400"> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - <span><i class="fa-solid fa-star"></i></span> - </div> - <div class="text-xs text-gray-500 ml-3">(150)</div> - </div> - </div> - <AddToCart small client:load /> - </div> - </div> - </div> - <!-- ./related product --> + <div class="col-span-2 grid grid-cols-2 gap-8"> + <div class="grid grid-cols-2 gap-8"> + <div> + <h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider"> + Solutions + </h3> + <div class="mt-4 space-y-4"> + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Marketing</a> + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Analitycs</a> + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Commerce</a> + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Insights</a> + </div> + </div> - <!-- footer --> - <footer class="bg-white pt-16 pb-12 border-t border-gray-100"> - <div class="container grid grid-cols-3"> - <div class="col-span-1 space-y-8 mr-2"> - <img src="../assets/images/logo.svg" alt="logo" class="w-30"> - <div class="mr-2"> - <p class="text-gray-500"> - Lorem ipsum dolor sit amet consectetur adipisicing elit. Quia, hic? - </p> - </div> - <div class="flex space-x-6"> - <a href="#" class="text-gray-400 hover:text-gray-500"><i - class="fa-brands fa-facebook-square"></i></a> - <a href="#" class="text-gray-400 hover:text-gray-500"><i - class="fa-brands fa-instagram-square"></i></a> - <a href="#" class="text-gray-400 hover:text-gray-500"><i - class="fa-brands fa-twitter-square"></i></a> - <a href="#" class="text-gray-400 hover:text-gray-500"> - <i class="fa-brands fa-github-square"></i> - </a> - </div> - </div> + <div> + <h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider">Support</h3> + <div class="mt-4 space-y-4"> + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Pricing</a> + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block" + >Documentation</a + > + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Guides</a> + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">API Status</a> + </div> + </div> + </div> + <div class="grid grid-cols-2 gap-8"> + <div> + <h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider"> + Solutions + </h3> + <div class="mt-4 space-y-4"> + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Marketing</a> + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Analitycs</a> + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Commerce</a> + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Insights</a> + </div> + </div> - <div class="col-span-2 grid grid-cols-2 gap-8"> - <div class="grid grid-cols-2 gap-8"> - <div> - <h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider">Solutions</h3> - <div class="mt-4 space-y-4"> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Marketing</a> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Analitycs</a> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Commerce</a> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Insights</a> - </div> - </div> - - <div> - <h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider">Support</h3> - <div class="mt-4 space-y-4"> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Pricing</a> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Documentation</a> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Guides</a> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">API Status</a> - </div> - </div> - </div> - <div class="grid grid-cols-2 gap-8"> - <div> - <h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider">Solutions</h3> - <div class="mt-4 space-y-4"> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Marketing</a> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Analitycs</a> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Commerce</a> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Insights</a> - </div> - </div> - - <div> - <h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider">Support</h3> - <div class="mt-4 space-y-4"> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Pricing</a> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Documentation</a> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Guides</a> - <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">API Status</a> - </div> - </div> - </div> - </div> - </div> - </footer> - <!-- ./footer --> - - <!-- copyright --> - <div class="bg-gray-800 py-4"> - <div class="container flex items-center justify-between"> - <p class="text-white">© TailCommerce - All Right Reserved</p> - <div> - <img src="../assets/images/methods.png" alt="methods" class="h-5"> - </div> - </div> - </div> - <!-- ./copyright --> - -</body> + <div> + <h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider">Support</h3> + <div class="mt-4 space-y-4"> + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Pricing</a> + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block" + >Documentation</a + > + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">Guides</a> + <a href="#" class="text-base text-gray-500 hover:text-gray-900 block">API Status</a> + </div> + </div> + </div> + </div> + </div> + </footer> + <!-- ./footer --> + <!-- copyright --> + <div class="bg-gray-800 py-4"> + <div class="container flex items-center justify-between"> + <p class="text-white">© TailCommerce - All Right Reserved</p> + <div> + <img src="../assets/images/methods.png" alt="methods" class="h-5" /> + </div> + </div> + </div> + <!-- ./copyright --> + </body> </html> diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 33cb5f0d0b..e54c6e037c 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -2254,7 +2254,7 @@ export interface AstroUserConfig { * #### Server island fallback content * * Since your component will not render with the rest of the page, you may want to add generic content (e.g. a loading message) to temporarily show in its place. This content will be displayed when the page first renders but before the island has loaded. - * + * * Add placeholder content as a child of your Astro component with the `slot="fallback:` attribute. When your island content is available, the fallback content will be replaced. * * The example below displays a generic avatar as fallback content, then animates into a personalized avatar using view transitions: @@ -3377,7 +3377,6 @@ export interface SSRMetadata { headInTree: boolean; extraHead: string[]; propagators: Set<AstroComponentInstance>; - } /* Preview server stuff */ diff --git a/packages/astro/src/content/vite-plugin-content-virtual-mod.ts b/packages/astro/src/content/vite-plugin-content-virtual-mod.ts index 95921c9420..03d13a3d73 100644 --- a/packages/astro/src/content/vite-plugin-content-virtual-mod.ts +++ b/packages/astro/src/content/vite-plugin-content-virtual-mod.ts @@ -11,6 +11,7 @@ import { appendForwardSlash, removeFileExtension } from '../core/path.js'; import { isServerLikeOutput } from '../core/util.js'; import { rootRelativePath } from '../core/viteUtils.js'; import type { AstroPluginMetadata } from '../vite-plugin-astro/index.js'; +import { createDefaultAstroMetadata } from '../vite-plugin-astro/metadata.js'; import { CONTENT_FLAG, CONTENT_RENDER_FLAG, @@ -30,7 +31,6 @@ import { getEntryType, getExtGlob, } from './utils.js'; -import { createDefaultAstroMetadata } from '../vite-plugin-astro/metadata.js'; interface AstroContentVirtualModPluginParams { settings: AstroSettings; diff --git a/packages/astro/src/core/app/pipeline.ts b/packages/astro/src/core/app/pipeline.ts index 4dde786a4f..19284ef07a 100644 --- a/packages/astro/src/core/app/pipeline.ts +++ b/packages/astro/src/core/app/pipeline.ts @@ -99,11 +99,11 @@ export class AppPipeline extends Pipeline { } async getModuleForRoute(route: RouteData): Promise<SinglePageBuiltModule> { - for(const defaultRoute of this.defaultRoutes) { - if(route.component === defaultRoute.component) { + for (const defaultRoute of this.defaultRoutes) { + if (route.component === defaultRoute.component) { return { page: () => Promise.resolve(defaultRoute.instance), - renderers: [] + renderers: [], }; } } diff --git a/packages/astro/src/core/app/types.ts b/packages/astro/src/core/app/types.ts index 0c4e671160..69a9a4a491 100644 --- a/packages/astro/src/core/app/types.ts +++ b/packages/astro/src/core/app/types.ts @@ -1,5 +1,5 @@ import type { - ComponentInstance, + ComponentInstance, Locales, MiddlewareHandler, RouteData, @@ -84,7 +84,13 @@ export type SSRManifestI18n = { export type SerializedSSRManifest = Omit< SSRManifest, - 'middleware' | 'routes' | 'assets' | 'componentMetadata' | 'inlinedScripts' | 'clientDirectives' | 'serverIslandNameMap' + | 'middleware' + | 'routes' + | 'assets' + | 'componentMetadata' + | 'inlinedScripts' + | 'clientDirectives' + | 'serverIslandNameMap' > & { routes: SerializedRouteInfo[]; assets: string[]; diff --git a/packages/astro/src/core/build/pipeline.ts b/packages/astro/src/core/build/pipeline.ts index ed8b22870e..81a5dcfa2d 100644 --- a/packages/astro/src/core/build/pipeline.ts +++ b/packages/astro/src/core/build/pipeline.ts @@ -272,8 +272,8 @@ export class BuildPipeline extends Pipeline { return await entry.page(); } - for(const route of this.defaultRoutes) { - if(route.component === routeData.component) { + for (const route of this.defaultRoutes) { + if (route.component === routeData.component) { return route.instance; } } diff --git a/packages/astro/src/core/build/plugins/plugin-ssr.ts b/packages/astro/src/core/build/plugins/plugin-ssr.ts index c751a1fc19..2aff997ee6 100644 --- a/packages/astro/src/core/build/plugins/plugin-ssr.ts +++ b/packages/astro/src/core/build/plugins/plugin-ssr.ts @@ -4,6 +4,7 @@ import type { Plugin as VitePlugin } from 'vite'; import type { AstroAdapter, AstroSettings } from '../../../@types/astro.js'; import { isFunctionPerRouteEnabled } from '../../../integrations/hooks.js'; import { routeIsRedirect } from '../../redirects/index.js'; +import { VIRTUAL_ISLAND_MAP_ID } from '../../server-islands/vite-plugin-server-islands.js'; import { isServerLikeOutput } from '../../util.js'; import { addRollupInput } from '../add-rollup-input.js'; import type { BuildInternals } from '../internal.js'; @@ -13,7 +14,6 @@ import { SSR_MANIFEST_VIRTUAL_MODULE_ID } from './plugin-manifest.js'; import { MIDDLEWARE_MODULE_ID } from './plugin-middleware.js'; import { ASTRO_PAGE_MODULE_ID } from './plugin-pages.js'; import { RENDERERS_MODULE_ID } from './plugin-renderers.js'; -import { VIRTUAL_ISLAND_MAP_ID } from '../../server-islands/vite-plugin-server-islands.js'; import { getComponentFromVirtualModulePageName, getVirtualModulePageName } from './util.js'; export const SSR_VIRTUAL_MODULE_ID = '@astrojs-ssr-virtual-entry'; @@ -250,7 +250,9 @@ function generateSSRCode(settings: AstroSettings, adapter: AstroAdapter, middlew `import { manifest as defaultManifest } from '${SSR_MANIFEST_VIRTUAL_MODULE_ID}';`, `import * as serverEntrypointModule from '${adapter.serverEntrypoint}';`, edgeMiddleware ? `` : `import { onRequest as middleware } from '${middlewareId}';`, - settings.config.experimental.serverIslands ? `import { serverIslandMap } from '${VIRTUAL_ISLAND_MAP_ID}';` : '' + settings.config.experimental.serverIslands + ? `import { serverIslandMap } from '${VIRTUAL_ISLAND_MAP_ID}';` + : '', ]; const contents = [ diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index 07f80386f2..a3c5998ab9 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -540,7 +540,10 @@ export const AstroConfigSchema = z.object({ }) .strict() .optional(), - serverIslands: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.serverIslands), + serverIslands: z + .boolean() + .optional() + .default(ASTRO_CONFIG_DEFAULTS.experimental.serverIslands), }) .strict( `Invalid or outdated experimental feature.\nCheck for incorrect spelling or outdated Astro version.\nSee https://docs.astro.build/en/reference/configuration-reference/#experimental-flags for a list of all current experiments.` diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts index 4a821635e3..f0986e82ca 100644 --- a/packages/astro/src/core/create-vite.ts +++ b/packages/astro/src/core/create-vite.ts @@ -36,8 +36,8 @@ import { vitePluginSSRManifest } from '../vite-plugin-ssr-manifest/index.js'; import type { Logger } from './logger/core.js'; import { createViteLogger } from './logger/vite.js'; import { vitePluginMiddleware } from './middleware/vite-plugin.js'; -import { vitePluginServerIslands } from './server-islands/vite-plugin-server-islands.js'; import { joinPaths } from './path.js'; +import { vitePluginServerIslands } from './server-islands/vite-plugin-server-islands.js'; import { isObject } from './util.js'; interface CreateViteOptions { diff --git a/packages/astro/src/core/routing/default.ts b/packages/astro/src/core/routing/default.ts index 7cea8fab49..5bad66ec4f 100644 --- a/packages/astro/src/core/routing/default.ts +++ b/packages/astro/src/core/routing/default.ts @@ -1,7 +1,16 @@ -import type { ComponentInstance, ManifestData, SSRManifest, } from "../../@types/astro.js"; -import { DEFAULT_404_COMPONENT } from "../constants.js"; -import { ensureServerIslandRoute, createEndpoint as createServerIslandEndpoint, SERVER_ISLAND_ROUTE, SERVER_ISLAND_COMPONENT } from "../server-islands/endpoint.js"; -import { ensure404Route, default404Instance, DEFAULT_404_ROUTE } from './astro-designed-error-pages.js'; +import type { ComponentInstance, ManifestData, SSRManifest } from '../../@types/astro.js'; +import { DEFAULT_404_COMPONENT } from '../constants.js'; +import { + SERVER_ISLAND_COMPONENT, + SERVER_ISLAND_ROUTE, + createEndpoint as createServerIslandEndpoint, + ensureServerIslandRoute, +} from '../server-islands/endpoint.js'; +import { + DEFAULT_404_ROUTE, + default404Instance, + ensure404Route, +} from './astro-designed-error-pages.js'; export function injectDefaultRoutes(manifest: ManifestData) { ensure404Route(manifest); @@ -14,7 +23,7 @@ type DefaultRouteParams = { matchesComponent(filePath: URL): boolean; route: string; component: string; -} +}; export function createDefaultRoutes(manifest: SSRManifest, root: URL): DefaultRouteParams[] { return [ @@ -29,6 +38,6 @@ export function createDefaultRoutes(manifest: SSRManifest, root: URL): DefaultRo matchesComponent: (filePath) => filePath.href === new URL(SERVER_ISLAND_COMPONENT, root).href, route: SERVER_ISLAND_ROUTE, component: SERVER_ISLAND_COMPONENT, - } + }, ]; } diff --git a/packages/astro/src/core/server-islands/endpoint.ts b/packages/astro/src/core/server-islands/endpoint.ts index 31eae7f7d3..7b6857e1ac 100644 --- a/packages/astro/src/core/server-islands/endpoint.ts +++ b/packages/astro/src/core/server-islands/endpoint.ts @@ -1,5 +1,15 @@ -import { renderComponent, renderTemplate, type AstroComponentFactory, type ComponentSlots } from '../../runtime/server/index.js'; -import type { ComponentInstance, ManifestData, RouteData, SSRManifest } from '../../@types/astro.js'; +import type { + ComponentInstance, + ManifestData, + RouteData, + SSRManifest, +} from '../../@types/astro.js'; +import { + type AstroComponentFactory, + type ComponentSlots, + renderComponent, + renderTemplate, +} from '../../runtime/server/index.js'; import { createSlotValueFromString } from '../../runtime/server/render/slot.js'; export const SERVER_ISLAND_ROUTE = '/_server-islands/[name]'; @@ -17,7 +27,7 @@ export function ensureServerIslandRoute(manifest: ManifestData) { params: ['name'], segments: [ [{ content: '_server-islands', dynamic: false, spread: false }], - [{ content: 'name', dynamic: true, spread: false }] + [{ content: 'name', dynamic: true, spread: false }], ], // eslint-disable-next-line pattern: /^\/_server-islands\/([^/]+?)$/, @@ -25,7 +35,7 @@ export function ensureServerIslandRoute(manifest: ManifestData) { isIndex: false, fallbackRoutes: [], route: SERVER_ISLAND_ROUTE, - } + }; manifest.routes.push(route); } @@ -34,7 +44,7 @@ type RenderOptions = { componentExport: string; props: Record<string, any>; slots: Record<string, string>; -} +}; export function createEndpoint(manifest: SSRManifest) { const page: AstroComponentFactory = async (result) => { @@ -42,19 +52,19 @@ export function createEndpoint(manifest: SSRManifest) { const request = result.request; const raw = await request.text(); const data = JSON.parse(raw) as RenderOptions; - if(!params.name) { + if (!params.name) { return new Response(null, { status: 400, - statusText: 'Bad request' + statusText: 'Bad request', }); } const componentId = params.name; const imp = manifest.serverIslandMap?.get(componentId); - if(!imp) { + if (!imp) { return new Response(null, { status: 404, - statusText: 'Not found' + statusText: 'Not found', }); } @@ -63,15 +73,15 @@ export function createEndpoint(manifest: SSRManifest) { const Component = (componentModule as any)[data.componentExport]; const slots: ComponentSlots = {}; - for(const prop in data.slots) { + for (const prop in data.slots) { slots[prop] = createSlotValueFromString(data.slots[prop]); } return renderTemplate`${renderComponent(result, 'Component', Component, props, slots)}`; - } + }; page.isAstroComponentFactory = true; - + const instance: ComponentInstance = { default: page, partial: true, @@ -79,4 +89,3 @@ export function createEndpoint(manifest: SSRManifest) { return instance; } - diff --git a/packages/astro/src/core/server-islands/vite-plugin-server-islands.ts b/packages/astro/src/core/server-islands/vite-plugin-server-islands.ts index c657a4569d..573ae9cf97 100644 --- a/packages/astro/src/core/server-islands/vite-plugin-server-islands.ts +++ b/packages/astro/src/core/server-islands/vite-plugin-server-islands.ts @@ -1,10 +1,10 @@ -import type { AstroPluginMetadata } from '../../vite-plugin-astro/index.js'; -import type { AstroSettings } from '../../@types/astro.js'; import type { ConfigEnv, ViteDevServer, Plugin as VitePlugin } from 'vite'; +import type { AstroSettings } from '../../@types/astro.js'; +import type { AstroPluginMetadata } from '../../vite-plugin-astro/index.js'; export const VIRTUAL_ISLAND_MAP_ID = '@astro-server-islands'; export const RESOLVED_VIRTUAL_ISLAND_MAP_ID = '\0' + VIRTUAL_ISLAND_MAP_ID; -const serverIslandPlaceholder = '\'$$server-islands$$\''; +const serverIslandPlaceholder = "'$$server-islands$$'"; export function vitePluginServerIslands({ settings }: { settings: AstroSettings }): VitePlugin { let command: ConfigEnv['command'] = 'serve'; @@ -20,29 +20,29 @@ export function vitePluginServerIslands({ settings }: { settings: AstroSettings viteServer = _server; }, resolveId(name) { - if(name === VIRTUAL_ISLAND_MAP_ID) { + if (name === VIRTUAL_ISLAND_MAP_ID) { return RESOLVED_VIRTUAL_ISLAND_MAP_ID; } }, load(id) { - if(id === RESOLVED_VIRTUAL_ISLAND_MAP_ID) { + if (id === RESOLVED_VIRTUAL_ISLAND_MAP_ID) { return `export const serverIslandMap = ${serverIslandPlaceholder};`; } }, transform(_code, id) { - if(id.endsWith('.astro')) { + if (id.endsWith('.astro')) { const info = this.getModuleInfo(id); - if(info?.meta) { + if (info?.meta) { const astro = info.meta.astro as AstroPluginMetadata['astro'] | undefined; - if(astro?.serverComponents.length) { - for(const comp of astro.serverComponents) { - if(!settings.serverIslandNameMap.has(comp.resolvedPath)) { + if (astro?.serverComponents.length) { + for (const comp of astro.serverComponents) { + if (!settings.serverIslandNameMap.has(comp.resolvedPath)) { let name = comp.localName; let idx = 1; - while(true) { + while (true) { // Name not taken, let's use it. - if(!settings.serverIslandMap.has(name)) { + if (!settings.serverIslandMap.has(name)) { break; } // Increment a number onto the name: Avatar -> Avatar1 @@ -57,12 +57,12 @@ export function vitePluginServerIslands({ settings }: { settings: AstroSettings }); // Build mode - if(command === 'build') { + if (command === 'build') { let referenceId = this.emitFile({ type: 'chunk', id: comp.specifier, importer: id, - name: comp.localName + name: comp.localName, }); referenceIdMap.set(comp.resolvedPath, referenceId); @@ -74,17 +74,17 @@ export function vitePluginServerIslands({ settings }: { settings: AstroSettings } }, renderChunk(code) { - if(code.includes(serverIslandPlaceholder)) { + if (code.includes(serverIslandPlaceholder)) { let mapSource = 'new Map(['; - for(let [resolvedPath, referenceId] of referenceIdMap) { + for (let [resolvedPath, referenceId] of referenceIdMap) { const fileName = this.getFileName(referenceId); const islandName = settings.serverIslandNameMap.get(resolvedPath)!; - mapSource += `\n\t['${islandName}', () => import('./${fileName}')],` + mapSource += `\n\t['${islandName}', () => import('./${fileName}')],`; } mapSource += '\n]);'; referenceIdMap.clear(); return code.replace(serverIslandPlaceholder, mapSource); } }, - } + }; } diff --git a/packages/astro/src/jsx/babel.ts b/packages/astro/src/jsx/babel.ts index 19425a03f0..02280031b1 100644 --- a/packages/astro/src/jsx/babel.ts +++ b/packages/astro/src/jsx/babel.ts @@ -3,8 +3,8 @@ import * as t from '@babel/types'; import { AstroError } from '../core/errors/errors.js'; import { AstroErrorData } from '../core/errors/index.js'; import { resolvePath } from '../core/viteUtils.js'; -import type { PluginMetadata } from '../vite-plugin-astro/types.js'; import { createDefaultAstroMetadata } from '../vite-plugin-astro/metadata.js'; +import type { PluginMetadata } from '../vite-plugin-astro/types.js'; const ClientOnlyPlaceholder = 'astro-client-only'; diff --git a/packages/astro/src/runtime/server/endpoint.ts b/packages/astro/src/runtime/server/endpoint.ts index d1d4afbebb..8cd6763912 100644 --- a/packages/astro/src/runtime/server/endpoint.ts +++ b/packages/astro/src/runtime/server/endpoint.ts @@ -26,7 +26,6 @@ export async function renderEndpoint( ); } if (handler === undefined) { - logger.warn( 'router', `No API Route handler exists for the method "${method}" for the route "${url.pathname}".\n` + diff --git a/packages/astro/src/runtime/server/render/astro/factory.ts b/packages/astro/src/runtime/server/render/astro/factory.ts index e4f726f50c..52b438c2b6 100644 --- a/packages/astro/src/runtime/server/render/astro/factory.ts +++ b/packages/astro/src/runtime/server/render/astro/factory.ts @@ -6,7 +6,11 @@ export type AstroFactoryReturnValue = RenderTemplateResult | Response | HeadAndC // The callback passed to to $$createComponent export interface AstroComponentFactory { - (result: SSRResult, props: any, slots: any): AstroFactoryReturnValue | Promise<AstroFactoryReturnValue>; + ( + result: SSRResult, + props: any, + slots: any + ): AstroFactoryReturnValue | Promise<AstroFactoryReturnValue>; isAstroComponentFactory?: boolean; moduleId?: string | undefined; propagation?: PropagationHint; diff --git a/packages/astro/src/runtime/server/render/component.ts b/packages/astro/src/runtime/server/render/component.ts index 001668d6d2..0b552b9506 100644 --- a/packages/astro/src/runtime/server/render/component.ts +++ b/packages/astro/src/runtime/server/render/component.ts @@ -27,9 +27,9 @@ import { } from './common.js'; import { componentIsHTMLElement, renderHTMLElement } from './dom.js'; import { maybeRenderHead } from './head.js'; +import { containsServerDirective, renderServerIsland } from './server-islands.js'; import { type ComponentSlots, renderSlotToString, renderSlots } from './slot.js'; import { formatList, internalSpreadAttributes, renderElement, voidElementNames } from './util.js'; -import { containsServerDirective, renderServerIsland } from './server-islands.js'; const needsHeadRenderingSymbol = Symbol.for('astro.needsHeadRendering'); const rendererAliases = new Map([['solid', 'solid-js']]); @@ -474,10 +474,10 @@ function renderAstroComponent( props: Record<string | number, any>, slots: any = {} ): RenderInstance { - if(containsServerDirective(props)) { + if (containsServerDirective(props)) { return renderServerIsland(result, displayName, props, slots); } - + const instance = createAstroComponentInstance(result, displayName, Component, props, slots); return { async render(destination) { diff --git a/packages/astro/src/runtime/server/render/server-islands.ts b/packages/astro/src/runtime/server/render/server-islands.ts index 5a1e45c59c..ee6b03ae21 100644 --- a/packages/astro/src/runtime/server/render/server-islands.ts +++ b/packages/astro/src/runtime/server/render/server-islands.ts @@ -1,18 +1,16 @@ -import type { - SSRResult, -} from '../../../@types/astro.js'; -import { renderChild } from "./any.js"; -import type { RenderInstance } from "./common.js"; -import { renderSlotToString, type ComponentSlots } from "./slot.js"; +import type { SSRResult } from '../../../@types/astro.js'; +import { renderChild } from './any.js'; +import type { RenderInstance } from './common.js'; +import { type ComponentSlots, renderSlotToString } from './slot.js'; const internalProps = new Set([ 'server:component-path', 'server:component-export', 'server:component-directive', - 'server:defer' + 'server:defer', ]); -export function containsServerDirective(props: Record<string | number, any>,) { +export function containsServerDirective(props: Record<string | number, any>) { return 'server:component-directive' in props; } @@ -20,7 +18,7 @@ export function renderServerIsland( result: SSRResult, _displayName: string, props: Record<string | number, any>, - slots: ComponentSlots, + slots: ComponentSlots ): RenderInstance { return { async render(destination) { @@ -28,23 +26,23 @@ export function renderServerIsland( const componentExport = props['server:component-export']; const componentId = result.serverIslandNameMap.get(componentPath); - if(!componentId) { + if (!componentId) { throw new Error(`Could not find server component name`); } // Remove internal props - for(const key of Object.keys(props)) { - if(internalProps.has(key)) { + for (const key of Object.keys(props)) { + if (internalProps.has(key)) { delete props[key]; } } - - destination.write('<!--server-island-start-->') + + destination.write('<!--server-island-start-->'); // Render the slots const renderedSlots: Record<string, string> = {}; - for(const name in slots) { - if(name !== 'fallback') { + for (const name in slots) { + if (name !== 'fallback') { const content = await renderSlotToString(result, slots[name]); renderedSlots[name] = content.toString(); } else { @@ -83,7 +81,7 @@ if(response.status === 200 && response.headers.get('content-type') === 'text/htm script.before(frag); } script.remove(); -</script>`) - } - } +</script>`); + }, + }; } diff --git a/packages/astro/src/runtime/server/render/slot.ts b/packages/astro/src/runtime/server/render/slot.ts index fae7edc9eb..bf5a2bb3b8 100644 --- a/packages/astro/src/runtime/server/render/slot.ts +++ b/packages/astro/src/runtime/server/render/slot.ts @@ -105,7 +105,7 @@ export async function renderSlots( } export function createSlotValueFromString(content: string): ComponentSlotValue { - return function() { + return function () { return renderTemplate`${unescapeHTML(content)}`; }; } diff --git a/packages/astro/src/vite-plugin-astro-server/pipeline.ts b/packages/astro/src/vite-plugin-astro-server/pipeline.ts index c41d5bbcd9..7ad9ead1ea 100644 --- a/packages/astro/src/vite-plugin-astro-server/pipeline.ts +++ b/packages/astro/src/vite-plugin-astro-server/pipeline.ts @@ -158,8 +158,8 @@ export class DevPipeline extends Pipeline { const { loader } = this; // First check built-in routes - for(const route of this.defaultRoutes) { - if(route.matchesComponent(filePath)) { + for (const route of this.defaultRoutes) { + if (route.matchesComponent(filePath)) { return route.instance; } } @@ -226,8 +226,8 @@ export class DevPipeline extends Pipeline { rewriteKnownRoute(route: string, sourceRoute: RouteData): ComponentInstance { if (isServerLikeOutput(this.config) && sourceRoute.prerender) { - for(let def of this.defaultRoutes) { - if(route === def.route) { + for (let def of this.defaultRoutes) { + if (route === def.route) { return def.instance; } } diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index ba94d7cbf2..9904d2844d 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -9,8 +9,8 @@ import { AstroError, AstroErrorData } from '../core/errors/index.js'; import { patchOverlay } from '../core/errors/overlay.js'; import type { Logger } from '../core/logger/core.js'; import { createViteLoader } from '../core/module-loader/index.js'; -import { createRouteManifest } from '../core/routing/index.js'; import { injectDefaultRoutes } from '../core/routing/default.js'; +import { createRouteManifest } from '../core/routing/index.js'; import { toRoutingStrategy } from '../i18n/utils.js'; import { baseMiddleware } from './base.js'; import { createController } from './controller.js'; @@ -36,7 +36,7 @@ export default function createVitePluginAstroServer({ const loader = createViteLoader(viteServer); const manifest = createDevelopmentManifest(settings); let manifestData: ManifestData = injectDefaultRoutes( - createRouteManifest({ settings, fsMod }, logger), + createRouteManifest({ settings, fsMod }, logger) ); const pipeline = DevPipeline.create(manifestData, { loader, logger, manifest, settings }); const controller = createController({ loader }); @@ -46,9 +46,7 @@ export default function createVitePluginAstroServer({ function rebuildManifest(needsManifestRebuild: boolean) { pipeline.clearRouteCache(); if (needsManifestRebuild) { - manifestData = injectDefaultRoutes( - createRouteManifest({ settings }, logger), - ); + manifestData = injectDefaultRoutes(createRouteManifest({ settings }, logger)); pipeline.setManifestData(manifestData); } } diff --git a/packages/astro/src/vite-plugin-markdown/index.ts b/packages/astro/src/vite-plugin-markdown/index.ts index 25a5ab6484..6859af1483 100644 --- a/packages/astro/src/vite-plugin-markdown/index.ts +++ b/packages/astro/src/vite-plugin-markdown/index.ts @@ -13,9 +13,9 @@ import { AstroError, AstroErrorData } from '../core/errors/index.js'; import type { Logger } from '../core/logger/core.js'; import { isMarkdownFile } from '../core/util.js'; import { shorthash } from '../runtime/server/shorthash.js'; +import { createDefaultAstroMetadata } from '../vite-plugin-astro/metadata.js'; import { getFileInfo } from '../vite-plugin-utils/index.js'; import { type MarkdownImagePath, getMarkdownCodeForImages } from './images.js'; -import { createDefaultAstroMetadata } from '../vite-plugin-astro/metadata.js'; interface AstroPluginOptions { settings: AstroSettings; diff --git a/packages/astro/test/server-islands.test.js b/packages/astro/test/server-islands.test.js index 60fece1e46..2b784276de 100644 --- a/packages/astro/test/server-islands.test.js +++ b/packages/astro/test/server-islands.test.js @@ -1,4 +1,3 @@ - import assert from 'node:assert/strict'; import { after, before, describe, it } from 'node:test'; import * as cheerio from 'cheerio'; @@ -27,22 +26,22 @@ describe('Server islands', () => { await devServer.stop(); }); - it('omits the islands HTML', async () => { + it('omits the islands HTML', async () => { const res = await fixture.fetch('/'); assert.equal(res.status, 200); const html = await res.text(); const $ = cheerio.load(html); const serverIslandEl = $('h2#island'); assert.equal(serverIslandEl.length, 0); - }); - }); + }); + }); describe('prod', () => { before(async () => { await fixture.build(); }); - it('omits the islands HTML', async () => { + it('omits the islands HTML', async () => { const app = await fixture.loadTestAdapterApp(); const request = new Request('http://example.com/'); const response = await app.render(request); @@ -54,8 +53,8 @@ describe('Server islands', () => { const serverIslandScript = $('script[data-island-id]'); assert.equal(serverIslandScript.length, 1, 'has the island script'); - }); - }); + }); + }); }); describe('Hybrid mode', () => { @@ -93,11 +92,11 @@ describe('Server islands', () => { componentExport: 'default', props: {}, slots: {}, - }) + }), }); return app.render(request); } - + it('Island returns its HTML', async () => { const response = await fetchIsland(); const html = await response.text();