Initial project setup with Astro framework, including configuration files, a comprehensive .gitignore, and a variety of UI components for a streaming platform. Added essential styles and layout structure, along with a README detailing project features and development guidelines.
This commit is contained in:
1
src/assets/astro.svg
Normal file
1
src/assets/astro.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" width="115" height="48"><path fill="#17191E" d="M7.77 36.35C6.4 35.11 6 32.51 6.57 30.62c.99 1.2 2.35 1.57 3.75 1.78 2.18.33 4.31.2 6.33-.78.23-.12.44-.27.7-.42.18.55.23 1.1.17 1.67a4.56 4.56 0 0 1-1.94 3.23c-.43.32-.9.61-1.34.91-1.38.94-1.76 2.03-1.24 3.62l.05.17a3.63 3.63 0 0 1-1.6-1.38 3.87 3.87 0 0 1-.63-2.1c0-.37 0-.74-.05-1.1-.13-.9-.55-1.3-1.33-1.32a1.56 1.56 0 0 0-1.63 1.26c0 .06-.03.12-.05.2Z"/><path fill="url(#a)" d="M7.77 36.35C6.4 35.11 6 32.51 6.57 30.62c.99 1.2 2.35 1.57 3.75 1.78 2.18.33 4.31.2 6.33-.78.23-.12.44-.27.7-.42.18.55.23 1.1.17 1.67a4.56 4.56 0 0 1-1.94 3.23c-.43.32-.9.61-1.34.91-1.38.94-1.76 2.03-1.24 3.62l.05.17a3.63 3.63 0 0 1-1.6-1.38 3.87 3.87 0 0 1-.63-2.1c0-.37 0-.74-.05-1.1-.13-.9-.55-1.3-1.33-1.32a1.56 1.56 0 0 0-1.63 1.26c0 .06-.03.12-.05.2Z"/><path fill="#17191E" d="M.02 30.31s4.02-1.95 8.05-1.95l3.04-9.4c.11-.45.44-.76.82-.76.37 0 .7.31.82.76l3.04 9.4c4.77 0 8.05 1.95 8.05 1.95L17 11.71c-.2-.56-.53-.91-.98-.91H7.83c-.44 0-.76.35-.97.9L.02 30.31Zm42.37-5.97c0 1.64-2.05 2.62-4.88 2.62-1.85 0-2.5-.45-2.5-1.41 0-1 .8-1.49 2.65-1.49 1.67 0 3.09.03 4.73.23v.05Zm.03-2.04a21.37 21.37 0 0 0-4.37-.36c-5.32 0-7.82 1.25-7.82 4.18 0 3.04 1.71 4.2 5.68 4.2 3.35 0 5.63-.84 6.46-2.92h.14c-.03.5-.05 1-.05 1.4 0 1.07.18 1.16 1.06 1.16h4.15a16.9 16.9 0 0 1-.36-4c0-1.67.06-2.93.06-4.62 0-3.45-2.07-5.64-8.56-5.64-2.8 0-5.9.48-8.26 1.19.22.93.54 2.83.7 4.06 2.04-.96 4.95-1.37 7.2-1.37 3.11 0 3.97.71 3.97 2.15v.57Zm11.37 3c-.56.07-1.33.07-2.12.07-.83 0-1.6-.03-2.12-.1l-.02.58c0 2.85 1.87 4.52 8.45 4.52 6.2 0 8.2-1.64 8.2-4.55 0-2.74-1.33-4.09-7.2-4.39-4.58-.2-4.99-.7-4.99-1.28 0-.66.59-1 3.65-1 3.18 0 4.03.43 4.03 1.35v.2a46.13 46.13 0 0 1 4.24.03l.02-.55c0-3.36-2.8-4.46-8.2-4.46-6.08 0-8.13 1.49-8.13 4.39 0 2.6 1.64 4.23 7.48 4.48 4.3.14 4.77.62 4.77 1.28 0 .7-.7 1.03-3.71 1.03-3.47 0-4.35-.48-4.35-1.47v-.13Zm19.82-12.05a17.5 17.5 0 0 1-6.24 3.48c.03.84.03 2.4.03 3.24l1.5.02c-.02 1.63-.04 3.6-.04 4.9 0 3.04 1.6 5.32 6.58 5.32 2.1 0 3.5-.23 5.23-.6a43.77 43.77 0 0 1-.46-4.13c-1.03.34-2.34.53-3.78.53-2 0-2.82-.55-2.82-2.13 0-1.37 0-2.65.03-3.84 2.57.02 5.13.07 6.64.11-.02-1.18.03-2.9.1-4.04-2.2.04-4.65.07-6.68.07l.07-2.93h-.16Zm13.46 6.04a767.33 767.33 0 0 1 .07-3.18H82.6c.07 1.96.07 3.98.07 6.92 0 2.95-.03 4.99-.07 6.93h5.18c-.09-1.37-.11-3.68-.11-5.65 0-3.1 1.26-4 4.12-4 1.33 0 2.28.16 3.1.46.03-1.16.26-3.43.4-4.43-.86-.25-1.81-.41-2.96-.41-2.46-.03-4.26.98-5.1 3.38l-.17-.02Zm22.55 3.65c0 2.5-1.8 3.66-4.64 3.66-2.81 0-4.61-1.1-4.61-3.66s1.82-3.52 4.61-3.52c2.82 0 4.64 1.03 4.64 3.52Zm4.71-.11c0-4.96-3.87-7.18-9.35-7.18-5.5 0-9.23 2.22-9.23 7.18 0 4.94 3.49 7.59 9.21 7.59 5.77 0 9.37-2.65 9.37-7.6Z"/><defs><linearGradient id="a" x1="6.33" x2="19.43" y1="40.8" y2="34.6" gradientUnits="userSpaceOnUse"><stop stop-color="#D83333"/><stop offset="1" stop-color="#F041FF"/></linearGradient></defs></svg>
|
After Width: | Height: | Size: 2.8 KiB |
1
src/assets/background.svg
Normal file
1
src/assets/background.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1440" height="1024" fill="none"><path fill="url(#a)" fill-rule="evenodd" d="M-217.58 475.75c91.82-72.02 225.52-29.38 341.2-44.74C240 415.56 372.33 315.14 466.77 384.9c102.9 76.02 44.74 246.76 90.31 366.31 29.83 78.24 90.48 136.14 129.48 210.23 57.92 109.99 169.67 208.23 155.9 331.77-13.52 121.26-103.42 264.33-224.23 281.37-141.96 20.03-232.72-220.96-374.06-196.99-151.7 25.73-172.68 330.24-325.85 315.72-128.6-12.2-110.9-230.73-128.15-358.76-12.16-90.14 65.87-176.25 44.1-264.57-26.42-107.2-167.12-163.46-176.72-273.45-10.15-116.29 33.01-248.75 124.87-320.79Z" clip-rule="evenodd" style="opacity:.154"/><path fill="url(#b)" fill-rule="evenodd" d="M1103.43 115.43c146.42-19.45 275.33-155.84 413.5-103.59 188.09 71.13 409 212.64 407.06 413.88-1.94 201.25-259.28 278.6-414.96 405.96-130 106.35-240.24 294.39-405.6 265.3-163.7-28.8-161.93-274.12-284.34-386.66-134.95-124.06-436-101.46-445.82-284.6-9.68-180.38 247.41-246.3 413.54-316.9 101.01-42.93 207.83 21.06 316.62 6.61Z" clip-rule="evenodd" style="opacity:.154"/><defs><linearGradient id="b" x1="373" x2="1995.44" y1="1100" y2="118.03" gradientUnits="userSpaceOnUse"><stop stop-color="#D83333"/><stop offset="1" stop-color="#F041FF"/></linearGradient><linearGradient id="a" x1="107.37" x2="1130.66" y1="1993.35" y2="1026.31" gradientUnits="userSpaceOnUse"><stop stop-color="#3245FF"/><stop offset="1" stop-color="#BC52EE"/></linearGradient></defs></svg>
|
After Width: | Height: | Size: 1.4 KiB |
52
src/components/ui/Alert.astro
Normal file
52
src/components/ui/Alert.astro
Normal file
@ -0,0 +1,52 @@
|
||||
---
|
||||
export interface Props {
|
||||
variant?: "success" | "warning" | "error" | "info";
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { variant = "info", class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const baseClasses = "alert";
|
||||
const variantClasses = `alert-${variant}`;
|
||||
|
||||
const classes = [baseClasses, variantClasses, className]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} {...rest}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.alert {
|
||||
padding: var(--spacing-4);
|
||||
border: 1px solid;
|
||||
border-radius: var(--radius-md);
|
||||
margin-bottom: var(--spacing-4);
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: rgba(16, 185, 129, 0.1);
|
||||
border-color: var(--success);
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
background-color: rgba(245, 158, 11, 0.1);
|
||||
border-color: var(--warning);
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background-color: rgba(239, 68, 68, 0.1);
|
||||
border-color: var(--error);
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
background-color: rgba(59, 130, 246, 0.1);
|
||||
border-color: var(--info);
|
||||
color: var(--info);
|
||||
}
|
||||
</style>
|
58
src/components/ui/Badge.astro
Normal file
58
src/components/ui/Badge.astro
Normal file
@ -0,0 +1,58 @@
|
||||
---
|
||||
export interface Props {
|
||||
variant?: "primary" | "secondary" | "success" | "warning" | "error";
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { variant = "primary", class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const baseClasses = "badge";
|
||||
const variantClasses = `badge-${variant}`;
|
||||
|
||||
const classes = [baseClasses, variantClasses, className]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
---
|
||||
|
||||
<span class={classes} {...rest}>
|
||||
<slot />
|
||||
</span>
|
||||
|
||||
<style>
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: var(--spacing-1) var(--spacing-2);
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: var(--font-weight-medium);
|
||||
line-height: var(--line-height-tight);
|
||||
border-radius: var(--radius-full);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.025em;
|
||||
}
|
||||
|
||||
.badge-primary {
|
||||
background-color: var(--primary-600);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.badge-secondary {
|
||||
background-color: var(--bg-tertiary);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.badge-success {
|
||||
background-color: var(--success);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.badge-warning {
|
||||
background-color: var(--warning);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.badge-error {
|
||||
background-color: var(--error);
|
||||
color: white;
|
||||
}
|
||||
</style>
|
150
src/components/ui/Button.astro
Normal file
150
src/components/ui/Button.astro
Normal file
@ -0,0 +1,150 @@
|
||||
---
|
||||
export interface Props {
|
||||
variant?: "primary" | "secondary" | "outline" | "ghost";
|
||||
size?: "sm" | "lg";
|
||||
type?: "button" | "submit" | "reset";
|
||||
href?: string;
|
||||
disabled?: boolean;
|
||||
icon?: boolean;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
variant = "primary",
|
||||
size,
|
||||
type = "button",
|
||||
href,
|
||||
disabled = false,
|
||||
icon = false,
|
||||
class: className = "",
|
||||
...rest
|
||||
} = Astro.props;
|
||||
|
||||
const baseClasses = "btn";
|
||||
const variantClasses = `btn-${variant}`;
|
||||
const sizeClasses = size ? `btn-${size}` : "";
|
||||
const iconClasses = icon ? "btn-icon" : "";
|
||||
|
||||
const classes = [
|
||||
baseClasses,
|
||||
variantClasses,
|
||||
sizeClasses,
|
||||
iconClasses,
|
||||
className,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
|
||||
const Tag = href ? "a" : "button";
|
||||
---
|
||||
|
||||
<Tag
|
||||
class={classes}
|
||||
type={href ? undefined : type}
|
||||
href={href}
|
||||
disabled={disabled}
|
||||
{...rest}
|
||||
>
|
||||
<slot />
|
||||
</Tag>
|
||||
|
||||
<style>
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--spacing-3) var(--spacing-6);
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-medium);
|
||||
line-height: var(--line-height-tight);
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: var(--primary-600);
|
||||
color: white;
|
||||
border-color: var(--primary-600);
|
||||
}
|
||||
|
||||
.btn-primary:hover:not(:disabled) {
|
||||
background-color: var(--primary-700);
|
||||
border-color: var(--primary-700);
|
||||
}
|
||||
|
||||
.btn-primary:active:not(:disabled) {
|
||||
background-color: var(--primary-800);
|
||||
border-color: var(--primary-800);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: var(--bg-tertiary);
|
||||
color: var(--text-primary);
|
||||
border-color: var(--border-primary);
|
||||
}
|
||||
|
||||
.btn-secondary:hover:not(:disabled) {
|
||||
background-color: var(--bg-hover);
|
||||
border-color: var(--border-secondary);
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background-color: transparent;
|
||||
color: var(--primary-400);
|
||||
border-color: var(--primary-600);
|
||||
}
|
||||
|
||||
.btn-outline:hover:not(:disabled) {
|
||||
background-color: var(--primary-600);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
background-color: transparent;
|
||||
color: var(--text-secondary);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.btn-ghost:hover:not(:disabled) {
|
||||
background-color: var(--bg-hover);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: var(--spacing-2) var(--spacing-4);
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.btn-lg {
|
||||
padding: var(--spacing-4) var(--spacing-8);
|
||||
font-size: var(--font-size-lg);
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
padding: var(--spacing-3);
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.btn-icon.btn-sm {
|
||||
padding: var(--spacing-2);
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.btn-icon.btn-lg {
|
||||
padding: var(--spacing-4);
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
}
|
||||
</style>
|
29
src/components/ui/Card.astro
Normal file
29
src/components/ui/Card.astro
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["card", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} {...rest}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.card {
|
||||
background-color: var(--bg-card);
|
||||
border: 1px solid var(--border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--spacing-6);
|
||||
box-shadow: var(--shadow);
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
border-color: var(--border-secondary);
|
||||
}
|
||||
</style>
|
19
src/components/ui/CardBody.astro
Normal file
19
src/components/ui/CardBody.astro
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["card-body", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} {...rest}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.card-body {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
22
src/components/ui/CardFooter.astro
Normal file
22
src/components/ui/CardFooter.astro
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["card-footer", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} {...rest}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.card-footer {
|
||||
padding: var(--spacing-4) var(--spacing-6) var(--spacing-6);
|
||||
border-top: 1px solid var(--border-primary);
|
||||
margin: var(--spacing-4) calc(var(--spacing-6) * -1)
|
||||
calc(var(--spacing-6) * -1);
|
||||
}
|
||||
</style>
|
22
src/components/ui/CardHeader.astro
Normal file
22
src/components/ui/CardHeader.astro
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["card-header", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} {...rest}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.card-header {
|
||||
padding: var(--spacing-6) var(--spacing-6) var(--spacing-4);
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
margin: calc(var(--spacing-6) * -1) calc(var(--spacing-6) * -1)
|
||||
var(--spacing-4);
|
||||
}
|
||||
</style>
|
21
src/components/ui/CardSubtitle.astro
Normal file
21
src/components/ui/CardSubtitle.astro
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["card-subtitle", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<p class={classes} {...rest}>
|
||||
<slot />
|
||||
</p>
|
||||
|
||||
<style>
|
||||
.card-subtitle {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--text-secondary);
|
||||
margin: 0 0 var(--spacing-4);
|
||||
}
|
||||
</style>
|
22
src/components/ui/CardTitle.astro
Normal file
22
src/components/ui/CardTitle.astro
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["card-title", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<h3 class={classes} {...rest}>
|
||||
<slot />
|
||||
</h3>
|
||||
|
||||
<style>
|
||||
.card-title {
|
||||
font-size: var(--font-size-lg);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--text-primary);
|
||||
margin: 0 0 var(--spacing-2);
|
||||
}
|
||||
</style>
|
66
src/components/ui/Col.astro
Normal file
66
src/components/ui/Col.astro
Normal file
@ -0,0 +1,66 @@
|
||||
---
|
||||
export interface Props {
|
||||
xs?: number | "auto";
|
||||
sm?: number | "auto";
|
||||
md?: number | "auto";
|
||||
lg?: number | "auto";
|
||||
xl?: number | "auto";
|
||||
xxl?: number | "auto";
|
||||
offset?: {
|
||||
xs?: number;
|
||||
sm?: number;
|
||||
md?: number;
|
||||
lg?: number;
|
||||
xl?: number;
|
||||
xxl?: number;
|
||||
};
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
xs,
|
||||
sm,
|
||||
md,
|
||||
lg,
|
||||
xl,
|
||||
xxl,
|
||||
offset,
|
||||
class: className = "",
|
||||
...rest
|
||||
} = Astro.props;
|
||||
|
||||
const getColClass = (size: string, value: number | "auto" | undefined) => {
|
||||
if (value === undefined) return "";
|
||||
return value === "auto" ? `col-${size}-auto` : `col-${size}-${value}`;
|
||||
};
|
||||
|
||||
const getOffsetClass = (size: string, value: number | undefined) => {
|
||||
if (value === undefined) return "";
|
||||
return `offset-${size}-${value}`;
|
||||
};
|
||||
|
||||
const baseClasses = xs || sm || md || lg || xl || xxl ? "" : "col";
|
||||
|
||||
const colClasses = [
|
||||
baseClasses,
|
||||
xs ? getColClass("", xs) : "",
|
||||
sm ? getColClass("sm", sm) : "",
|
||||
md ? getColClass("md", md) : "",
|
||||
lg ? getColClass("lg", lg) : "",
|
||||
xl ? getColClass("xl", xl) : "",
|
||||
xxl ? getColClass("xxl", xxl) : "",
|
||||
offset?.xs ? getOffsetClass("", offset.xs) : "",
|
||||
offset?.sm ? getOffsetClass("sm", offset.sm) : "",
|
||||
offset?.md ? getOffsetClass("md", offset.md) : "",
|
||||
offset?.lg ? getOffsetClass("lg", offset.lg) : "",
|
||||
offset?.xl ? getOffsetClass("xl", offset.xl) : "",
|
||||
offset?.xxl ? getOffsetClass("xxl", offset.xxl) : "",
|
||||
className,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
---
|
||||
|
||||
<div class={colClasses} {...rest}>
|
||||
<slot />
|
||||
</div>
|
15
src/components/ui/Container.astro
Normal file
15
src/components/ui/Container.astro
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
export interface Props {
|
||||
fluid?: boolean;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { fluid = false, class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const baseClasses = fluid ? "container-fluid" : "container";
|
||||
const classes = [baseClasses, className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} {...rest}>
|
||||
<slot />
|
||||
</div>
|
21
src/components/ui/FormError.astro
Normal file
21
src/components/ui/FormError.astro
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["form-error", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<small class={classes} {...rest}>
|
||||
<slot />
|
||||
</small>
|
||||
|
||||
<style>
|
||||
.form-error {
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--error);
|
||||
margin-top: var(--spacing-1);
|
||||
}
|
||||
</style>
|
19
src/components/ui/FormGroup.astro
Normal file
19
src/components/ui/FormGroup.astro
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["form-group", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} {...rest}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.form-group {
|
||||
margin-bottom: var(--spacing-4);
|
||||
}
|
||||
</style>
|
24
src/components/ui/FormLabel.astro
Normal file
24
src/components/ui/FormLabel.astro
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
export interface Props {
|
||||
for?: string;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { for: htmlFor, class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["form-label", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<label class={classes} for={htmlFor} {...rest}>
|
||||
<slot />
|
||||
</label>
|
||||
|
||||
<style>
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-2);
|
||||
}
|
||||
</style>
|
21
src/components/ui/FormText.astro
Normal file
21
src/components/ui/FormText.astro
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["form-text", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<small class={classes} {...rest}>
|
||||
<slot />
|
||||
</small>
|
||||
|
||||
<style>
|
||||
.form-text {
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--text-muted);
|
||||
margin-top: var(--spacing-1);
|
||||
}
|
||||
</style>
|
55
src/components/ui/Input.astro
Normal file
55
src/components/ui/Input.astro
Normal file
@ -0,0 +1,55 @@
|
||||
---
|
||||
export interface Props {
|
||||
type?: "text" | "email" | "password" | "number" | "tel" | "url" | "search";
|
||||
size?: "sm" | "lg";
|
||||
placeholder?: string;
|
||||
value?: string;
|
||||
name?: string;
|
||||
id?: string;
|
||||
disabled?: boolean;
|
||||
required?: boolean;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
type = "text",
|
||||
size,
|
||||
placeholder,
|
||||
value,
|
||||
name,
|
||||
id,
|
||||
disabled = false,
|
||||
required = false,
|
||||
class: className = "",
|
||||
...rest
|
||||
} = Astro.props;
|
||||
|
||||
const baseClasses = "form-control-base input";
|
||||
const sizeClasses = size ? `input-${size}` : "";
|
||||
|
||||
const classes = [baseClasses, sizeClasses, className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<input
|
||||
type={type}
|
||||
class={classes}
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
name={name}
|
||||
id={id}
|
||||
disabled={disabled}
|
||||
required={required}
|
||||
{...rest}
|
||||
/>
|
||||
|
||||
<style>
|
||||
.input-sm {
|
||||
padding: var(--spacing-2) var(--spacing-3);
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.input-lg {
|
||||
padding: var(--spacing-4) var(--spacing-5);
|
||||
font-size: var(--font-size-lg);
|
||||
}
|
||||
</style>
|
79
src/components/ui/Modal.astro
Normal file
79
src/components/ui/Modal.astro
Normal file
@ -0,0 +1,79 @@
|
||||
---
|
||||
export interface Props {
|
||||
id: string;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { id, class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["modal-backdrop", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} id={id} style="display: none;" {...rest}>
|
||||
<div class="modal">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const modalTriggers = document.querySelectorAll("[data-modal-trigger]");
|
||||
const modalCloses = document.querySelectorAll("[data-modal-close]");
|
||||
|
||||
modalTriggers.forEach((trigger) => {
|
||||
trigger.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
const modalId = trigger.getAttribute("data-modal-trigger");
|
||||
const modal = document.getElementById(modalId || "");
|
||||
if (modal) {
|
||||
modal.style.display = "flex";
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
modalCloses.forEach((close) => {
|
||||
close.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
const modal = close.closest(".modal-backdrop");
|
||||
if (modal) {
|
||||
(modal as HTMLElement).style.display = "none";
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener("click", (e) => {
|
||||
if (
|
||||
e.target &&
|
||||
(e.target as HTMLElement).classList.contains("modal-backdrop")
|
||||
) {
|
||||
(e.target as HTMLElement).style.display = "none";
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.modal-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: var(--z-modal-backdrop);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modal {
|
||||
background-color: var(--bg-card);
|
||||
border: 1px solid var(--border-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-xl);
|
||||
max-width: 90vw;
|
||||
max-height: 90vh;
|
||||
overflow: auto;
|
||||
z-index: var(--z-modal);
|
||||
}
|
||||
</style>
|
19
src/components/ui/ModalBody.astro
Normal file
19
src/components/ui/ModalBody.astro
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["modal-body", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} {...rest}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.modal-body {
|
||||
padding: var(--spacing-6);
|
||||
}
|
||||
</style>
|
23
src/components/ui/ModalFooter.astro
Normal file
23
src/components/ui/ModalFooter.astro
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["modal-footer", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} {...rest}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.modal-footer {
|
||||
padding: var(--spacing-6);
|
||||
border-top: 1px solid var(--border-primary);
|
||||
display: flex;
|
||||
gap: var(--spacing-3);
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
28
src/components/ui/ModalHeader.astro
Normal file
28
src/components/ui/ModalHeader.astro
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
import Button from "./Button.astro";
|
||||
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["modal-header", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} {...rest}>
|
||||
<slot />
|
||||
<Button variant="ghost" icon data-modal-close>
|
||||
<span>×</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.modal-header {
|
||||
padding: var(--spacing-6);
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
22
src/components/ui/ModalTitle.astro
Normal file
22
src/components/ui/ModalTitle.astro
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["modal-title", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<h2 class={classes} {...rest}>
|
||||
<slot />
|
||||
</h2>
|
||||
|
||||
<style>
|
||||
.modal-title {
|
||||
font-size: var(--font-size-lg);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--text-primary);
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
115
src/components/ui/MovieCard.astro
Normal file
115
src/components/ui/MovieCard.astro
Normal file
@ -0,0 +1,115 @@
|
||||
---
|
||||
import Card from "./Card.astro";
|
||||
|
||||
export interface Props {
|
||||
title: string;
|
||||
poster: string;
|
||||
year?: number;
|
||||
genre?: string;
|
||||
rating?: number;
|
||||
href?: string;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
poster,
|
||||
year,
|
||||
genre,
|
||||
rating,
|
||||
href,
|
||||
class: className = "",
|
||||
...rest
|
||||
} = Astro.props;
|
||||
|
||||
const classes = ["movie-card", className].filter(Boolean).join(" ");
|
||||
const Tag = href ? "a" : "div";
|
||||
---
|
||||
|
||||
<Tag class={classes} href={href} {...rest}>
|
||||
<Card class="movie-card-inner">
|
||||
<img src={poster} alt={title} class="movie-poster" loading="lazy" />
|
||||
<div class="movie-info">
|
||||
<h3 class="movie-title">{title}</h3>
|
||||
{
|
||||
(year || genre) && (
|
||||
<div class="movie-meta">
|
||||
{year && <span>{year}</span>}
|
||||
{year && genre && <span> • </span>}
|
||||
{genre && <span>{genre}</span>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
rating && (
|
||||
<div class="movie-rating">
|
||||
<span>⭐</span>
|
||||
<span>{rating}/10</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</Card>
|
||||
</Tag>
|
||||
|
||||
<style>
|
||||
.movie-card {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.movie-card:hover {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.movie-card:hover :global(.movie-card-inner) {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
.movie-card-inner {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.movie-poster {
|
||||
width: 100%;
|
||||
aspect-ratio: 2/3;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.movie-info {
|
||||
padding: var(--spacing-4);
|
||||
}
|
||||
|
||||
.movie-title {
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-semibold);
|
||||
color: var(--text-primary);
|
||||
margin: 0 0 var(--spacing-2);
|
||||
line-height: var(--line-height-tight);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.movie-meta {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--spacing-2);
|
||||
}
|
||||
|
||||
.movie-rating {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-1);
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--primary-400);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
</style>
|
22
src/components/ui/NavLink.astro
Normal file
22
src/components/ui/NavLink.astro
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
export interface Props {
|
||||
href: string;
|
||||
active?: boolean;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { href, active = false, class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const baseClasses = "nav-link";
|
||||
const activeClasses = active ? "active" : "";
|
||||
|
||||
const classes = [baseClasses, activeClasses, className]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
---
|
||||
|
||||
<li>
|
||||
<a class={classes} href={href} {...rest}>
|
||||
<slot />
|
||||
</a>
|
||||
</li>
|
25
src/components/ui/Navbar.astro
Normal file
25
src/components/ui/Navbar.astro
Normal file
@ -0,0 +1,25 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["navbar", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<nav class={classes} {...rest}>
|
||||
<div class="container">
|
||||
<div class="row justify-content-between align-items-center">
|
||||
<div class="col-auto">
|
||||
<slot name="brand" />
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<slot name="nav" />
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<slot name="actions" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
14
src/components/ui/NavbarBrand.astro
Normal file
14
src/components/ui/NavbarBrand.astro
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
export interface Props {
|
||||
href?: string;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { href = "/", class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["navbar-brand", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<a class={classes} href={href} {...rest}>
|
||||
<slot />
|
||||
</a>
|
13
src/components/ui/NavbarNav.astro
Normal file
13
src/components/ui/NavbarNav.astro
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const classes = ["navbar-nav", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<ul class={classes} {...rest}>
|
||||
<slot />
|
||||
</ul>
|
40
src/components/ui/Progress.astro
Normal file
40
src/components/ui/Progress.astro
Normal file
@ -0,0 +1,40 @@
|
||||
---
|
||||
export interface Props {
|
||||
value: number;
|
||||
max?: number;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { value, max = 100, class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const percentage = Math.min((value / max) * 100, 100);
|
||||
const classes = ["progress", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} {...rest}>
|
||||
<div
|
||||
class="progress-bar"
|
||||
style={`width: ${percentage}%`}
|
||||
role="progressbar"
|
||||
aria-valuenow={value}
|
||||
aria-valuemin="0"
|
||||
aria-valuemax={max}
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.progress {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
background-color: var(--bg-tertiary);
|
||||
border-radius: var(--radius-full);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: 100%;
|
||||
background-color: var(--primary-600);
|
||||
transition: width var(--transition-normal);
|
||||
}
|
||||
</style>
|
14
src/components/ui/Row.astro
Normal file
14
src/components/ui/Row.astro
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
export interface Props {
|
||||
class?: string;
|
||||
style?: string;
|
||||
}
|
||||
|
||||
const { class: className = "", style, ...rest } = Astro.props;
|
||||
|
||||
const classes = ["row", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} style={style} {...rest}>
|
||||
<slot />
|
||||
</div>
|
65
src/components/ui/SearchBar.astro
Normal file
65
src/components/ui/SearchBar.astro
Normal file
@ -0,0 +1,65 @@
|
||||
---
|
||||
import Input from "./Input.astro";
|
||||
|
||||
export interface Props {
|
||||
placeholder?: string;
|
||||
value?: string;
|
||||
name?: string;
|
||||
id?: string;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
placeholder = "Rechercher...",
|
||||
value,
|
||||
name = "search",
|
||||
id = "search",
|
||||
class: className = "",
|
||||
...rest
|
||||
} = Astro.props;
|
||||
|
||||
const classes = ["search-bar", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} {...rest}>
|
||||
<Input
|
||||
type="search"
|
||||
class="search-input"
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
name={name}
|
||||
id={id}
|
||||
/>
|
||||
<svg
|
||||
class="search-icon"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
>
|
||||
<circle cx="11" cy="11" r="8"></circle>
|
||||
<path d="M21 21l-4.35-4.35"></path>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.search-bar {
|
||||
position: relative;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.search-bar :global(.search-input) {
|
||||
padding-left: var(--spacing-10);
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
left: var(--spacing-3);
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: var(--text-muted);
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
51
src/components/ui/Select.astro
Normal file
51
src/components/ui/Select.astro
Normal file
@ -0,0 +1,51 @@
|
||||
---
|
||||
export interface Props {
|
||||
name?: string;
|
||||
id?: string;
|
||||
disabled?: boolean;
|
||||
required?: boolean;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
name,
|
||||
id,
|
||||
disabled = false,
|
||||
required = false,
|
||||
class: className = "",
|
||||
...rest
|
||||
} = Astro.props;
|
||||
|
||||
const classes = ["select", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<select
|
||||
class={classes}
|
||||
name={name}
|
||||
id={id}
|
||||
disabled={disabled}
|
||||
required={required}
|
||||
{...rest}
|
||||
>
|
||||
<slot />
|
||||
</select>
|
||||
|
||||
<style>
|
||||
.select {
|
||||
width: 100%;
|
||||
padding: var(--spacing-3) var(--spacing-4);
|
||||
font-size: var(--font-size-base);
|
||||
line-height: var(--line-height-normal);
|
||||
color: var(--text-primary);
|
||||
background-color: var(--bg-tertiary);
|
||||
border: 1px solid var(--border-primary);
|
||||
border-radius: var(--radius-md);
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.select:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-600);
|
||||
box-shadow: 0 0 0 3px rgba(132, 61, 255, 0.1);
|
||||
}
|
||||
</style>
|
47
src/components/ui/Spinner.astro
Normal file
47
src/components/ui/Spinner.astro
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
export interface Props {
|
||||
size?: "sm" | "lg";
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { size, class: className = "", ...rest } = Astro.props;
|
||||
|
||||
const baseClasses = "spinner";
|
||||
const sizeClasses = size ? `spinner-${size}` : "";
|
||||
|
||||
const classes = [baseClasses, sizeClasses, className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<div class={classes} {...rest}></div>
|
||||
|
||||
<style>
|
||||
.spinner {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border: 2px solid var(--border-primary);
|
||||
border-top: 2px solid var(--primary-600);
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.spinner-sm {
|
||||
width: 0.75rem;
|
||||
height: 0.75rem;
|
||||
border-width: 1.5px;
|
||||
}
|
||||
|
||||
.spinner-lg {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
59
src/components/ui/Textarea.astro
Normal file
59
src/components/ui/Textarea.astro
Normal file
@ -0,0 +1,59 @@
|
||||
---
|
||||
export interface Props {
|
||||
placeholder?: string;
|
||||
value?: string;
|
||||
name?: string;
|
||||
id?: string;
|
||||
rows?: number;
|
||||
disabled?: boolean;
|
||||
required?: boolean;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
placeholder,
|
||||
value,
|
||||
name,
|
||||
id,
|
||||
rows = 4,
|
||||
disabled = false,
|
||||
required = false,
|
||||
class: className = "",
|
||||
...rest
|
||||
} = Astro.props;
|
||||
|
||||
const classes = ["textarea", className].filter(Boolean).join(" ");
|
||||
---
|
||||
|
||||
<textarea
|
||||
class={classes}
|
||||
placeholder={placeholder}
|
||||
name={name}
|
||||
id={id}
|
||||
rows={rows}
|
||||
disabled={disabled}
|
||||
required={required}
|
||||
{...rest}>{value}</textarea
|
||||
>
|
||||
|
||||
<style>
|
||||
.textarea {
|
||||
width: 100%;
|
||||
padding: var(--spacing-3) var(--spacing-4);
|
||||
font-size: var(--font-size-base);
|
||||
line-height: var(--line-height-normal);
|
||||
color: var(--text-primary);
|
||||
background-color: var(--bg-tertiary);
|
||||
border: 1px solid var(--border-primary);
|
||||
border-radius: var(--radius-md);
|
||||
transition: all var(--transition-fast);
|
||||
resize: vertical;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-600);
|
||||
box-shadow: 0 0 0 3px rgba(132, 61, 255, 0.1);
|
||||
}
|
||||
</style>
|
18
src/layouts/Layout.astro
Normal file
18
src/layouts/Layout.astro
Normal file
@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<title>Nixi - Streaming Films & Séries</title>
|
||||
</head>
|
||||
<body>
|
||||
<slot />
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<style is:global>
|
||||
@import "../styles/variables.css";
|
||||
@import "../styles/grid.css";
|
||||
</style>
|
282
src/pages/index.astro
Normal file
282
src/pages/index.astro
Normal file
@ -0,0 +1,282 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import Button from "../components/ui/Button.astro";
|
||||
import Card from "../components/ui/Card.astro";
|
||||
import CardHeader from "../components/ui/CardHeader.astro";
|
||||
import CardBody from "../components/ui/CardBody.astro";
|
||||
import CardFooter from "../components/ui/CardFooter.astro";
|
||||
import CardTitle from "../components/ui/CardTitle.astro";
|
||||
import CardSubtitle from "../components/ui/CardSubtitle.astro";
|
||||
import Badge from "../components/ui/Badge.astro";
|
||||
import Alert from "../components/ui/Alert.astro";
|
||||
import Container from "../components/ui/Container.astro";
|
||||
import Row from "../components/ui/Row.astro";
|
||||
import Col from "../components/ui/Col.astro";
|
||||
import Input from "../components/ui/Input.astro";
|
||||
import Textarea from "../components/ui/Textarea.astro";
|
||||
import Select from "../components/ui/Select.astro";
|
||||
import FormGroup from "../components/ui/FormGroup.astro";
|
||||
import FormLabel from "../components/ui/FormLabel.astro";
|
||||
import FormText from "../components/ui/FormText.astro";
|
||||
import FormError from "../components/ui/FormError.astro";
|
||||
import Modal from "../components/ui/Modal.astro";
|
||||
import ModalHeader from "../components/ui/ModalHeader.astro";
|
||||
import ModalBody from "../components/ui/ModalBody.astro";
|
||||
import ModalFooter from "../components/ui/ModalFooter.astro";
|
||||
import ModalTitle from "../components/ui/ModalTitle.astro";
|
||||
import Progress from "../components/ui/Progress.astro";
|
||||
import Spinner from "../components/ui/Spinner.astro";
|
||||
import MovieCard from "../components/ui/MovieCard.astro";
|
||||
import SearchBar from "../components/ui/SearchBar.astro";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<Container>
|
||||
<div style="padding: 2rem 0;">
|
||||
<h1
|
||||
style="color: var(--primary-400); margin-bottom: 3rem; text-align: center;"
|
||||
>
|
||||
🎬 Nixi - Design System Demo
|
||||
</h1>
|
||||
|
||||
<!-- Alerts -->
|
||||
<section style="margin-bottom: 3rem;">
|
||||
<h2 style="color: var(--text-primary); margin-bottom: 1rem;">
|
||||
📢 Alertes
|
||||
</h2>
|
||||
<Alert variant="success"
|
||||
>Succès ! Votre compte a été créé avec succès.</Alert
|
||||
>
|
||||
<Alert variant="warning"
|
||||
>Attention ! Votre abonnement expire bientôt.</Alert
|
||||
>
|
||||
<Alert variant="error">Erreur ! Impossible de charger le contenu.</Alert
|
||||
>
|
||||
<Alert variant="info"
|
||||
>Info : Nouveaux films ajoutés cette semaine.</Alert
|
||||
>
|
||||
</section>
|
||||
|
||||
<!-- Buttons -->
|
||||
<section style="margin-bottom: 3rem;">
|
||||
<h2 style="color: var(--text-primary); margin-bottom: 1rem;">
|
||||
🔘 Boutons
|
||||
</h2>
|
||||
<div
|
||||
style="display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem;"
|
||||
>
|
||||
<Button variant="primary">Primary</Button>
|
||||
<Button variant="secondary">Secondary</Button>
|
||||
<Button variant="outline">Outline</Button>
|
||||
<Button variant="ghost">Ghost</Button>
|
||||
<Button variant="primary" disabled>Disabled</Button>
|
||||
</div>
|
||||
<div
|
||||
style="display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem;"
|
||||
>
|
||||
<Button variant="primary" size="sm">Small</Button>
|
||||
<Button variant="primary">Normal</Button>
|
||||
<Button variant="primary" size="lg">Large</Button>
|
||||
<Button variant="primary" icon>⭐</Button>
|
||||
</div>
|
||||
<Button variant="primary" data-modal-trigger="demo-modal"
|
||||
>Ouvrir Modal</Button
|
||||
>
|
||||
</section>
|
||||
|
||||
<!-- Badges -->
|
||||
<section style="margin-bottom: 3rem;">
|
||||
<h2 style="color: var(--text-primary); margin-bottom: 1rem;">
|
||||
🏷️ Badges
|
||||
</h2>
|
||||
<div style="display: flex; gap: 0.5rem; flex-wrap: wrap;">
|
||||
<Badge variant="primary">Action</Badge>
|
||||
<Badge variant="secondary">Comédie</Badge>
|
||||
<Badge variant="success">HD</Badge>
|
||||
<Badge variant="warning">VF</Badge>
|
||||
<Badge variant="error">+18</Badge>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Progress & Spinner -->
|
||||
<Row style="margin-bottom: 3rem;">
|
||||
<Col md={6}>
|
||||
<h2 style="color: var(--text-primary); margin-bottom: 1rem;">
|
||||
📊 Progress
|
||||
</h2>
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<Progress value={25} />
|
||||
</div>
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<Progress value={60} />
|
||||
</div>
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<Progress value={90} />
|
||||
</div>
|
||||
</Col>
|
||||
<Col md={6}>
|
||||
<h2 style="color: var(--text-primary); margin-bottom: 1rem;">
|
||||
⏳ Spinners
|
||||
</h2>
|
||||
<div style="display: flex; gap: 1rem; align-items: center;">
|
||||
<Spinner size="sm" />
|
||||
<Spinner />
|
||||
<Spinner size="lg" />
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<!-- Search Bar -->
|
||||
<section style="margin-bottom: 3rem;">
|
||||
<h2 style="color: var(--text-primary); margin-bottom: 1rem;">
|
||||
🔍 Barre de recherche
|
||||
</h2>
|
||||
<SearchBar placeholder="Rechercher un film ou une série..." />
|
||||
</section>
|
||||
|
||||
<!-- Forms -->
|
||||
<Row style="margin-bottom: 3rem;">
|
||||
<Col md={6}>
|
||||
<h2 style="color: var(--text-primary); margin-bottom: 1rem;">
|
||||
📝 Formulaires
|
||||
</h2>
|
||||
<FormGroup>
|
||||
<FormLabel for="email">Email</FormLabel>
|
||||
<Input type="email" id="email" placeholder="votre@email.com" />
|
||||
<FormText>Nous ne partagerons jamais votre email.</FormText>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<FormLabel for="password">Mot de passe</FormLabel>
|
||||
<Input type="password" id="password" placeholder="••••••••" />
|
||||
<FormError
|
||||
>Le mot de passe doit contenir au moins 8 caractères.</FormError
|
||||
>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<FormLabel for="genre">Genre préféré</FormLabel>
|
||||
<Select id="genre">
|
||||
<option>Action</option>
|
||||
<option>Comédie</option>
|
||||
<option>Drame</option>
|
||||
<option>Sci-Fi</option>
|
||||
</Select>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<FormLabel for="bio">Biographie</FormLabel>
|
||||
<Textarea
|
||||
id="bio"
|
||||
placeholder="Parlez-nous de vos goûts cinématographiques..."
|
||||
rows={3}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
<Col md={6}>
|
||||
<h2 style="color: var(--text-primary); margin-bottom: 1rem;">
|
||||
🎬 MovieCards
|
||||
</h2>
|
||||
<Row>
|
||||
<Col md={6}>
|
||||
<MovieCard
|
||||
title="Inception"
|
||||
poster="https://via.placeholder.com/200x300/6b04fd/ffffff?text=Inception"
|
||||
year={2010}
|
||||
genre="Sci-Fi"
|
||||
rating={8.8}
|
||||
href="/film/inception"
|
||||
/>
|
||||
</Col>
|
||||
<Col md={6}>
|
||||
<MovieCard
|
||||
title="The Matrix"
|
||||
poster="https://via.placeholder.com/200x300/843dff/ffffff?text=Matrix"
|
||||
year={1999}
|
||||
genre="Action"
|
||||
rating={8.7}
|
||||
href="/film/matrix"
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<!-- Cards -->
|
||||
<section style="margin-bottom: 3rem;">
|
||||
<h2 style="color: var(--text-primary); margin-bottom: 1rem;">
|
||||
🃏 Cartes
|
||||
</h2>
|
||||
<Row>
|
||||
<Col md={4}>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Carte Standard</CardTitle>
|
||||
<CardSubtitle>Avec header et footer</CardSubtitle>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<p>Contenu de la carte avec du texte descriptif.</p>
|
||||
</CardBody>
|
||||
<CardFooter>
|
||||
<Row>
|
||||
<Col md={8}>
|
||||
<Button variant="primary" size="sm" class="w-100"
|
||||
>Action</Button
|
||||
>
|
||||
</Col>
|
||||
<Col md={4}>
|
||||
<Button variant="ghost" size="sm" class="w-100"
|
||||
>Annuler</Button
|
||||
>
|
||||
</Col>
|
||||
</Row>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col md={4}>
|
||||
<Card>
|
||||
<CardBody>
|
||||
<CardTitle>Carte Simple</CardTitle>
|
||||
<p>
|
||||
Une carte sans header ni footer, juste le contenu principal.
|
||||
</p>
|
||||
<Badge variant="success">Nouveau</Badge>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col md={4}>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Streaming Stats</CardTitle>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<p><strong>Films vus :</strong> 127</p>
|
||||
<p><strong>Séries terminées :</strong> 23</p>
|
||||
<p><strong>Temps total :</strong> 240h</p>
|
||||
<Progress value={75} />
|
||||
</CardBody>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</section>
|
||||
</div>
|
||||
</Container>
|
||||
|
||||
<!-- Modal Demo -->
|
||||
<Modal id="demo-modal">
|
||||
<ModalHeader>
|
||||
<ModalTitle>Exemple de Modal</ModalTitle>
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<p>
|
||||
Ceci est un exemple de modal avec du contenu. Vous pouvez y mettre des
|
||||
formulaires, des informations, ou tout autre contenu.
|
||||
</p>
|
||||
<FormGroup>
|
||||
<FormLabel for="modal-input">Votre nom</FormLabel>
|
||||
<Input type="text" id="modal-input" placeholder="Entrez votre nom" />
|
||||
</FormGroup>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button variant="primary">Confirmer</Button>
|
||||
<Button variant="secondary" data-modal-close>Annuler</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
</Layout>
|
934
src/styles/grid.css
Normal file
934
src/styles/grid.css
Normal file
@ -0,0 +1,934 @@
|
||||
.container {
|
||||
width: 100%;
|
||||
padding-right: var(--spacing-4);
|
||||
padding-left: var(--spacing-4);
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.container {
|
||||
max-width: 540px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
max-width: 720px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.container {
|
||||
max-width: 960px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.container {
|
||||
max-width: 1140px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1400px) {
|
||||
.container {
|
||||
max-width: 1320px;
|
||||
}
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
width: 100%;
|
||||
padding-right: var(--spacing-4);
|
||||
padding-left: var(--spacing-4);
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-right: calc(var(--spacing-3) * -1);
|
||||
margin-left: calc(var(--spacing-3) * -1);
|
||||
}
|
||||
|
||||
.row > * {
|
||||
padding-right: var(--spacing-3);
|
||||
padding-left: var(--spacing-3);
|
||||
}
|
||||
|
||||
.col {
|
||||
flex: 1 0 0%;
|
||||
}
|
||||
|
||||
.col-auto {
|
||||
flex: 0 0 auto;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.col-1 {
|
||||
flex: 0 0 auto;
|
||||
width: 8.33333333%;
|
||||
}
|
||||
.col-2 {
|
||||
flex: 0 0 auto;
|
||||
width: 16.66666667%;
|
||||
}
|
||||
.col-3 {
|
||||
flex: 0 0 auto;
|
||||
width: 25%;
|
||||
}
|
||||
.col-4 {
|
||||
flex: 0 0 auto;
|
||||
width: 33.33333333%;
|
||||
}
|
||||
.col-5 {
|
||||
flex: 0 0 auto;
|
||||
width: 41.66666667%;
|
||||
}
|
||||
.col-6 {
|
||||
flex: 0 0 auto;
|
||||
width: 50%;
|
||||
}
|
||||
.col-7 {
|
||||
flex: 0 0 auto;
|
||||
width: 58.33333333%;
|
||||
}
|
||||
.col-8 {
|
||||
flex: 0 0 auto;
|
||||
width: 66.66666667%;
|
||||
}
|
||||
.col-9 {
|
||||
flex: 0 0 auto;
|
||||
width: 75%;
|
||||
}
|
||||
.col-10 {
|
||||
flex: 0 0 auto;
|
||||
width: 83.33333333%;
|
||||
}
|
||||
.col-11 {
|
||||
flex: 0 0 auto;
|
||||
width: 91.66666667%;
|
||||
}
|
||||
.col-12 {
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.col-sm {
|
||||
flex: 1 0 0%;
|
||||
}
|
||||
.col-sm-auto {
|
||||
flex: 0 0 auto;
|
||||
width: auto;
|
||||
}
|
||||
.col-sm-1 {
|
||||
flex: 0 0 auto;
|
||||
width: 8.33333333%;
|
||||
}
|
||||
.col-sm-2 {
|
||||
flex: 0 0 auto;
|
||||
width: 16.66666667%;
|
||||
}
|
||||
.col-sm-3 {
|
||||
flex: 0 0 auto;
|
||||
width: 25%;
|
||||
}
|
||||
.col-sm-4 {
|
||||
flex: 0 0 auto;
|
||||
width: 33.33333333%;
|
||||
}
|
||||
.col-sm-5 {
|
||||
flex: 0 0 auto;
|
||||
width: 41.66666667%;
|
||||
}
|
||||
.col-sm-6 {
|
||||
flex: 0 0 auto;
|
||||
width: 50%;
|
||||
}
|
||||
.col-sm-7 {
|
||||
flex: 0 0 auto;
|
||||
width: 58.33333333%;
|
||||
}
|
||||
.col-sm-8 {
|
||||
flex: 0 0 auto;
|
||||
width: 66.66666667%;
|
||||
}
|
||||
.col-sm-9 {
|
||||
flex: 0 0 auto;
|
||||
width: 75%;
|
||||
}
|
||||
.col-sm-10 {
|
||||
flex: 0 0 auto;
|
||||
width: 83.33333333%;
|
||||
}
|
||||
.col-sm-11 {
|
||||
flex: 0 0 auto;
|
||||
width: 91.66666667%;
|
||||
}
|
||||
.col-sm-12 {
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.col-md {
|
||||
flex: 1 0 0%;
|
||||
}
|
||||
.col-md-auto {
|
||||
flex: 0 0 auto;
|
||||
width: auto;
|
||||
}
|
||||
.col-md-1 {
|
||||
flex: 0 0 auto;
|
||||
width: 8.33333333%;
|
||||
}
|
||||
.col-md-2 {
|
||||
flex: 0 0 auto;
|
||||
width: 16.66666667%;
|
||||
}
|
||||
.col-md-3 {
|
||||
flex: 0 0 auto;
|
||||
width: 25%;
|
||||
}
|
||||
.col-md-4 {
|
||||
flex: 0 0 auto;
|
||||
width: 33.33333333%;
|
||||
}
|
||||
.col-md-5 {
|
||||
flex: 0 0 auto;
|
||||
width: 41.66666667%;
|
||||
}
|
||||
.col-md-6 {
|
||||
flex: 0 0 auto;
|
||||
width: 50%;
|
||||
}
|
||||
.col-md-7 {
|
||||
flex: 0 0 auto;
|
||||
width: 58.33333333%;
|
||||
}
|
||||
.col-md-8 {
|
||||
flex: 0 0 auto;
|
||||
width: 66.66666667%;
|
||||
}
|
||||
.col-md-9 {
|
||||
flex: 0 0 auto;
|
||||
width: 75%;
|
||||
}
|
||||
.col-md-10 {
|
||||
flex: 0 0 auto;
|
||||
width: 83.33333333%;
|
||||
}
|
||||
.col-md-11 {
|
||||
flex: 0 0 auto;
|
||||
width: 91.66666667%;
|
||||
}
|
||||
.col-md-12 {
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.col-lg {
|
||||
flex: 1 0 0%;
|
||||
}
|
||||
.col-lg-auto {
|
||||
flex: 0 0 auto;
|
||||
width: auto;
|
||||
}
|
||||
.col-lg-1 {
|
||||
flex: 0 0 auto;
|
||||
width: 8.33333333%;
|
||||
}
|
||||
.col-lg-2 {
|
||||
flex: 0 0 auto;
|
||||
width: 16.66666667%;
|
||||
}
|
||||
.col-lg-3 {
|
||||
flex: 0 0 auto;
|
||||
width: 25%;
|
||||
}
|
||||
.col-lg-4 {
|
||||
flex: 0 0 auto;
|
||||
width: 33.33333333%;
|
||||
}
|
||||
.col-lg-5 {
|
||||
flex: 0 0 auto;
|
||||
width: 41.66666667%;
|
||||
}
|
||||
.col-lg-6 {
|
||||
flex: 0 0 auto;
|
||||
width: 50%;
|
||||
}
|
||||
.col-lg-7 {
|
||||
flex: 0 0 auto;
|
||||
width: 58.33333333%;
|
||||
}
|
||||
.col-lg-8 {
|
||||
flex: 0 0 auto;
|
||||
width: 66.66666667%;
|
||||
}
|
||||
.col-lg-9 {
|
||||
flex: 0 0 auto;
|
||||
width: 75%;
|
||||
}
|
||||
.col-lg-10 {
|
||||
flex: 0 0 auto;
|
||||
width: 83.33333333%;
|
||||
}
|
||||
.col-lg-11 {
|
||||
flex: 0 0 auto;
|
||||
width: 91.66666667%;
|
||||
}
|
||||
.col-lg-12 {
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.col-xl {
|
||||
flex: 1 0 0%;
|
||||
}
|
||||
.col-xl-auto {
|
||||
flex: 0 0 auto;
|
||||
width: auto;
|
||||
}
|
||||
.col-xl-1 {
|
||||
flex: 0 0 auto;
|
||||
width: 8.33333333%;
|
||||
}
|
||||
.col-xl-2 {
|
||||
flex: 0 0 auto;
|
||||
width: 16.66666667%;
|
||||
}
|
||||
.col-xl-3 {
|
||||
flex: 0 0 auto;
|
||||
width: 25%;
|
||||
}
|
||||
.col-xl-4 {
|
||||
flex: 0 0 auto;
|
||||
width: 33.33333333%;
|
||||
}
|
||||
.col-xl-5 {
|
||||
flex: 0 0 auto;
|
||||
width: 41.66666667%;
|
||||
}
|
||||
.col-xl-6 {
|
||||
flex: 0 0 auto;
|
||||
width: 50%;
|
||||
}
|
||||
.col-xl-7 {
|
||||
flex: 0 0 auto;
|
||||
width: 58.33333333%;
|
||||
}
|
||||
.col-xl-8 {
|
||||
flex: 0 0 auto;
|
||||
width: 66.66666667%;
|
||||
}
|
||||
.col-xl-9 {
|
||||
flex: 0 0 auto;
|
||||
width: 75%;
|
||||
}
|
||||
.col-xl-10 {
|
||||
flex: 0 0 auto;
|
||||
width: 83.33333333%;
|
||||
}
|
||||
.col-xl-11 {
|
||||
flex: 0 0 auto;
|
||||
width: 91.66666667%;
|
||||
}
|
||||
.col-xl-12 {
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1400px) {
|
||||
.col-xxl {
|
||||
flex: 1 0 0%;
|
||||
}
|
||||
.col-xxl-auto {
|
||||
flex: 0 0 auto;
|
||||
width: auto;
|
||||
}
|
||||
.col-xxl-1 {
|
||||
flex: 0 0 auto;
|
||||
width: 8.33333333%;
|
||||
}
|
||||
.col-xxl-2 {
|
||||
flex: 0 0 auto;
|
||||
width: 16.66666667%;
|
||||
}
|
||||
.col-xxl-3 {
|
||||
flex: 0 0 auto;
|
||||
width: 25%;
|
||||
}
|
||||
.col-xxl-4 {
|
||||
flex: 0 0 auto;
|
||||
width: 33.33333333%;
|
||||
}
|
||||
.col-xxl-5 {
|
||||
flex: 0 0 auto;
|
||||
width: 41.66666667%;
|
||||
}
|
||||
.col-xxl-6 {
|
||||
flex: 0 0 auto;
|
||||
width: 50%;
|
||||
}
|
||||
.col-xxl-7 {
|
||||
flex: 0 0 auto;
|
||||
width: 58.33333333%;
|
||||
}
|
||||
.col-xxl-8 {
|
||||
flex: 0 0 auto;
|
||||
width: 66.66666667%;
|
||||
}
|
||||
.col-xxl-9 {
|
||||
flex: 0 0 auto;
|
||||
width: 75%;
|
||||
}
|
||||
.col-xxl-10 {
|
||||
flex: 0 0 auto;
|
||||
width: 83.33333333%;
|
||||
}
|
||||
.col-xxl-11 {
|
||||
flex: 0 0 auto;
|
||||
width: 91.66666667%;
|
||||
}
|
||||
.col-xxl-12 {
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.offset-1 {
|
||||
margin-left: 8.33333333%;
|
||||
}
|
||||
.offset-2 {
|
||||
margin-left: 16.66666667%;
|
||||
}
|
||||
.offset-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
.offset-4 {
|
||||
margin-left: 33.33333333%;
|
||||
}
|
||||
.offset-5 {
|
||||
margin-left: 41.66666667%;
|
||||
}
|
||||
.offset-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
.offset-7 {
|
||||
margin-left: 58.33333333%;
|
||||
}
|
||||
.offset-8 {
|
||||
margin-left: 66.66666667%;
|
||||
}
|
||||
.offset-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
.offset-10 {
|
||||
margin-left: 83.33333333%;
|
||||
}
|
||||
.offset-11 {
|
||||
margin-left: 91.66666667%;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.offset-sm-0 {
|
||||
margin-left: 0;
|
||||
}
|
||||
.offset-sm-1 {
|
||||
margin-left: 8.33333333%;
|
||||
}
|
||||
.offset-sm-2 {
|
||||
margin-left: 16.66666667%;
|
||||
}
|
||||
.offset-sm-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
.offset-sm-4 {
|
||||
margin-left: 33.33333333%;
|
||||
}
|
||||
.offset-sm-5 {
|
||||
margin-left: 41.66666667%;
|
||||
}
|
||||
.offset-sm-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
.offset-sm-7 {
|
||||
margin-left: 58.33333333%;
|
||||
}
|
||||
.offset-sm-8 {
|
||||
margin-left: 66.66666667%;
|
||||
}
|
||||
.offset-sm-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
.offset-sm-10 {
|
||||
margin-left: 83.33333333%;
|
||||
}
|
||||
.offset-sm-11 {
|
||||
margin-left: 91.66666667%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.offset-md-0 {
|
||||
margin-left: 0;
|
||||
}
|
||||
.offset-md-1 {
|
||||
margin-left: 8.33333333%;
|
||||
}
|
||||
.offset-md-2 {
|
||||
margin-left: 16.66666667%;
|
||||
}
|
||||
.offset-md-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
.offset-md-4 {
|
||||
margin-left: 33.33333333%;
|
||||
}
|
||||
.offset-md-5 {
|
||||
margin-left: 41.66666667%;
|
||||
}
|
||||
.offset-md-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
.offset-md-7 {
|
||||
margin-left: 58.33333333%;
|
||||
}
|
||||
.offset-md-8 {
|
||||
margin-left: 66.66666667%;
|
||||
}
|
||||
.offset-md-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
.offset-md-10 {
|
||||
margin-left: 83.33333333%;
|
||||
}
|
||||
.offset-md-11 {
|
||||
margin-left: 91.66666667%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.offset-lg-0 {
|
||||
margin-left: 0;
|
||||
}
|
||||
.offset-lg-1 {
|
||||
margin-left: 8.33333333%;
|
||||
}
|
||||
.offset-lg-2 {
|
||||
margin-left: 16.66666667%;
|
||||
}
|
||||
.offset-lg-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
.offset-lg-4 {
|
||||
margin-left: 33.33333333%;
|
||||
}
|
||||
.offset-lg-5 {
|
||||
margin-left: 41.66666667%;
|
||||
}
|
||||
.offset-lg-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
.offset-lg-7 {
|
||||
margin-left: 58.33333333%;
|
||||
}
|
||||
.offset-lg-8 {
|
||||
margin-left: 66.66666667%;
|
||||
}
|
||||
.offset-lg-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
.offset-lg-10 {
|
||||
margin-left: 83.33333333%;
|
||||
}
|
||||
.offset-lg-11 {
|
||||
margin-left: 91.66666667%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.offset-xl-0 {
|
||||
margin-left: 0;
|
||||
}
|
||||
.offset-xl-1 {
|
||||
margin-left: 8.33333333%;
|
||||
}
|
||||
.offset-xl-2 {
|
||||
margin-left: 16.66666667%;
|
||||
}
|
||||
.offset-xl-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
.offset-xl-4 {
|
||||
margin-left: 33.33333333%;
|
||||
}
|
||||
.offset-xl-5 {
|
||||
margin-left: 41.66666667%;
|
||||
}
|
||||
.offset-xl-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
.offset-xl-7 {
|
||||
margin-left: 58.33333333%;
|
||||
}
|
||||
.offset-xl-8 {
|
||||
margin-left: 66.66666667%;
|
||||
}
|
||||
.offset-xl-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
.offset-xl-10 {
|
||||
margin-left: 83.33333333%;
|
||||
}
|
||||
.offset-xl-11 {
|
||||
margin-left: 91.66666667%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1400px) {
|
||||
.offset-xxl-0 {
|
||||
margin-left: 0;
|
||||
}
|
||||
.offset-xxl-1 {
|
||||
margin-left: 8.33333333%;
|
||||
}
|
||||
.offset-xxl-2 {
|
||||
margin-left: 16.66666667%;
|
||||
}
|
||||
.offset-xxl-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
.offset-xxl-4 {
|
||||
margin-left: 33.33333333%;
|
||||
}
|
||||
.offset-xxl-5 {
|
||||
margin-left: 41.66666667%;
|
||||
}
|
||||
.offset-xxl-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
.offset-xxl-7 {
|
||||
margin-left: 58.33333333%;
|
||||
}
|
||||
.offset-xxl-8 {
|
||||
margin-left: 66.66666667%;
|
||||
}
|
||||
.offset-xxl-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
.offset-xxl-10 {
|
||||
margin-left: 83.33333333%;
|
||||
}
|
||||
.offset-xxl-11 {
|
||||
margin-left: 91.66666667%;
|
||||
}
|
||||
}
|
||||
|
||||
.justify-content-start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.justify-content-end {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.justify-content-center {
|
||||
justify-content: center;
|
||||
}
|
||||
.justify-content-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.justify-content-around {
|
||||
justify-content: space-around;
|
||||
}
|
||||
.justify-content-evenly {
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.align-items-start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
.align-items-end {
|
||||
align-items: flex-end;
|
||||
}
|
||||
.align-items-center {
|
||||
align-items: center;
|
||||
}
|
||||
.align-items-baseline {
|
||||
align-items: baseline;
|
||||
}
|
||||
.align-items-stretch {
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.flex-row {
|
||||
flex-direction: row;
|
||||
}
|
||||
.flex-column {
|
||||
flex-direction: column;
|
||||
}
|
||||
.flex-row-reverse {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
.flex-column-reverse {
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
.flex-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.flex-nowrap {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
.flex-wrap-reverse {
|
||||
flex-wrap: wrap-reverse;
|
||||
}
|
||||
|
||||
.w-100 {
|
||||
width: 100% !important;
|
||||
}
|
||||
.w-auto {
|
||||
width: auto !important;
|
||||
}
|
||||
.w-75 {
|
||||
width: 75% !important;
|
||||
}
|
||||
.w-50 {
|
||||
width: 50% !important;
|
||||
}
|
||||
.w-25 {
|
||||
width: 25% !important;
|
||||
}
|
||||
|
||||
.h-100 {
|
||||
height: 100% !important;
|
||||
}
|
||||
.h-auto {
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.d-block {
|
||||
display: block !important;
|
||||
}
|
||||
.d-inline {
|
||||
display: inline !important;
|
||||
}
|
||||
.d-inline-block {
|
||||
display: inline-block !important;
|
||||
}
|
||||
.d-flex {
|
||||
display: flex !important;
|
||||
}
|
||||
.d-inline-flex {
|
||||
display: inline-flex !important;
|
||||
}
|
||||
.d-none {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.text-left {
|
||||
text-align: left !important;
|
||||
}
|
||||
.text-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
.text-right {
|
||||
text-align: right !important;
|
||||
}
|
||||
|
||||
.m-0 {
|
||||
margin: 0 !important;
|
||||
}
|
||||
.m-1 {
|
||||
margin: var(--spacing-1) !important;
|
||||
}
|
||||
.m-2 {
|
||||
margin: var(--spacing-2) !important;
|
||||
}
|
||||
.m-3 {
|
||||
margin: var(--spacing-3) !important;
|
||||
}
|
||||
.m-4 {
|
||||
margin: var(--spacing-4) !important;
|
||||
}
|
||||
.m-5 {
|
||||
margin: var(--spacing-5) !important;
|
||||
}
|
||||
|
||||
.mt-0 {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
.mt-1 {
|
||||
margin-top: var(--spacing-1) !important;
|
||||
}
|
||||
.mt-2 {
|
||||
margin-top: var(--spacing-2) !important;
|
||||
}
|
||||
.mt-3 {
|
||||
margin-top: var(--spacing-3) !important;
|
||||
}
|
||||
.mt-4 {
|
||||
margin-top: var(--spacing-4) !important;
|
||||
}
|
||||
.mt-5 {
|
||||
margin-top: var(--spacing-5) !important;
|
||||
}
|
||||
|
||||
.mb-0 {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.mb-1 {
|
||||
margin-bottom: var(--spacing-1) !important;
|
||||
}
|
||||
.mb-2 {
|
||||
margin-bottom: var(--spacing-2) !important;
|
||||
}
|
||||
.mb-3 {
|
||||
margin-bottom: var(--spacing-3) !important;
|
||||
}
|
||||
.mb-4 {
|
||||
margin-bottom: var(--spacing-4) !important;
|
||||
}
|
||||
.mb-5 {
|
||||
margin-bottom: var(--spacing-5) !important;
|
||||
}
|
||||
|
||||
.ms-0 {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
.ms-1 {
|
||||
margin-left: var(--spacing-1) !important;
|
||||
}
|
||||
.ms-2 {
|
||||
margin-left: var(--spacing-2) !important;
|
||||
}
|
||||
.ms-3 {
|
||||
margin-left: var(--spacing-3) !important;
|
||||
}
|
||||
.ms-4 {
|
||||
margin-left: var(--spacing-4) !important;
|
||||
}
|
||||
.ms-5 {
|
||||
margin-left: var(--spacing-5) !important;
|
||||
}
|
||||
|
||||
.me-0 {
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
.me-1 {
|
||||
margin-right: var(--spacing-1) !important;
|
||||
}
|
||||
.me-2 {
|
||||
margin-right: var(--spacing-2) !important;
|
||||
}
|
||||
.me-3 {
|
||||
margin-right: var(--spacing-3) !important;
|
||||
}
|
||||
.me-4 {
|
||||
margin-right: var(--spacing-4) !important;
|
||||
}
|
||||
.me-5 {
|
||||
margin-right: var(--spacing-5) !important;
|
||||
}
|
||||
|
||||
.p-0 {
|
||||
padding: 0 !important;
|
||||
}
|
||||
.p-1 {
|
||||
padding: var(--spacing-1) !important;
|
||||
}
|
||||
.p-2 {
|
||||
padding: var(--spacing-2) !important;
|
||||
}
|
||||
.p-3 {
|
||||
padding: var(--spacing-3) !important;
|
||||
}
|
||||
.p-4 {
|
||||
padding: var(--spacing-4) !important;
|
||||
}
|
||||
.p-5 {
|
||||
padding: var(--spacing-5) !important;
|
||||
}
|
||||
|
||||
.pt-0 {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
.pt-1 {
|
||||
padding-top: var(--spacing-1) !important;
|
||||
}
|
||||
.pt-2 {
|
||||
padding-top: var(--spacing-2) !important;
|
||||
}
|
||||
.pt-3 {
|
||||
padding-top: var(--spacing-3) !important;
|
||||
}
|
||||
.pt-4 {
|
||||
padding-top: var(--spacing-4) !important;
|
||||
}
|
||||
.pt-5 {
|
||||
padding-top: var(--spacing-5) !important;
|
||||
}
|
||||
|
||||
.pb-0 {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
.pb-1 {
|
||||
padding-bottom: var(--spacing-1) !important;
|
||||
}
|
||||
.pb-2 {
|
||||
padding-bottom: var(--spacing-2) !important;
|
||||
}
|
||||
.pb-3 {
|
||||
padding-bottom: var(--spacing-3) !important;
|
||||
}
|
||||
.pb-4 {
|
||||
padding-bottom: var(--spacing-4) !important;
|
||||
}
|
||||
.pb-5 {
|
||||
padding-bottom: var(--spacing-5) !important;
|
||||
}
|
||||
|
||||
.ps-0 {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
.ps-1 {
|
||||
padding-left: var(--spacing-1) !important;
|
||||
}
|
||||
.ps-2 {
|
||||
padding-left: var(--spacing-2) !important;
|
||||
}
|
||||
.ps-3 {
|
||||
padding-left: var(--spacing-3) !important;
|
||||
}
|
||||
.ps-4 {
|
||||
padding-left: var(--spacing-4) !important;
|
||||
}
|
||||
.ps-5 {
|
||||
padding-left: var(--spacing-5) !important;
|
||||
}
|
||||
|
||||
.pe-0 {
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
.pe-1 {
|
||||
padding-right: var(--spacing-1) !important;
|
||||
}
|
||||
.pe-2 {
|
||||
padding-right: var(--spacing-2) !important;
|
||||
}
|
||||
.pe-3 {
|
||||
padding-right: var(--spacing-3) !important;
|
||||
}
|
||||
.pe-4 {
|
||||
padding-right: var(--spacing-4) !important;
|
||||
}
|
||||
.pe-5 {
|
||||
padding-right: var(--spacing-5) !important;
|
||||
}
|
163
src/styles/variables.css
Normal file
163
src/styles/variables.css
Normal file
@ -0,0 +1,163 @@
|
||||
:root {
|
||||
--primary-50: #f3f1ff;
|
||||
--primary-100: #ebe5ff;
|
||||
--primary-200: #d9ccff;
|
||||
--primary-300: #bea6ff;
|
||||
--primary-400: #9f75ff;
|
||||
--primary-500: #843dff;
|
||||
--primary-600: #7916ff;
|
||||
--primary-700: #6b04fd;
|
||||
--primary-800: #5a03d4;
|
||||
--primary-900: #4b05ad;
|
||||
--primary-950: #2c0274;
|
||||
|
||||
--gray-50: #f8fafc;
|
||||
--gray-100: #f1f5f9;
|
||||
--gray-200: #e2e8f0;
|
||||
--gray-300: #cbd5e1;
|
||||
--gray-400: #94a3b8;
|
||||
--gray-500: #64748b;
|
||||
--gray-600: #475569;
|
||||
--gray-700: #334155;
|
||||
--gray-800: #1e293b;
|
||||
--gray-900: #0f172a;
|
||||
--gray-950: #020617;
|
||||
|
||||
--success: #10b981;
|
||||
--warning: #f59e0b;
|
||||
--error: #ef4444;
|
||||
--info: #3b82f6;
|
||||
|
||||
--bg-primary: var(--gray-950);
|
||||
--bg-secondary: var(--gray-900);
|
||||
--bg-tertiary: var(--gray-800);
|
||||
--bg-card: var(--gray-900);
|
||||
--bg-hover: var(--gray-800);
|
||||
|
||||
--text-primary: var(--gray-50);
|
||||
--text-secondary: var(--gray-300);
|
||||
--text-muted: var(--gray-500);
|
||||
|
||||
--border-primary: var(--gray-700);
|
||||
--border-secondary: var(--gray-800);
|
||||
|
||||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||
--shadow-lg:
|
||||
0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
--shadow-xl:
|
||||
0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
||||
|
||||
--radius-sm: 0.125rem;
|
||||
--radius: 0.25rem;
|
||||
--radius-md: 0.375rem;
|
||||
--radius-lg: 0.5rem;
|
||||
--radius-xl: 0.75rem;
|
||||
--radius-2xl: 1rem;
|
||||
--radius-3xl: 1.5rem;
|
||||
--radius-full: 9999px;
|
||||
|
||||
--spacing-1: 0.25rem;
|
||||
--spacing-2: 0.5rem;
|
||||
--spacing-3: 0.75rem;
|
||||
--spacing-4: 1rem;
|
||||
--spacing-5: 1.25rem;
|
||||
--spacing-6: 1.5rem;
|
||||
--spacing-8: 2rem;
|
||||
--spacing-10: 2.5rem;
|
||||
--spacing-12: 3rem;
|
||||
--spacing-16: 4rem;
|
||||
--spacing-20: 5rem;
|
||||
--spacing-24: 6rem;
|
||||
--spacing-32: 8rem;
|
||||
|
||||
--font-family-sans:
|
||||
ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||
Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
|
||||
--font-family-mono:
|
||||
ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo,
|
||||
monospace;
|
||||
|
||||
--font-size-xs: 0.75rem;
|
||||
--font-size-sm: 0.875rem;
|
||||
--font-size-base: 1rem;
|
||||
--font-size-lg: 1.125rem;
|
||||
--font-size-xl: 1.25rem;
|
||||
--font-size-2xl: 1.5rem;
|
||||
--font-size-3xl: 1.875rem;
|
||||
--font-size-4xl: 2.25rem;
|
||||
--font-size-5xl: 3rem;
|
||||
|
||||
--font-weight-normal: 400;
|
||||
--font-weight-medium: 500;
|
||||
--font-weight-semibold: 600;
|
||||
--font-weight-bold: 700;
|
||||
|
||||
--line-height-tight: 1.25;
|
||||
--line-height-normal: 1.5;
|
||||
--line-height-relaxed: 1.625;
|
||||
|
||||
--transition-fast: 150ms ease;
|
||||
--transition-normal: 300ms ease;
|
||||
--transition-slow: 500ms ease;
|
||||
|
||||
--z-dropdown: 1000;
|
||||
--z-sticky: 1020;
|
||||
--z-fixed: 1030;
|
||||
--z-modal-backdrop: 1040;
|
||||
--z-modal: 1050;
|
||||
--z-popover: 1060;
|
||||
--z-tooltip: 1070;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: var(--font-family-sans);
|
||||
font-size: var(--font-size-base);
|
||||
line-height: var(--line-height-normal);
|
||||
color: var(--text-primary);
|
||||
background-color: var(--bg-primary);
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
/* Form Control Base Styles */
|
||||
.form-control-base {
|
||||
width: 100%;
|
||||
padding: var(--spacing-3) var(--spacing-4);
|
||||
font-size: var(--font-size-base);
|
||||
line-height: var(--line-height-normal);
|
||||
color: var(--text-primary);
|
||||
background-color: var(--bg-tertiary);
|
||||
border: 1px solid var(--border-primary);
|
||||
border-radius: var(--radius-md);
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.form-control-base:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-600);
|
||||
box-shadow: 0 0 0 3px rgba(132, 61, 255, 0.1);
|
||||
}
|
||||
|
||||
.form-control-base:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.form-control-base::placeholder {
|
||||
color: var(--text-muted);
|
||||
}
|
Reference in New Issue
Block a user