mirror of
https://github.com/withastro/astro.git
synced 2025-01-06 22:10:10 -05:00
[ci] format
This commit is contained in:
parent
d495df5361
commit
b46a78e1c9
26 changed files with 1602 additions and 1319 deletions
|
@ -43,7 +43,21 @@ html {
|
||||||
-o-tab-size: 4;
|
-o-tab-size: 4;
|
||||||
tab-size: 4;
|
tab-size: 4;
|
||||||
/* 3 */
|
/* 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";
|
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 */
|
/* 4 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +138,8 @@ code,
|
||||||
kbd,
|
kbd,
|
||||||
samp,
|
samp,
|
||||||
pre {
|
pre {
|
||||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
|
||||||
|
'Courier New', monospace;
|
||||||
/* 1 */
|
/* 1 */
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
/* 2 */
|
/* 2 */
|
||||||
|
@ -347,14 +362,16 @@ textarea {
|
||||||
2. Set the default placeholder color to the user's configured gray 400 color.
|
2. Set the default placeholder color to the user's configured gray 400 color.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
input::-moz-placeholder, textarea::-moz-placeholder {
|
input::-moz-placeholder,
|
||||||
|
textarea::-moz-placeholder {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
/* 1 */
|
/* 1 */
|
||||||
color: #9ca3af;
|
color: #9ca3af;
|
||||||
/* 2 */
|
/* 2 */
|
||||||
}
|
}
|
||||||
|
|
||||||
input:-ms-input-placeholder, textarea:-ms-input-placeholder {
|
input:-ms-input-placeholder,
|
||||||
|
textarea:-ms-input-placeholder {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
/* 1 */
|
/* 1 */
|
||||||
color: #9ca3af;
|
color: #9ca3af;
|
||||||
|
@ -374,7 +391,7 @@ Set the default cursor for buttons.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
button,
|
button,
|
||||||
[role="button"] {
|
[role='button'] {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,7 +441,21 @@ Ensure the default browser behavior of the `hidden` attribute.
|
||||||
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 {
|
[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;
|
-webkit-appearance: none;
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
|
@ -441,30 +472,49 @@ Ensure the default browser behavior of the `hidden` attribute.
|
||||||
--tw-shadow: 0 0 #0000;
|
--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 {
|
[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: 2px solid transparent;
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
--tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);
|
--tw-ring-inset: var(--tw-empty, /*!*/ /*!*/);
|
||||||
--tw-ring-offset-width: 0px;
|
--tw-ring-offset-width: 0px;
|
||||||
--tw-ring-offset-color: #fff;
|
--tw-ring-offset-color: #fff;
|
||||||
--tw-ring-color: #2563eb;
|
--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-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
||||||
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
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);
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||||
border-color: #2563eb;
|
border-color: #2563eb;
|
||||||
}
|
}
|
||||||
|
|
||||||
input::-moz-placeholder, textarea::-moz-placeholder {
|
input::-moz-placeholder,
|
||||||
|
textarea::-moz-placeholder {
|
||||||
color: #6b7280;
|
color: #6b7280;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
input:-ms-input-placeholder, textarea:-ms-input-placeholder {
|
input:-ms-input-placeholder,
|
||||||
|
textarea:-ms-input-placeholder {
|
||||||
color: #6b7280;
|
color: #6b7280;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
input::placeholder,textarea::placeholder {
|
input::placeholder,
|
||||||
|
textarea::placeholder {
|
||||||
color: #6b7280;
|
color: #6b7280;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
@ -477,7 +527,15 @@ input::placeholder,textarea::placeholder {
|
||||||
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 {
|
::-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-top: 0;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
@ -502,7 +560,8 @@ select {
|
||||||
color-adjust: unset;
|
color-adjust: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
[type='checkbox'],[type='radio'] {
|
[type='checkbox'],
|
||||||
|
[type='radio'] {
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
|
@ -534,19 +593,23 @@ select {
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
[type='checkbox']:focus,[type='radio']:focus {
|
[type='checkbox']:focus,
|
||||||
|
[type='radio']:focus {
|
||||||
outline: 2px solid transparent;
|
outline: 2px solid transparent;
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
--tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);
|
--tw-ring-inset: var(--tw-empty, /*!*/ /*!*/);
|
||||||
--tw-ring-offset-width: 2px;
|
--tw-ring-offset-width: 2px;
|
||||||
--tw-ring-offset-color: #fff;
|
--tw-ring-offset-color: #fff;
|
||||||
--tw-ring-color: #2563eb;
|
--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-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
||||||
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
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);
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
[type='checkbox']:checked,[type='radio']:checked {
|
[type='checkbox']:checked,
|
||||||
|
[type='radio']:checked {
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
background-color: currentColor;
|
background-color: currentColor;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
|
@ -562,7 +625,10 @@ select {
|
||||||
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 {
|
[type='checkbox']:checked:hover,
|
||||||
|
[type='checkbox']:checked:focus,
|
||||||
|
[type='radio']:checked:hover,
|
||||||
|
[type='radio']:checked:focus {
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
background-color: currentColor;
|
background-color: currentColor;
|
||||||
}
|
}
|
||||||
|
@ -576,7 +642,8 @@ select {
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
[type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus {
|
[type='checkbox']:indeterminate:hover,
|
||||||
|
[type='checkbox']:indeterminate:focus {
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
background-color: currentColor;
|
background-color: currentColor;
|
||||||
}
|
}
|
||||||
|
@ -599,11 +666,18 @@ body {
|
||||||
font-family: Poppins, sans-serif;
|
font-family: Poppins, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
font-family: Roboto, sans-serif;
|
font-family: Roboto, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
*, ::before, ::after {
|
*,
|
||||||
|
::before,
|
||||||
|
::after {
|
||||||
--tw-translate-x: 0;
|
--tw-translate-x: 0;
|
||||||
--tw-translate-y: 0;
|
--tw-translate-y: 0;
|
||||||
--tw-rotate: 0;
|
--tw-rotate: 0;
|
||||||
|
@ -694,8 +768,10 @@ h1, h2, h3, h4, h5, h6 {
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-selector input:checked + label {
|
.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-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
||||||
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
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);
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
||||||
--tw-ring-opacity: 1;
|
--tw-ring-opacity: 1;
|
||||||
--tw-ring-color: rgb(253 61 87 / var(--tw-ring-opacity));
|
--tw-ring-color: rgb(253 61 87 / var(--tw-ring-opacity));
|
||||||
|
@ -736,8 +812,10 @@ h1, h2, h3, h4, h5, h6 {
|
||||||
.input-box:focus {
|
.input-box:focus {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: rgb(253 61 87 / var(--tw-border-opacity));
|
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-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
||||||
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
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);
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1546,7 +1624,7 @@ h1, h2, h3, h4, h5, h6 {
|
||||||
}
|
}
|
||||||
|
|
||||||
.leading-3 {
|
.leading-3 {
|
||||||
line-height: .75rem;
|
line-height: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tracking-wider {
|
.tracking-wider {
|
||||||
|
@ -1635,25 +1713,53 @@ h1, h2, h3, h4, h5, h6 {
|
||||||
.shadow-sm {
|
.shadow-sm {
|
||||||
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||||
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
|
--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);
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
|
||||||
|
var(--tw-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.shadow-md {
|
.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: 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);
|
--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);
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
|
||||||
|
var(--tw-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.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: 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);
|
--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);
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
|
||||||
|
var(--tw-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.transition {
|
.transition {
|
||||||
transition-property: color, background-color, border-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-text-decoration-color, -webkit-backdrop-filter;
|
transition-property:
|
||||||
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
|
color,
|
||||||
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;
|
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-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
transition-duration: 150ms;
|
transition-duration: 150ms;
|
||||||
}
|
}
|
||||||
|
@ -1717,8 +1823,10 @@ h1, h2, h3, h4, h5, h6 {
|
||||||
}
|
}
|
||||||
|
|
||||||
.focus\:ring-0:focus {
|
.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-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
||||||
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
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);
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"}
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
@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 base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
|
|
|
@ -5,17 +5,21 @@ const { placeholder } = Astro.props;
|
||||||
let wishlist = 0;
|
let wishlist = 0;
|
||||||
let cart = 0;
|
let cart = 0;
|
||||||
|
|
||||||
if(!placeholder) {
|
if (!placeholder) {
|
||||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
<a href="#" class="text-center text-gray-700 hover:text-primary transition relative">
|
<a href="#" class="text-center text-gray-700 hover:text-primary transition relative">
|
||||||
<div class="text-2xl">
|
<div class="text-2xl">
|
||||||
<i class="fa-regular fa-heart"></i>
|
<i class="fa-regular fa-heart"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs leading-3">Wishlist</div>
|
<div class="text-xs leading-3">Wishlist</div>
|
||||||
<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>
|
||||||
<a href="#" class="text-center text-gray-700 hover:text-primary transition relative">
|
<a href="#" class="text-center text-gray-700 hover:text-primary transition relative">
|
||||||
<div class="text-2xl">
|
<div class="text-2xl">
|
||||||
|
|
|
@ -4,41 +4,48 @@ import AddToCart from '../components/AddToCart';
|
||||||
import PersonalBar from '../components/PersonalBar.astro';
|
import PersonalBar from '../components/PersonalBar.astro';
|
||||||
import '@fortawesome/fontawesome-free/css/all.min.css';
|
import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
---
|
---
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
<!doctype html>
|
||||||
<meta charset="UTF-8">
|
<html lang="en">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<head>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<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>
|
<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.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&family=Roboto:wght@400;500;700&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&family=Roboto:wght@400;500;700&display=swap"
|
||||||
rel="stylesheet">
|
rel="stylesheet"
|
||||||
</head>
|
/>
|
||||||
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<!-- header -->
|
<!-- header -->
|
||||||
<header class="py-4 shadow-sm bg-white">
|
<header class="py-4 shadow-sm bg-white">
|
||||||
<div class="container flex items-center justify-between">
|
<div class="container flex items-center justify-between">
|
||||||
<a href="index.html">
|
<a href="index.html">
|
||||||
<img src="../assets/images/logo.svg" alt="Logo" class="w-32">
|
<img src="../assets/images/logo.svg" alt="Logo" class="w-32" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="w-full max-w-xl relative flex">
|
<div class="w-full max-w-xl relative flex">
|
||||||
<span class="absolute left-4 top-3 text-lg text-gray-400">
|
<span class="absolute left-4 top-3 text-lg text-gray-400">
|
||||||
<i class="fa-solid fa-magnifying-glass"></i>
|
<i class="fa-solid fa-magnifying-glass"></i>
|
||||||
</span>
|
</span>
|
||||||
<input type="text" name="search" id="search"
|
<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"
|
class="w-full border border-primary border-r-0 pl-12 py-3 pr-3 rounded-l-md focus:outline-none"
|
||||||
placeholder="search">
|
placeholder="search"
|
||||||
|
/>
|
||||||
<button
|
<button
|
||||||
class="bg-primary border border-primary text-white px-8 rounded-r-md hover:bg-transparent hover:text-primary transition">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>
|
||||||
|
|
||||||
<div class="flex items-center space-x-4">
|
<div class="flex items-center space-x-4">
|
||||||
|
@ -61,29 +68,50 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
|
|
||||||
<!-- dropdown -->
|
<!-- dropdown -->
|
||||||
<div
|
<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">
|
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">
|
<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">
|
<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>
|
<span class="ml-6 text-gray-600 text-sm">Sofa</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition">
|
<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">
|
<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>
|
<span class="ml-6 text-gray-600 text-sm">Terarce</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition">
|
<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">
|
<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>
|
<span class="ml-6 text-gray-600 text-sm">Bed</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition">
|
<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">
|
<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>
|
<span class="ml-6 text-gray-600 text-sm">office</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition">
|
<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">
|
<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>
|
<span class="ml-6 text-gray-600 text-sm">Outdoor</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="#" class="flex items-center px-6 py-3 hover:bg-gray-100 transition">
|
<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">
|
<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>
|
<span class="ml-6 text-gray-600 text-sm">Mattress</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -117,14 +145,33 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
<!-- product-detail -->
|
<!-- product-detail -->
|
||||||
<div class="container grid grid-cols-2 gap-6">
|
<div class="container grid grid-cols-2 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<img src="../assets/images/products/product1.jpg" alt="product" class="w-full">
|
<img src="../assets/images/products/product1.jpg" alt="product" class="w-full" />
|
||||||
<div class="grid grid-cols-5 gap-4 mt-4">
|
<div class="grid grid-cols-5 gap-4 mt-4">
|
||||||
<img src="../assets/images/products/product2.jpg" alt="product2"
|
<img
|
||||||
class="w-full cursor-pointer border border-primary">
|
src="../assets/images/products/product2.jpg"
|
||||||
<img src="../assets/images/products/product3.jpg" alt="product2" class="w-full cursor-pointer border">
|
alt="product2"
|
||||||
<img src="../assets/images/products/product4.jpg" alt="product2" class="w-full cursor-pointer border">
|
class="w-full cursor-pointer border border-primary"
|
||||||
<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">
|
<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>
|
</div>
|
||||||
|
|
||||||
|
@ -163,37 +210,54 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
<p class="text-base text-gray-400 line-through">$55.00</p>
|
<p class="text-base text-gray-400 line-through">$55.00</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="mt-4 text-gray-600">Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos eius eum
|
<p class="mt-4 text-gray-600">
|
||||||
reprehenderit dolore vel mollitia optio consequatur hic asperiores inventore suscipit, velit
|
Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos eius eum reprehenderit dolore
|
||||||
consequuntur, voluptate doloremque iure necessitatibus adipisci magnam porro.</p>
|
vel mollitia optio consequatur hic asperiores inventore suscipit, velit consequuntur,
|
||||||
|
voluptate doloremque iure necessitatibus adipisci magnam porro.
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="pt-4">
|
<div class="pt-4">
|
||||||
<h3 class="text-sm text-gray-800 uppercase mb-1">Size</h3>
|
<h3 class="text-sm text-gray-800 uppercase mb-1">Size</h3>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div class="size-selector">
|
<div class="size-selector">
|
||||||
<input type="radio" name="size" id="size-xs" class="hidden">
|
<input type="radio" name="size" id="size-xs" class="hidden" />
|
||||||
<label for="size-xs"
|
<label
|
||||||
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>
|
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>
|
||||||
<div class="size-selector">
|
<div class="size-selector">
|
||||||
<input type="radio" name="size" id="size-sm" class="hidden">
|
<input type="radio" name="size" id="size-sm" class="hidden" />
|
||||||
<label for="size-sm"
|
<label
|
||||||
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>
|
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>
|
||||||
<div class="size-selector">
|
<div class="size-selector">
|
||||||
<input type="radio" name="size" id="size-m" class="hidden">
|
<input type="radio" name="size" id="size-m" class="hidden" />
|
||||||
<label for="size-m"
|
<label
|
||||||
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>
|
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>
|
||||||
<div class="size-selector">
|
<div class="size-selector">
|
||||||
<input type="radio" name="size" id="size-l" class="hidden">
|
<input type="radio" name="size" id="size-l" class="hidden" />
|
||||||
<label for="size-l"
|
<label
|
||||||
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>
|
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>
|
||||||
<div class="size-selector">
|
<div class="size-selector">
|
||||||
<input type="radio" name="size" id="size-xl" class="hidden">
|
<input type="radio" name="size" id="size-xl" class="hidden" />
|
||||||
<label for="size-xl"
|
<label
|
||||||
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>
|
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>
|
||||||
</div>
|
</div>
|
||||||
|
@ -202,55 +266,73 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
<h3 class="text-xl text-gray-800 mb-3 uppercase font-medium">Color</h3>
|
<h3 class="text-xl text-gray-800 mb-3 uppercase font-medium">Color</h3>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div class="color-selector">
|
<div class="color-selector">
|
||||||
<input type="radio" name="color" id="red" class="hidden">
|
<input type="radio" name="color" id="red" class="hidden" />
|
||||||
<label for="red"
|
<label
|
||||||
|
for="red"
|
||||||
class="border border-gray-200 rounded-sm h-6 w-6 cursor-pointer shadow-sm block"
|
class="border border-gray-200 rounded-sm h-6 w-6 cursor-pointer shadow-sm block"
|
||||||
style="background-color: #fc3d57;"></label>
|
style="background-color: #fc3d57;"></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="color-selector">
|
<div class="color-selector">
|
||||||
<input type="radio" name="color" id="black" class="hidden">
|
<input type="radio" name="color" id="black" class="hidden" />
|
||||||
<label for="black"
|
<label
|
||||||
|
for="black"
|
||||||
class="border border-gray-200 rounded-sm h-6 w-6 cursor-pointer shadow-sm block"
|
class="border border-gray-200 rounded-sm h-6 w-6 cursor-pointer shadow-sm block"
|
||||||
style="background-color: #000;"></label>
|
style="background-color: #000;"></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="color-selector">
|
<div class="color-selector">
|
||||||
<input type="radio" name="color" id="white" class="hidden">
|
<input type="radio" name="color" id="white" class="hidden" />
|
||||||
<label for="white"
|
<label
|
||||||
|
for="white"
|
||||||
class="border border-gray-200 rounded-sm h-6 w-6 cursor-pointer shadow-sm block"
|
class="border border-gray-200 rounded-sm h-6 w-6 cursor-pointer shadow-sm block"
|
||||||
style="background-color: #fff;"></label>
|
style="background-color: #fff;"></label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<h3 class="text-sm text-gray-800 uppercase mb-1">Quantity</h3>
|
<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="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-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-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
|
||||||
|
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">
|
<div class="mt-6 flex gap-3 border-b border-gray-200 pb-5 pt-5">
|
||||||
<AddToCart client:load />
|
<AddToCart client:load />
|
||||||
<a href="#"
|
<a
|
||||||
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">
|
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
|
<i class="fa-solid fa-heart"></i> Wishlist
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex gap-3 mt-4">
|
<div class="flex gap-3 mt-4">
|
||||||
<a href="#"
|
<a
|
||||||
class="text-gray-400 hover:text-gray-500 h-8 w-8 rounded-full border border-gray-300 flex items-center justify-center">
|
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>
|
<i class="fa-brands fa-facebook-f"></i>
|
||||||
</a>
|
</a>
|
||||||
<a href="#"
|
<a
|
||||||
class="text-gray-400 hover:text-gray-500 h-8 w-8 rounded-full border border-gray-300 flex items-center justify-center">
|
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>
|
<i class="fa-brands fa-twitter"></i>
|
||||||
</a>
|
</a>
|
||||||
<a href="#"
|
<a
|
||||||
class="text-gray-400 hover:text-gray-500 h-8 w-8 rounded-full border border-gray-300 flex items-center justify-center">
|
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>
|
<i class="fa-brands fa-instagram"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -260,32 +342,40 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
|
|
||||||
<!-- description -->
|
<!-- description -->
|
||||||
<div class="container pb-16">
|
<div class="container pb-16">
|
||||||
<h3 class="border-b border-gray-200 font-roboto text-gray-800 pb-3 font-medium">Product details</h3>
|
<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="w-3/5 pt-6">
|
||||||
<div class="text-gray-600">
|
<div class="text-gray-600">
|
||||||
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tenetur necessitatibus deleniti natus
|
<p>
|
||||||
dolore cum maiores suscipit optio itaque voluptatibus veritatis tempora iste facilis non aut
|
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Tenetur necessitatibus
|
||||||
sapiente dolor quisquam, ex ab.</p>
|
deleniti natus dolore cum maiores suscipit optio itaque voluptatibus veritatis tempora
|
||||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorum, quae accusantium voluptatem
|
iste facilis non aut sapiente dolor quisquam, ex ab.
|
||||||
blanditiis sapiente voluptatum. Autem ab, dolorum assumenda earum veniam eius illo fugiat possimus
|
</p>
|
||||||
illum dolor totam, ducimus excepturi.</p>
|
<p>
|
||||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Error quia modi ut expedita! Iure molestiae
|
Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorum, quae accusantium
|
||||||
labore cumque nobis quasi fuga, quibusdam rem? Temporibus consectetur corrupti rerum veritatis
|
voluptatem blanditiis sapiente voluptatum. Autem ab, dolorum assumenda earum veniam eius
|
||||||
numquam labore amet.</p>
|
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>
|
||||||
|
|
||||||
<table class="table-auto border-collapse w-full text-left text-gray-600 text-sm mt-6">
|
<table class="table-auto border-collapse w-full text-left text-gray-600 text-sm mt-6">
|
||||||
<tr>
|
<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 w-40 font-medium">Color</th>
|
||||||
<th class="py-2 px-4 border border-gray-300 ">Blank, Brown, Red</th>
|
<th class="py-2 px-4 border border-gray-300">Blank, Brown, Red</th>
|
||||||
</tr>
|
</tr>
|
||||||
<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 w-40 font-medium">Material</th>
|
||||||
<th class="py-2 px-4 border border-gray-300 ">Latex</th>
|
<th class="py-2 px-4 border border-gray-300">Latex</th>
|
||||||
</tr>
|
</tr>
|
||||||
<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 w-40 font-medium">Weight</th>
|
||||||
<th class="py-2 px-4 border border-gray-300 ">55kg</th>
|
<th class="py-2 px-4 border border-gray-300">55kg</th>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -298,25 +388,34 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
<div class="grid grid-cols-4 gap-6">
|
<div class="grid grid-cols-4 gap-6">
|
||||||
<div class="bg-white shadow rounded overflow-hidden group">
|
<div class="bg-white shadow rounded overflow-hidden group">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<img src="../assets/images/products/product1.jpg" alt="product 1" class="w-full">
|
<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
|
<div
|
||||||
justify-center gap-2 opacity-0 group-hover:opacity-100 transition">
|
class="absolute inset-0 bg-black bg-opacity-40 flex items-center
|
||||||
<a href="#"
|
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"
|
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">
|
title="view product"
|
||||||
|
>
|
||||||
<i class="fa-solid fa-magnifying-glass"></i>
|
<i class="fa-solid fa-magnifying-glass"></i>
|
||||||
</a>
|
</a>
|
||||||
<a href="#"
|
<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"
|
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">
|
title="add to wishlist"
|
||||||
|
>
|
||||||
<i class="fa-solid fa-heart"></i>
|
<i class="fa-solid fa-heart"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pt-4 pb-3 px-4">
|
<div class="pt-4 pb-3 px-4">
|
||||||
<a href="#">
|
<a href="#">
|
||||||
<h4 class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition">Guyer
|
<h4
|
||||||
Chair</h4>
|
class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition"
|
||||||
|
>
|
||||||
|
Guyer Chair
|
||||||
|
</h4>
|
||||||
</a>
|
</a>
|
||||||
<div class="flex items-baseline mb-1 space-x-2">
|
<div class="flex items-baseline mb-1 space-x-2">
|
||||||
<p class="text-xl text-primary font-semibold">$45.00</p>
|
<p class="text-xl text-primary font-semibold">$45.00</p>
|
||||||
|
@ -337,25 +436,34 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-white shadow rounded overflow-hidden group">
|
<div class="bg-white shadow rounded overflow-hidden group">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<img src="../assets/images/products/product4.jpg" alt="product 1" class="w-full">
|
<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
|
<div
|
||||||
justify-center gap-2 opacity-0 group-hover:opacity-100 transition">
|
class="absolute inset-0 bg-black bg-opacity-40 flex items-center
|
||||||
<a href="#"
|
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"
|
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">
|
title="view product"
|
||||||
|
>
|
||||||
<i class="fa-solid fa-magnifying-glass"></i>
|
<i class="fa-solid fa-magnifying-glass"></i>
|
||||||
</a>
|
</a>
|
||||||
<a href="#"
|
<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"
|
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">
|
title="add to wishlist"
|
||||||
|
>
|
||||||
<i class="fa-solid fa-heart"></i>
|
<i class="fa-solid fa-heart"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pt-4 pb-3 px-4">
|
<div class="pt-4 pb-3 px-4">
|
||||||
<a href="#">
|
<a href="#">
|
||||||
<h4 class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition">Bed
|
<h4
|
||||||
King Size</h4>
|
class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition"
|
||||||
|
>
|
||||||
|
Bed King Size
|
||||||
|
</h4>
|
||||||
</a>
|
</a>
|
||||||
<div class="flex items-baseline mb-1 space-x-2">
|
<div class="flex items-baseline mb-1 space-x-2">
|
||||||
<p class="text-xl text-primary font-semibold">$45.00</p>
|
<p class="text-xl text-primary font-semibold">$45.00</p>
|
||||||
|
@ -376,25 +484,34 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-white shadow rounded overflow-hidden group">
|
<div class="bg-white shadow rounded overflow-hidden group">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<img src="../assets/images/products/product2.jpg" alt="product 1" class="w-full">
|
<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
|
<div
|
||||||
justify-center gap-2 opacity-0 group-hover:opacity-100 transition">
|
class="absolute inset-0 bg-black bg-opacity-40 flex items-center
|
||||||
<a href="#"
|
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"
|
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">
|
title="view product"
|
||||||
|
>
|
||||||
<i class="fa-solid fa-magnifying-glass"></i>
|
<i class="fa-solid fa-magnifying-glass"></i>
|
||||||
</a>
|
</a>
|
||||||
<a href="#"
|
<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"
|
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">
|
title="add to wishlist"
|
||||||
|
>
|
||||||
<i class="fa-solid fa-heart"></i>
|
<i class="fa-solid fa-heart"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pt-4 pb-3 px-4">
|
<div class="pt-4 pb-3 px-4">
|
||||||
<a href="#">
|
<a href="#">
|
||||||
<h4 class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition">
|
<h4
|
||||||
Couple Sofa</h4>
|
class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition"
|
||||||
|
>
|
||||||
|
Couple Sofa
|
||||||
|
</h4>
|
||||||
</a>
|
</a>
|
||||||
<div class="flex items-baseline mb-1 space-x-2">
|
<div class="flex items-baseline mb-1 space-x-2">
|
||||||
<p class="text-xl text-primary font-semibold">$45.00</p>
|
<p class="text-xl text-primary font-semibold">$45.00</p>
|
||||||
|
@ -415,25 +532,34 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
</div>
|
</div>
|
||||||
<div class="bg-white shadow rounded overflow-hidden group">
|
<div class="bg-white shadow rounded overflow-hidden group">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<img src="../assets/images/products/product3.jpg" alt="product 1" class="w-full">
|
<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
|
<div
|
||||||
justify-center gap-2 opacity-0 group-hover:opacity-100 transition">
|
class="absolute inset-0 bg-black bg-opacity-40 flex items-center
|
||||||
<a href="#"
|
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"
|
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">
|
title="view product"
|
||||||
|
>
|
||||||
<i class="fa-solid fa-magnifying-glass"></i>
|
<i class="fa-solid fa-magnifying-glass"></i>
|
||||||
</a>
|
</a>
|
||||||
<a href="#"
|
<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"
|
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">
|
title="add to wishlist"
|
||||||
|
>
|
||||||
<i class="fa-solid fa-heart"></i>
|
<i class="fa-solid fa-heart"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pt-4 pb-3 px-4">
|
<div class="pt-4 pb-3 px-4">
|
||||||
<a href="#">
|
<a href="#">
|
||||||
<h4 class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition">
|
<h4
|
||||||
Mattrass X</h4>
|
class="uppercase font-medium text-xl mb-2 text-gray-800 hover:text-primary transition"
|
||||||
|
>
|
||||||
|
Mattrass X
|
||||||
|
</h4>
|
||||||
</a>
|
</a>
|
||||||
<div class="flex items-baseline mb-1 space-x-2">
|
<div class="flex items-baseline mb-1 space-x-2">
|
||||||
<p class="text-xl text-primary font-semibold">$45.00</p>
|
<p class="text-xl text-primary font-semibold">$45.00</p>
|
||||||
|
@ -460,19 +586,22 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
<footer class="bg-white pt-16 pb-12 border-t border-gray-100">
|
<footer class="bg-white pt-16 pb-12 border-t border-gray-100">
|
||||||
<div class="container grid grid-cols-3">
|
<div class="container grid grid-cols-3">
|
||||||
<div class="col-span-1 space-y-8 mr-2">
|
<div class="col-span-1 space-y-8 mr-2">
|
||||||
<img src="../assets/images/logo.svg" alt="logo" class="w-30">
|
<img src="../assets/images/logo.svg" alt="logo" class="w-30" />
|
||||||
<div class="mr-2">
|
<div class="mr-2">
|
||||||
<p class="text-gray-500">
|
<p class="text-gray-500">
|
||||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quia, hic?
|
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quia, hic?
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex space-x-6">
|
<div class="flex space-x-6">
|
||||||
<a href="#" class="text-gray-400 hover:text-gray-500"><i
|
<a href="#" class="text-gray-400 hover:text-gray-500"
|
||||||
class="fa-brands fa-facebook-square"></i></a>
|
><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"
|
||||||
<a href="#" class="text-gray-400 hover:text-gray-500"><i
|
><i class="fa-brands fa-instagram-square"></i></a
|
||||||
class="fa-brands fa-twitter-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">
|
<a href="#" class="text-gray-400 hover:text-gray-500">
|
||||||
<i class="fa-brands fa-github-square"></i>
|
<i class="fa-brands fa-github-square"></i>
|
||||||
</a>
|
</a>
|
||||||
|
@ -482,7 +611,9 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
<div class="col-span-2 grid grid-cols-2 gap-8">
|
<div class="col-span-2 grid grid-cols-2 gap-8">
|
||||||
<div class="grid grid-cols-2 gap-8">
|
<div class="grid grid-cols-2 gap-8">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider">Solutions</h3>
|
<h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider">
|
||||||
|
Solutions
|
||||||
|
</h3>
|
||||||
<div class="mt-4 space-y-4">
|
<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">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">Analitycs</a>
|
||||||
|
@ -495,7 +626,9 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
<h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider">Support</h3>
|
<h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider">Support</h3>
|
||||||
<div class="mt-4 space-y-4">
|
<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">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"
|
||||||
|
>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">Guides</a>
|
||||||
<a href="#" class="text-base text-gray-500 hover:text-gray-900 block">API Status</a>
|
<a href="#" class="text-base text-gray-500 hover:text-gray-900 block">API Status</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -503,7 +636,9 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 gap-8">
|
<div class="grid grid-cols-2 gap-8">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider">Solutions</h3>
|
<h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider">
|
||||||
|
Solutions
|
||||||
|
</h3>
|
||||||
<div class="mt-4 space-y-4">
|
<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">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">Analitycs</a>
|
||||||
|
@ -516,7 +651,9 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
<h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider">Support</h3>
|
<h3 class="text-sm font-semibold text-gray-400 uppercase tracking-wider">Support</h3>
|
||||||
<div class="mt-4 space-y-4">
|
<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">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"
|
||||||
|
>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">Guides</a>
|
||||||
<a href="#" class="text-base text-gray-500 hover:text-gray-900 block">API Status</a>
|
<a href="#" class="text-base text-gray-500 hover:text-gray-900 block">API Status</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -532,12 +669,10 @@ import '@fortawesome/fontawesome-free/css/all.min.css';
|
||||||
<div class="container flex items-center justify-between">
|
<div class="container flex items-center justify-between">
|
||||||
<p class="text-white">© TailCommerce - All Right Reserved</p>
|
<p class="text-white">© TailCommerce - All Right Reserved</p>
|
||||||
<div>
|
<div>
|
||||||
<img src="../assets/images/methods.png" alt="methods" class="h-5">
|
<img src="../assets/images/methods.png" alt="methods" class="h-5" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- ./copyright -->
|
<!-- ./copyright -->
|
||||||
|
</body>
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -3377,7 +3377,6 @@ export interface SSRMetadata {
|
||||||
headInTree: boolean;
|
headInTree: boolean;
|
||||||
extraHead: string[];
|
extraHead: string[];
|
||||||
propagators: Set<AstroComponentInstance>;
|
propagators: Set<AstroComponentInstance>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Preview server stuff */
|
/* Preview server stuff */
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { appendForwardSlash, removeFileExtension } from '../core/path.js';
|
||||||
import { isServerLikeOutput } from '../core/util.js';
|
import { isServerLikeOutput } from '../core/util.js';
|
||||||
import { rootRelativePath } from '../core/viteUtils.js';
|
import { rootRelativePath } from '../core/viteUtils.js';
|
||||||
import type { AstroPluginMetadata } from '../vite-plugin-astro/index.js';
|
import type { AstroPluginMetadata } from '../vite-plugin-astro/index.js';
|
||||||
|
import { createDefaultAstroMetadata } from '../vite-plugin-astro/metadata.js';
|
||||||
import {
|
import {
|
||||||
CONTENT_FLAG,
|
CONTENT_FLAG,
|
||||||
CONTENT_RENDER_FLAG,
|
CONTENT_RENDER_FLAG,
|
||||||
|
@ -30,7 +31,6 @@ import {
|
||||||
getEntryType,
|
getEntryType,
|
||||||
getExtGlob,
|
getExtGlob,
|
||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
import { createDefaultAstroMetadata } from '../vite-plugin-astro/metadata.js';
|
|
||||||
|
|
||||||
interface AstroContentVirtualModPluginParams {
|
interface AstroContentVirtualModPluginParams {
|
||||||
settings: AstroSettings;
|
settings: AstroSettings;
|
||||||
|
|
|
@ -99,11 +99,11 @@ export class AppPipeline extends Pipeline {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getModuleForRoute(route: RouteData): Promise<SinglePageBuiltModule> {
|
async getModuleForRoute(route: RouteData): Promise<SinglePageBuiltModule> {
|
||||||
for(const defaultRoute of this.defaultRoutes) {
|
for (const defaultRoute of this.defaultRoutes) {
|
||||||
if(route.component === defaultRoute.component) {
|
if (route.component === defaultRoute.component) {
|
||||||
return {
|
return {
|
||||||
page: () => Promise.resolve(defaultRoute.instance),
|
page: () => Promise.resolve(defaultRoute.instance),
|
||||||
renderers: []
|
renderers: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,13 @@ export type SSRManifestI18n = {
|
||||||
|
|
||||||
export type SerializedSSRManifest = Omit<
|
export type SerializedSSRManifest = Omit<
|
||||||
SSRManifest,
|
SSRManifest,
|
||||||
'middleware' | 'routes' | 'assets' | 'componentMetadata' | 'inlinedScripts' | 'clientDirectives' | 'serverIslandNameMap'
|
| 'middleware'
|
||||||
|
| 'routes'
|
||||||
|
| 'assets'
|
||||||
|
| 'componentMetadata'
|
||||||
|
| 'inlinedScripts'
|
||||||
|
| 'clientDirectives'
|
||||||
|
| 'serverIslandNameMap'
|
||||||
> & {
|
> & {
|
||||||
routes: SerializedRouteInfo[];
|
routes: SerializedRouteInfo[];
|
||||||
assets: string[];
|
assets: string[];
|
||||||
|
|
|
@ -272,8 +272,8 @@ export class BuildPipeline extends Pipeline {
|
||||||
return await entry.page();
|
return await entry.page();
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const route of this.defaultRoutes) {
|
for (const route of this.defaultRoutes) {
|
||||||
if(route.component === routeData.component) {
|
if (route.component === routeData.component) {
|
||||||
return route.instance;
|
return route.instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import type { Plugin as VitePlugin } from 'vite';
|
||||||
import type { AstroAdapter, AstroSettings } from '../../../@types/astro.js';
|
import type { AstroAdapter, AstroSettings } from '../../../@types/astro.js';
|
||||||
import { isFunctionPerRouteEnabled } from '../../../integrations/hooks.js';
|
import { isFunctionPerRouteEnabled } from '../../../integrations/hooks.js';
|
||||||
import { routeIsRedirect } from '../../redirects/index.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 { isServerLikeOutput } from '../../util.js';
|
||||||
import { addRollupInput } from '../add-rollup-input.js';
|
import { addRollupInput } from '../add-rollup-input.js';
|
||||||
import type { BuildInternals } from '../internal.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 { MIDDLEWARE_MODULE_ID } from './plugin-middleware.js';
|
||||||
import { ASTRO_PAGE_MODULE_ID } from './plugin-pages.js';
|
import { ASTRO_PAGE_MODULE_ID } from './plugin-pages.js';
|
||||||
import { RENDERERS_MODULE_ID } from './plugin-renderers.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';
|
import { getComponentFromVirtualModulePageName, getVirtualModulePageName } from './util.js';
|
||||||
|
|
||||||
export const SSR_VIRTUAL_MODULE_ID = '@astrojs-ssr-virtual-entry';
|
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 { manifest as defaultManifest } from '${SSR_MANIFEST_VIRTUAL_MODULE_ID}';`,
|
||||||
`import * as serverEntrypointModule from '${adapter.serverEntrypoint}';`,
|
`import * as serverEntrypointModule from '${adapter.serverEntrypoint}';`,
|
||||||
edgeMiddleware ? `` : `import { onRequest as middleware } from '${middlewareId}';`,
|
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 = [
|
const contents = [
|
||||||
|
|
|
@ -540,7 +540,10 @@ export const AstroConfigSchema = z.object({
|
||||||
})
|
})
|
||||||
.strict()
|
.strict()
|
||||||
.optional(),
|
.optional(),
|
||||||
serverIslands: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.serverIslands),
|
serverIslands: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.default(ASTRO_CONFIG_DEFAULTS.experimental.serverIslands),
|
||||||
})
|
})
|
||||||
.strict(
|
.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.`
|
`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.`
|
||||||
|
|
|
@ -36,8 +36,8 @@ import { vitePluginSSRManifest } from '../vite-plugin-ssr-manifest/index.js';
|
||||||
import type { Logger } from './logger/core.js';
|
import type { Logger } from './logger/core.js';
|
||||||
import { createViteLogger } from './logger/vite.js';
|
import { createViteLogger } from './logger/vite.js';
|
||||||
import { vitePluginMiddleware } from './middleware/vite-plugin.js';
|
import { vitePluginMiddleware } from './middleware/vite-plugin.js';
|
||||||
import { vitePluginServerIslands } from './server-islands/vite-plugin-server-islands.js';
|
|
||||||
import { joinPaths } from './path.js';
|
import { joinPaths } from './path.js';
|
||||||
|
import { vitePluginServerIslands } from './server-islands/vite-plugin-server-islands.js';
|
||||||
import { isObject } from './util.js';
|
import { isObject } from './util.js';
|
||||||
|
|
||||||
interface CreateViteOptions {
|
interface CreateViteOptions {
|
||||||
|
|
|
@ -1,7 +1,16 @@
|
||||||
import type { ComponentInstance, ManifestData, SSRManifest, } from "../../@types/astro.js";
|
import type { ComponentInstance, ManifestData, SSRManifest } from '../../@types/astro.js';
|
||||||
import { DEFAULT_404_COMPONENT } from "../constants.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 {
|
||||||
import { ensure404Route, default404Instance, DEFAULT_404_ROUTE } from './astro-designed-error-pages.js';
|
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) {
|
export function injectDefaultRoutes(manifest: ManifestData) {
|
||||||
ensure404Route(manifest);
|
ensure404Route(manifest);
|
||||||
|
@ -14,7 +23,7 @@ type DefaultRouteParams = {
|
||||||
matchesComponent(filePath: URL): boolean;
|
matchesComponent(filePath: URL): boolean;
|
||||||
route: string;
|
route: string;
|
||||||
component: string;
|
component: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function createDefaultRoutes(manifest: SSRManifest, root: URL): DefaultRouteParams[] {
|
export function createDefaultRoutes(manifest: SSRManifest, root: URL): DefaultRouteParams[] {
|
||||||
return [
|
return [
|
||||||
|
@ -29,6 +38,6 @@ export function createDefaultRoutes(manifest: SSRManifest, root: URL): DefaultRo
|
||||||
matchesComponent: (filePath) => filePath.href === new URL(SERVER_ISLAND_COMPONENT, root).href,
|
matchesComponent: (filePath) => filePath.href === new URL(SERVER_ISLAND_COMPONENT, root).href,
|
||||||
route: SERVER_ISLAND_ROUTE,
|
route: SERVER_ISLAND_ROUTE,
|
||||||
component: SERVER_ISLAND_COMPONENT,
|
component: SERVER_ISLAND_COMPONENT,
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,15 @@
|
||||||
import { renderComponent, renderTemplate, type AstroComponentFactory, type ComponentSlots } from '../../runtime/server/index.js';
|
import type {
|
||||||
import type { ComponentInstance, ManifestData, RouteData, SSRManifest } from '../../@types/astro.js';
|
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';
|
import { createSlotValueFromString } from '../../runtime/server/render/slot.js';
|
||||||
|
|
||||||
export const SERVER_ISLAND_ROUTE = '/_server-islands/[name]';
|
export const SERVER_ISLAND_ROUTE = '/_server-islands/[name]';
|
||||||
|
@ -17,7 +27,7 @@ export function ensureServerIslandRoute(manifest: ManifestData) {
|
||||||
params: ['name'],
|
params: ['name'],
|
||||||
segments: [
|
segments: [
|
||||||
[{ content: '_server-islands', dynamic: false, spread: false }],
|
[{ content: '_server-islands', dynamic: false, spread: false }],
|
||||||
[{ content: 'name', dynamic: true, spread: false }]
|
[{ content: 'name', dynamic: true, spread: false }],
|
||||||
],
|
],
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
pattern: /^\/_server-islands\/([^/]+?)$/,
|
pattern: /^\/_server-islands\/([^/]+?)$/,
|
||||||
|
@ -25,7 +35,7 @@ export function ensureServerIslandRoute(manifest: ManifestData) {
|
||||||
isIndex: false,
|
isIndex: false,
|
||||||
fallbackRoutes: [],
|
fallbackRoutes: [],
|
||||||
route: SERVER_ISLAND_ROUTE,
|
route: SERVER_ISLAND_ROUTE,
|
||||||
}
|
};
|
||||||
|
|
||||||
manifest.routes.push(route);
|
manifest.routes.push(route);
|
||||||
}
|
}
|
||||||
|
@ -34,7 +44,7 @@ type RenderOptions = {
|
||||||
componentExport: string;
|
componentExport: string;
|
||||||
props: Record<string, any>;
|
props: Record<string, any>;
|
||||||
slots: Record<string, string>;
|
slots: Record<string, string>;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function createEndpoint(manifest: SSRManifest) {
|
export function createEndpoint(manifest: SSRManifest) {
|
||||||
const page: AstroComponentFactory = async (result) => {
|
const page: AstroComponentFactory = async (result) => {
|
||||||
|
@ -42,19 +52,19 @@ export function createEndpoint(manifest: SSRManifest) {
|
||||||
const request = result.request;
|
const request = result.request;
|
||||||
const raw = await request.text();
|
const raw = await request.text();
|
||||||
const data = JSON.parse(raw) as RenderOptions;
|
const data = JSON.parse(raw) as RenderOptions;
|
||||||
if(!params.name) {
|
if (!params.name) {
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 400,
|
status: 400,
|
||||||
statusText: 'Bad request'
|
statusText: 'Bad request',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const componentId = params.name;
|
const componentId = params.name;
|
||||||
|
|
||||||
const imp = manifest.serverIslandMap?.get(componentId);
|
const imp = manifest.serverIslandMap?.get(componentId);
|
||||||
if(!imp) {
|
if (!imp) {
|
||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 404,
|
status: 404,
|
||||||
statusText: 'Not found'
|
statusText: 'Not found',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,12 +73,12 @@ export function createEndpoint(manifest: SSRManifest) {
|
||||||
const Component = (componentModule as any)[data.componentExport];
|
const Component = (componentModule as any)[data.componentExport];
|
||||||
|
|
||||||
const slots: ComponentSlots = {};
|
const slots: ComponentSlots = {};
|
||||||
for(const prop in data.slots) {
|
for (const prop in data.slots) {
|
||||||
slots[prop] = createSlotValueFromString(data.slots[prop]);
|
slots[prop] = createSlotValueFromString(data.slots[prop]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderTemplate`${renderComponent(result, 'Component', Component, props, slots)}`;
|
return renderTemplate`${renderComponent(result, 'Component', Component, props, slots)}`;
|
||||||
}
|
};
|
||||||
|
|
||||||
page.isAstroComponentFactory = true;
|
page.isAstroComponentFactory = true;
|
||||||
|
|
||||||
|
@ -79,4 +89,3 @@ export function createEndpoint(manifest: SSRManifest) {
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 { 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 VIRTUAL_ISLAND_MAP_ID = '@astro-server-islands';
|
||||||
export const RESOLVED_VIRTUAL_ISLAND_MAP_ID = '\0' + VIRTUAL_ISLAND_MAP_ID;
|
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 {
|
export function vitePluginServerIslands({ settings }: { settings: AstroSettings }): VitePlugin {
|
||||||
let command: ConfigEnv['command'] = 'serve';
|
let command: ConfigEnv['command'] = 'serve';
|
||||||
|
@ -20,29 +20,29 @@ export function vitePluginServerIslands({ settings }: { settings: AstroSettings
|
||||||
viteServer = _server;
|
viteServer = _server;
|
||||||
},
|
},
|
||||||
resolveId(name) {
|
resolveId(name) {
|
||||||
if(name === VIRTUAL_ISLAND_MAP_ID) {
|
if (name === VIRTUAL_ISLAND_MAP_ID) {
|
||||||
return RESOLVED_VIRTUAL_ISLAND_MAP_ID;
|
return RESOLVED_VIRTUAL_ISLAND_MAP_ID;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
load(id) {
|
load(id) {
|
||||||
if(id === RESOLVED_VIRTUAL_ISLAND_MAP_ID) {
|
if (id === RESOLVED_VIRTUAL_ISLAND_MAP_ID) {
|
||||||
return `export const serverIslandMap = ${serverIslandPlaceholder};`;
|
return `export const serverIslandMap = ${serverIslandPlaceholder};`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
transform(_code, id) {
|
transform(_code, id) {
|
||||||
if(id.endsWith('.astro')) {
|
if (id.endsWith('.astro')) {
|
||||||
const info = this.getModuleInfo(id);
|
const info = this.getModuleInfo(id);
|
||||||
if(info?.meta) {
|
if (info?.meta) {
|
||||||
const astro = info.meta.astro as AstroPluginMetadata['astro'] | undefined;
|
const astro = info.meta.astro as AstroPluginMetadata['astro'] | undefined;
|
||||||
if(astro?.serverComponents.length) {
|
if (astro?.serverComponents.length) {
|
||||||
for(const comp of astro.serverComponents) {
|
for (const comp of astro.serverComponents) {
|
||||||
if(!settings.serverIslandNameMap.has(comp.resolvedPath)) {
|
if (!settings.serverIslandNameMap.has(comp.resolvedPath)) {
|
||||||
let name = comp.localName;
|
let name = comp.localName;
|
||||||
let idx = 1;
|
let idx = 1;
|
||||||
|
|
||||||
while(true) {
|
while (true) {
|
||||||
// Name not taken, let's use it.
|
// Name not taken, let's use it.
|
||||||
if(!settings.serverIslandMap.has(name)) {
|
if (!settings.serverIslandMap.has(name)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Increment a number onto the name: Avatar -> Avatar1
|
// Increment a number onto the name: Avatar -> Avatar1
|
||||||
|
@ -57,12 +57,12 @@ export function vitePluginServerIslands({ settings }: { settings: AstroSettings
|
||||||
});
|
});
|
||||||
|
|
||||||
// Build mode
|
// Build mode
|
||||||
if(command === 'build') {
|
if (command === 'build') {
|
||||||
let referenceId = this.emitFile({
|
let referenceId = this.emitFile({
|
||||||
type: 'chunk',
|
type: 'chunk',
|
||||||
id: comp.specifier,
|
id: comp.specifier,
|
||||||
importer: id,
|
importer: id,
|
||||||
name: comp.localName
|
name: comp.localName,
|
||||||
});
|
});
|
||||||
|
|
||||||
referenceIdMap.set(comp.resolvedPath, referenceId);
|
referenceIdMap.set(comp.resolvedPath, referenceId);
|
||||||
|
@ -74,17 +74,17 @@ export function vitePluginServerIslands({ settings }: { settings: AstroSettings
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderChunk(code) {
|
renderChunk(code) {
|
||||||
if(code.includes(serverIslandPlaceholder)) {
|
if (code.includes(serverIslandPlaceholder)) {
|
||||||
let mapSource = 'new Map([';
|
let mapSource = 'new Map([';
|
||||||
for(let [resolvedPath, referenceId] of referenceIdMap) {
|
for (let [resolvedPath, referenceId] of referenceIdMap) {
|
||||||
const fileName = this.getFileName(referenceId);
|
const fileName = this.getFileName(referenceId);
|
||||||
const islandName = settings.serverIslandNameMap.get(resolvedPath)!;
|
const islandName = settings.serverIslandNameMap.get(resolvedPath)!;
|
||||||
mapSource += `\n\t['${islandName}', () => import('./${fileName}')],`
|
mapSource += `\n\t['${islandName}', () => import('./${fileName}')],`;
|
||||||
}
|
}
|
||||||
mapSource += '\n]);';
|
mapSource += '\n]);';
|
||||||
referenceIdMap.clear();
|
referenceIdMap.clear();
|
||||||
return code.replace(serverIslandPlaceholder, mapSource);
|
return code.replace(serverIslandPlaceholder, mapSource);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ import * as t from '@babel/types';
|
||||||
import { AstroError } from '../core/errors/errors.js';
|
import { AstroError } from '../core/errors/errors.js';
|
||||||
import { AstroErrorData } from '../core/errors/index.js';
|
import { AstroErrorData } from '../core/errors/index.js';
|
||||||
import { resolvePath } from '../core/viteUtils.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 { createDefaultAstroMetadata } from '../vite-plugin-astro/metadata.js';
|
||||||
|
import type { PluginMetadata } from '../vite-plugin-astro/types.js';
|
||||||
|
|
||||||
const ClientOnlyPlaceholder = 'astro-client-only';
|
const ClientOnlyPlaceholder = 'astro-client-only';
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ export async function renderEndpoint(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (handler === undefined) {
|
if (handler === undefined) {
|
||||||
|
|
||||||
logger.warn(
|
logger.warn(
|
||||||
'router',
|
'router',
|
||||||
`No API Route handler exists for the method "${method}" for the route "${url.pathname}".\n` +
|
`No API Route handler exists for the method "${method}" for the route "${url.pathname}".\n` +
|
||||||
|
|
|
@ -6,7 +6,11 @@ export type AstroFactoryReturnValue = RenderTemplateResult | Response | HeadAndC
|
||||||
|
|
||||||
// The callback passed to to $$createComponent
|
// The callback passed to to $$createComponent
|
||||||
export interface AstroComponentFactory {
|
export interface AstroComponentFactory {
|
||||||
(result: SSRResult, props: any, slots: any): AstroFactoryReturnValue | Promise<AstroFactoryReturnValue>;
|
(
|
||||||
|
result: SSRResult,
|
||||||
|
props: any,
|
||||||
|
slots: any
|
||||||
|
): AstroFactoryReturnValue | Promise<AstroFactoryReturnValue>;
|
||||||
isAstroComponentFactory?: boolean;
|
isAstroComponentFactory?: boolean;
|
||||||
moduleId?: string | undefined;
|
moduleId?: string | undefined;
|
||||||
propagation?: PropagationHint;
|
propagation?: PropagationHint;
|
||||||
|
|
|
@ -27,9 +27,9 @@ import {
|
||||||
} from './common.js';
|
} from './common.js';
|
||||||
import { componentIsHTMLElement, renderHTMLElement } from './dom.js';
|
import { componentIsHTMLElement, renderHTMLElement } from './dom.js';
|
||||||
import { maybeRenderHead } from './head.js';
|
import { maybeRenderHead } from './head.js';
|
||||||
|
import { containsServerDirective, renderServerIsland } from './server-islands.js';
|
||||||
import { type ComponentSlots, renderSlotToString, renderSlots } from './slot.js';
|
import { type ComponentSlots, renderSlotToString, renderSlots } from './slot.js';
|
||||||
import { formatList, internalSpreadAttributes, renderElement, voidElementNames } from './util.js';
|
import { formatList, internalSpreadAttributes, renderElement, voidElementNames } from './util.js';
|
||||||
import { containsServerDirective, renderServerIsland } from './server-islands.js';
|
|
||||||
|
|
||||||
const needsHeadRenderingSymbol = Symbol.for('astro.needsHeadRendering');
|
const needsHeadRenderingSymbol = Symbol.for('astro.needsHeadRendering');
|
||||||
const rendererAliases = new Map([['solid', 'solid-js']]);
|
const rendererAliases = new Map([['solid', 'solid-js']]);
|
||||||
|
@ -474,7 +474,7 @@ function renderAstroComponent(
|
||||||
props: Record<string | number, any>,
|
props: Record<string | number, any>,
|
||||||
slots: any = {}
|
slots: any = {}
|
||||||
): RenderInstance {
|
): RenderInstance {
|
||||||
if(containsServerDirective(props)) {
|
if (containsServerDirective(props)) {
|
||||||
return renderServerIsland(result, displayName, props, slots);
|
return renderServerIsland(result, displayName, props, slots);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
import type {
|
import type { SSRResult } from '../../../@types/astro.js';
|
||||||
SSRResult,
|
import { renderChild } from './any.js';
|
||||||
} from '../../../@types/astro.js';
|
import type { RenderInstance } from './common.js';
|
||||||
import { renderChild } from "./any.js";
|
import { type ComponentSlots, renderSlotToString } from './slot.js';
|
||||||
import type { RenderInstance } from "./common.js";
|
|
||||||
import { renderSlotToString, type ComponentSlots } from "./slot.js";
|
|
||||||
|
|
||||||
const internalProps = new Set([
|
const internalProps = new Set([
|
||||||
'server:component-path',
|
'server:component-path',
|
||||||
'server:component-export',
|
'server:component-export',
|
||||||
'server:component-directive',
|
'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;
|
return 'server:component-directive' in props;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +18,7 @@ export function renderServerIsland(
|
||||||
result: SSRResult,
|
result: SSRResult,
|
||||||
_displayName: string,
|
_displayName: string,
|
||||||
props: Record<string | number, any>,
|
props: Record<string | number, any>,
|
||||||
slots: ComponentSlots,
|
slots: ComponentSlots
|
||||||
): RenderInstance {
|
): RenderInstance {
|
||||||
return {
|
return {
|
||||||
async render(destination) {
|
async render(destination) {
|
||||||
|
@ -28,23 +26,23 @@ export function renderServerIsland(
|
||||||
const componentExport = props['server:component-export'];
|
const componentExport = props['server:component-export'];
|
||||||
const componentId = result.serverIslandNameMap.get(componentPath);
|
const componentId = result.serverIslandNameMap.get(componentPath);
|
||||||
|
|
||||||
if(!componentId) {
|
if (!componentId) {
|
||||||
throw new Error(`Could not find server component name`);
|
throw new Error(`Could not find server component name`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove internal props
|
// Remove internal props
|
||||||
for(const key of Object.keys(props)) {
|
for (const key of Object.keys(props)) {
|
||||||
if(internalProps.has(key)) {
|
if (internalProps.has(key)) {
|
||||||
delete props[key];
|
delete props[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
destination.write('<!--server-island-start-->')
|
destination.write('<!--server-island-start-->');
|
||||||
|
|
||||||
// Render the slots
|
// Render the slots
|
||||||
const renderedSlots: Record<string, string> = {};
|
const renderedSlots: Record<string, string> = {};
|
||||||
for(const name in slots) {
|
for (const name in slots) {
|
||||||
if(name !== 'fallback') {
|
if (name !== 'fallback') {
|
||||||
const content = await renderSlotToString(result, slots[name]);
|
const content = await renderSlotToString(result, slots[name]);
|
||||||
renderedSlots[name] = content.toString();
|
renderedSlots[name] = content.toString();
|
||||||
} else {
|
} else {
|
||||||
|
@ -83,7 +81,7 @@ if(response.status === 200 && response.headers.get('content-type') === 'text/htm
|
||||||
script.before(frag);
|
script.before(frag);
|
||||||
}
|
}
|
||||||
script.remove();
|
script.remove();
|
||||||
</script>`)
|
</script>`);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ export async function renderSlots(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createSlotValueFromString(content: string): ComponentSlotValue {
|
export function createSlotValueFromString(content: string): ComponentSlotValue {
|
||||||
return function() {
|
return function () {
|
||||||
return renderTemplate`${unescapeHTML(content)}`;
|
return renderTemplate`${unescapeHTML(content)}`;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,8 +158,8 @@ export class DevPipeline extends Pipeline {
|
||||||
const { loader } = this;
|
const { loader } = this;
|
||||||
|
|
||||||
// First check built-in routes
|
// First check built-in routes
|
||||||
for(const route of this.defaultRoutes) {
|
for (const route of this.defaultRoutes) {
|
||||||
if(route.matchesComponent(filePath)) {
|
if (route.matchesComponent(filePath)) {
|
||||||
return route.instance;
|
return route.instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,8 +226,8 @@ export class DevPipeline extends Pipeline {
|
||||||
|
|
||||||
rewriteKnownRoute(route: string, sourceRoute: RouteData): ComponentInstance {
|
rewriteKnownRoute(route: string, sourceRoute: RouteData): ComponentInstance {
|
||||||
if (isServerLikeOutput(this.config) && sourceRoute.prerender) {
|
if (isServerLikeOutput(this.config) && sourceRoute.prerender) {
|
||||||
for(let def of this.defaultRoutes) {
|
for (let def of this.defaultRoutes) {
|
||||||
if(route === def.route) {
|
if (route === def.route) {
|
||||||
return def.instance;
|
return def.instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
||||||
import { patchOverlay } from '../core/errors/overlay.js';
|
import { patchOverlay } from '../core/errors/overlay.js';
|
||||||
import type { Logger } from '../core/logger/core.js';
|
import type { Logger } from '../core/logger/core.js';
|
||||||
import { createViteLoader } from '../core/module-loader/index.js';
|
import { createViteLoader } from '../core/module-loader/index.js';
|
||||||
import { createRouteManifest } from '../core/routing/index.js';
|
|
||||||
import { injectDefaultRoutes } from '../core/routing/default.js';
|
import { injectDefaultRoutes } from '../core/routing/default.js';
|
||||||
|
import { createRouteManifest } from '../core/routing/index.js';
|
||||||
import { toRoutingStrategy } from '../i18n/utils.js';
|
import { toRoutingStrategy } from '../i18n/utils.js';
|
||||||
import { baseMiddleware } from './base.js';
|
import { baseMiddleware } from './base.js';
|
||||||
import { createController } from './controller.js';
|
import { createController } from './controller.js';
|
||||||
|
@ -36,7 +36,7 @@ export default function createVitePluginAstroServer({
|
||||||
const loader = createViteLoader(viteServer);
|
const loader = createViteLoader(viteServer);
|
||||||
const manifest = createDevelopmentManifest(settings);
|
const manifest = createDevelopmentManifest(settings);
|
||||||
let manifestData: ManifestData = injectDefaultRoutes(
|
let manifestData: ManifestData = injectDefaultRoutes(
|
||||||
createRouteManifest({ settings, fsMod }, logger),
|
createRouteManifest({ settings, fsMod }, logger)
|
||||||
);
|
);
|
||||||
const pipeline = DevPipeline.create(manifestData, { loader, logger, manifest, settings });
|
const pipeline = DevPipeline.create(manifestData, { loader, logger, manifest, settings });
|
||||||
const controller = createController({ loader });
|
const controller = createController({ loader });
|
||||||
|
@ -46,9 +46,7 @@ export default function createVitePluginAstroServer({
|
||||||
function rebuildManifest(needsManifestRebuild: boolean) {
|
function rebuildManifest(needsManifestRebuild: boolean) {
|
||||||
pipeline.clearRouteCache();
|
pipeline.clearRouteCache();
|
||||||
if (needsManifestRebuild) {
|
if (needsManifestRebuild) {
|
||||||
manifestData = injectDefaultRoutes(
|
manifestData = injectDefaultRoutes(createRouteManifest({ settings }, logger));
|
||||||
createRouteManifest({ settings }, logger),
|
|
||||||
);
|
|
||||||
pipeline.setManifestData(manifestData);
|
pipeline.setManifestData(manifestData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@ import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
||||||
import type { Logger } from '../core/logger/core.js';
|
import type { Logger } from '../core/logger/core.js';
|
||||||
import { isMarkdownFile } from '../core/util.js';
|
import { isMarkdownFile } from '../core/util.js';
|
||||||
import { shorthash } from '../runtime/server/shorthash.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 { getFileInfo } from '../vite-plugin-utils/index.js';
|
||||||
import { type MarkdownImagePath, getMarkdownCodeForImages } from './images.js';
|
import { type MarkdownImagePath, getMarkdownCodeForImages } from './images.js';
|
||||||
import { createDefaultAstroMetadata } from '../vite-plugin-astro/metadata.js';
|
|
||||||
|
|
||||||
interface AstroPluginOptions {
|
interface AstroPluginOptions {
|
||||||
settings: AstroSettings;
|
settings: AstroSettings;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import { after, before, describe, it } from 'node:test';
|
import { after, before, describe, it } from 'node:test';
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
|
@ -93,7 +92,7 @@ describe('Server islands', () => {
|
||||||
componentExport: 'default',
|
componentExport: 'default',
|
||||||
props: {},
|
props: {},
|
||||||
slots: {},
|
slots: {},
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
return app.render(request);
|
return app.render(request);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue