Design System
Sport Tech Club - Sistema de Design Unificado
Visão Geral
Este documento define o sistema de design do Sport Tech Club, garantindo consistência visual e de experiência em todas as interfaces da plataforma.
1. Fundamentos
1.1 Princípios de Design
yaml
principios:
esportivo:
descricao: Energia e dinamismo que refletem a prática esportiva
aplicacao: Cores vibrantes, formas dinâmicas, movimento
acessivel:
descricao: Usável por todos, independente de habilidade
aplicacao: Contrastes adequados, textos legíveis, áreas de toque generosas
mobile_first:
descricao: Projetado primeiro para dispositivos móveis
aplicacao: Touch-friendly, performance otimizada, offline-capable
confiavel:
descricao: Transmite segurança e profissionalismo
aplicacao: Consistência, feedback claro, estados bem definidos1.2 Tokens de Design
scss
// Design Tokens - Variáveis CSS/SCSS
// ===========================================
// CORES
// ===========================================
// Cores Primárias
$color-primary-50: #E3F2FD;
$color-primary-100: #BBDEFB;
$color-primary-200: #90CAF9;
$color-primary-300: #64B5F6;
$color-primary-400: #42A5F5;
$color-primary-500: #2196F3; // Principal
$color-primary-600: #1E88E5;
$color-primary-700: #1976D2;
$color-primary-800: #1565C0;
$color-primary-900: #0D47A1;
// Cores Secundárias (Accent)
$color-secondary-50: #FFF3E0;
$color-secondary-100: #FFE0B2;
$color-secondary-200: #FFCC80;
$color-secondary-300: #FFB74D;
$color-secondary-400: #FFA726;
$color-secondary-500: #FF9800; // Principal
$color-secondary-600: #FB8C00;
$color-secondary-700: #F57C00;
$color-secondary-800: #EF6C00;
$color-secondary-900: #E65100;
// Cores de Sucesso
$color-success-50: #E8F5E9;
$color-success-100: #C8E6C9;
$color-success-500: #4CAF50;
$color-success-700: #388E3C;
// Cores de Erro
$color-error-50: #FFEBEE;
$color-error-100: #FFCDD2;
$color-error-500: #F44336;
$color-error-700: #D32F2F;
// Cores de Aviso
$color-warning-50: #FFF8E1;
$color-warning-100: #FFECB3;
$color-warning-500: #FFC107;
$color-warning-700: #FFA000;
// Cores de Informação
$color-info-50: #E1F5FE;
$color-info-100: #B3E5FC;
$color-info-500: #03A9F4;
$color-info-700: #0288D1;
// Cores Neutras
$color-neutral-0: #FFFFFF;
$color-neutral-50: #FAFAFA;
$color-neutral-100: #F5F5F5;
$color-neutral-200: #EEEEEE;
$color-neutral-300: #E0E0E0;
$color-neutral-400: #BDBDBD;
$color-neutral-500: #9E9E9E;
$color-neutral-600: #757575;
$color-neutral-700: #616161;
$color-neutral-800: #424242;
$color-neutral-900: #212121;
$color-neutral-1000: #000000;
// Cores por Esporte
$color-sport-beach-tennis: #FF6B35;
$color-sport-beach-volley: #F7C948;
$color-sport-futevolei: #2EC4B6;
$color-sport-padel: #9B5DE5;2. Tipografia
2.1 Famílias de Fonte
scss
// Fontes
$font-family-primary: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
$font-family-secondary: 'Poppins', sans-serif;
$font-family-mono: 'JetBrains Mono', 'Fira Code', monospace;
// Import Google Fonts
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Poppins:wght@500;600;700&display=swap');2.2 Escala Tipográfica
scss
// Tamanhos de Fonte
$font-size-xs: 0.75rem; // 12px
$font-size-sm: 0.875rem; // 14px
$font-size-base: 1rem; // 16px
$font-size-lg: 1.125rem; // 18px
$font-size-xl: 1.25rem; // 20px
$font-size-2xl: 1.5rem; // 24px
$font-size-3xl: 1.875rem; // 30px
$font-size-4xl: 2.25rem; // 36px
$font-size-5xl: 3rem; // 48px
$font-size-6xl: 3.75rem; // 60px
// Pesos de Fonte
$font-weight-light: 300;
$font-weight-regular: 400;
$font-weight-medium: 500;
$font-weight-semibold: 600;
$font-weight-bold: 700;
// Altura de Linha
$line-height-tight: 1.25;
$line-height-snug: 1.375;
$line-height-normal: 1.5;
$line-height-relaxed: 1.625;
$line-height-loose: 2;
// Espaçamento entre Letras
$letter-spacing-tighter: -0.05em;
$letter-spacing-tight: -0.025em;
$letter-spacing-normal: 0;
$letter-spacing-wide: 0.025em;
$letter-spacing-wider: 0.05em;
$letter-spacing-widest: 0.1em;2.3 Estilos de Texto
scss
// Headings
.text-h1 {
font-family: $font-family-secondary;
font-size: $font-size-4xl;
font-weight: $font-weight-bold;
line-height: $line-height-tight;
letter-spacing: $letter-spacing-tight;
@media (max-width: 768px) {
font-size: $font-size-3xl;
}
}
.text-h2 {
font-family: $font-family-secondary;
font-size: $font-size-3xl;
font-weight: $font-weight-semibold;
line-height: $line-height-tight;
}
.text-h3 {
font-family: $font-family-secondary;
font-size: $font-size-2xl;
font-weight: $font-weight-semibold;
line-height: $line-height-snug;
}
.text-h4 {
font-family: $font-family-primary;
font-size: $font-size-xl;
font-weight: $font-weight-semibold;
line-height: $line-height-snug;
}
.text-h5 {
font-family: $font-family-primary;
font-size: $font-size-lg;
font-weight: $font-weight-medium;
line-height: $line-height-normal;
}
.text-h6 {
font-family: $font-family-primary;
font-size: $font-size-base;
font-weight: $font-weight-medium;
line-height: $line-height-normal;
}
// Body
.text-body-lg {
font-size: $font-size-lg;
line-height: $line-height-relaxed;
}
.text-body {
font-size: $font-size-base;
line-height: $line-height-normal;
}
.text-body-sm {
font-size: $font-size-sm;
line-height: $line-height-normal;
}
// Caption/Label
.text-caption {
font-size: $font-size-xs;
line-height: $line-height-normal;
letter-spacing: $letter-spacing-wide;
}
.text-overline {
font-size: $font-size-xs;
font-weight: $font-weight-semibold;
line-height: $line-height-normal;
letter-spacing: $letter-spacing-widest;
text-transform: uppercase;
}3. Espaçamento
3.1 Escala de Espaçamento
scss
// Espaçamento (baseado em 4px)
$spacing-0: 0;
$spacing-1: 0.25rem; // 4px
$spacing-2: 0.5rem; // 8px
$spacing-3: 0.75rem; // 12px
$spacing-4: 1rem; // 16px
$spacing-5: 1.25rem; // 20px
$spacing-6: 1.5rem; // 24px
$spacing-8: 2rem; // 32px
$spacing-10: 2.5rem; // 40px
$spacing-12: 3rem; // 48px
$spacing-16: 4rem; // 64px
$spacing-20: 5rem; // 80px
$spacing-24: 6rem; // 96px
// Aliases semânticos
$spacing-xs: $spacing-1;
$spacing-sm: $spacing-2;
$spacing-md: $spacing-4;
$spacing-lg: $spacing-6;
$spacing-xl: $spacing-8;
$spacing-2xl: $spacing-12;3.2 Layout Grid
scss
// Container
$container-max-width: 1280px;
$container-padding: $spacing-4;
// Grid
$grid-columns: 12;
$grid-gutter: $spacing-4;
// Breakpoints
$breakpoint-xs: 0;
$breakpoint-sm: 576px;
$breakpoint-md: 768px;
$breakpoint-lg: 992px;
$breakpoint-xl: 1200px;
$breakpoint-xxl: 1400px;
// Mixin para media queries
@mixin breakpoint($size) {
@if $size == 'sm' {
@media (min-width: $breakpoint-sm) { @content; }
} @else if $size == 'md' {
@media (min-width: $breakpoint-md) { @content; }
} @else if $size == 'lg' {
@media (min-width: $breakpoint-lg) { @content; }
} @else if $size == 'xl' {
@media (min-width: $breakpoint-xl) { @content; }
} @else if $size == 'xxl' {
@media (min-width: $breakpoint-xxl) { @content; }
}
}4. Componentes
4.1 Botões
scss
// Base do Botão
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: $spacing-2;
padding: $spacing-3 $spacing-6;
font-family: $font-family-primary;
font-size: $font-size-base;
font-weight: $font-weight-medium;
line-height: 1;
text-decoration: none;
border: none;
border-radius: $radius-md;
cursor: pointer;
transition: all 0.2s ease;
// Touch target mínimo de 44x44px
min-height: 44px;
min-width: 44px;
&:focus-visible {
outline: 2px solid $color-primary-500;
outline-offset: 2px;
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
// Variantes
.btn-primary {
@extend .btn;
background-color: $color-primary-500;
color: $color-neutral-0;
&:hover:not(:disabled) {
background-color: $color-primary-600;
}
&:active:not(:disabled) {
background-color: $color-primary-700;
}
}
.btn-secondary {
@extend .btn;
background-color: transparent;
color: $color-primary-500;
border: 2px solid $color-primary-500;
&:hover:not(:disabled) {
background-color: $color-primary-50;
}
}
.btn-ghost {
@extend .btn;
background-color: transparent;
color: $color-neutral-700;
&:hover:not(:disabled) {
background-color: $color-neutral-100;
}
}
.btn-danger {
@extend .btn;
background-color: $color-error-500;
color: $color-neutral-0;
&:hover:not(:disabled) {
background-color: $color-error-700;
}
}
// Tamanhos
.btn-sm {
padding: $spacing-2 $spacing-4;
font-size: $font-size-sm;
min-height: 36px;
}
.btn-lg {
padding: $spacing-4 $spacing-8;
font-size: $font-size-lg;
min-height: 52px;
}
// Com ícone
.btn-icon {
padding: $spacing-3;
&.btn-sm { padding: $spacing-2; }
&.btn-lg { padding: $spacing-4; }
}4.2 Inputs
scss
// Base do Input
.input {
display: block;
width: 100%;
padding: $spacing-3 $spacing-4;
font-family: $font-family-primary;
font-size: $font-size-base;
line-height: $line-height-normal;
color: $color-neutral-900;
background-color: $color-neutral-0;
border: 1px solid $color-neutral-300;
border-radius: $radius-md;
transition: all 0.2s ease;
// Touch target mínimo
min-height: 44px;
&::placeholder {
color: $color-neutral-500;
}
&:hover:not(:disabled) {
border-color: $color-neutral-400;
}
&:focus {
outline: none;
border-color: $color-primary-500;
box-shadow: 0 0 0 3px rgba($color-primary-500, 0.1);
}
&:disabled {
background-color: $color-neutral-100;
cursor: not-allowed;
}
&.input-error {
border-color: $color-error-500;
&:focus {
box-shadow: 0 0 0 3px rgba($color-error-500, 0.1);
}
}
&.input-success {
border-color: $color-success-500;
}
}
// Input Group
.input-group {
display: flex;
flex-direction: column;
gap: $spacing-1;
}
.input-label {
font-size: $font-size-sm;
font-weight: $font-weight-medium;
color: $color-neutral-700;
}
.input-helper {
font-size: $font-size-xs;
color: $color-neutral-600;
}
.input-error-message {
font-size: $font-size-xs;
color: $color-error-500;
}
// Input com ícone
.input-with-icon {
position: relative;
.input {
padding-left: $spacing-10;
}
.input-icon {
position: absolute;
left: $spacing-3;
top: 50%;
transform: translateY(-50%);
color: $color-neutral-500;
}
}4.3 Cards
scss
// Variáveis de bordas arredondadas
$radius-none: 0;
$radius-sm: 0.25rem; // 4px
$radius-md: 0.5rem; // 8px
$radius-lg: 0.75rem; // 12px
$radius-xl: 1rem; // 16px
$radius-2xl: 1.5rem; // 24px
$radius-full: 9999px;
// Sombras
$shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05);
$shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
$shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06);
$shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05);
$shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.1), 0 10px 10px rgba(0, 0, 0, 0.04);
// Card Base
.card {
background-color: $color-neutral-0;
border-radius: $radius-lg;
box-shadow: $shadow-sm;
overflow: hidden;
}
.card-header {
padding: $spacing-4 $spacing-4 0;
}
.card-body {
padding: $spacing-4;
}
.card-footer {
padding: 0 $spacing-4 $spacing-4;
}
// Card Variantes
.card-elevated {
box-shadow: $shadow-md;
&:hover {
box-shadow: $shadow-lg;
}
}
.card-outlined {
box-shadow: none;
border: 1px solid $color-neutral-200;
}
.card-interactive {
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
&:hover {
transform: translateY(-2px);
box-shadow: $shadow-lg;
}
&:active {
transform: translateY(0);
}
}4.4 Court Card (Específico do Domínio)
vue
<template>
<div
class="court-card"
:class="[`court-card--${sport}`, { 'court-card--available': isAvailable }]"
>
<div class="court-card__header">
<span class="court-card__sport-badge">
<SportIcon :sport="sport" />
{{ sportLabel }}
</span>
<span class="court-card__status" :class="`status--${status}`">
{{ statusLabel }}
</span>
</div>
<div class="court-card__body">
<h3 class="court-card__name">{{ name }}</h3>
<div class="court-card__features">
<span v-if="covered" class="feature">
<CoveredIcon /> Coberta
</span>
<span v-if="lighting" class="feature">
<LightingIcon /> Iluminação
</span>
<span class="feature">
<UsersIcon /> {{ maxPlayers }} jogadores
</span>
</div>
<div class="court-card__price">
<span class="price-value">R$ {{ pricePerHour }}</span>
<span class="price-unit">/hora</span>
</div>
</div>
<div class="court-card__footer">
<button
class="btn btn-primary btn-block"
:disabled="!isAvailable"
@click="$emit('book')"
>
{{ isAvailable ? 'Reservar' : 'Indisponível' }}
</button>
</div>
</div>
</template>
<style lang="scss" scoped>
.court-card {
@extend .card;
@extend .card-interactive;
&__header {
display: flex;
justify-content: space-between;
align-items: center;
padding: $spacing-4;
border-bottom: 1px solid $color-neutral-100;
}
&__sport-badge {
display: inline-flex;
align-items: center;
gap: $spacing-2;
padding: $spacing-1 $spacing-2;
font-size: $font-size-sm;
font-weight: $font-weight-medium;
border-radius: $radius-full;
}
// Cores por esporte
&--beach-tennis .court-card__sport-badge {
background-color: rgba($color-sport-beach-tennis, 0.1);
color: $color-sport-beach-tennis;
}
&--beach-volley .court-card__sport-badge {
background-color: rgba($color-sport-beach-volley, 0.1);
color: darken($color-sport-beach-volley, 15%);
}
&--futevolei .court-card__sport-badge {
background-color: rgba($color-sport-futevolei, 0.1);
color: $color-sport-futevolei;
}
&--padel .court-card__sport-badge {
background-color: rgba($color-sport-padel, 0.1);
color: $color-sport-padel;
}
&__status {
font-size: $font-size-xs;
font-weight: $font-weight-medium;
padding: $spacing-1 $spacing-2;
border-radius: $radius-full;
&.status--available {
background-color: $color-success-50;
color: $color-success-700;
}
&.status--occupied {
background-color: $color-error-50;
color: $color-error-700;
}
&.status--maintenance {
background-color: $color-warning-50;
color: $color-warning-700;
}
}
&__body {
padding: $spacing-4;
}
&__name {
@extend .text-h5;
margin-bottom: $spacing-2;
}
&__features {
display: flex;
flex-wrap: wrap;
gap: $spacing-2;
margin-bottom: $spacing-4;
.feature {
display: inline-flex;
align-items: center;
gap: $spacing-1;
font-size: $font-size-sm;
color: $color-neutral-600;
}
}
&__price {
.price-value {
font-size: $font-size-2xl;
font-weight: $font-weight-bold;
color: $color-primary-600;
}
.price-unit {
font-size: $font-size-sm;
color: $color-neutral-500;
}
}
&__footer {
padding: $spacing-4;
padding-top: 0;
}
}
.btn-block {
width: 100%;
}
</style>5. Iconografia
5.1 Biblioteca de Ícones
yaml
icones:
biblioteca: Lucide Icons
url: https://lucide.dev
categorias:
navegacao:
- home
- menu
- arrow-left
- arrow-right
- chevron-down
- x
acoes:
- plus
- edit
- trash
- search
- filter
- download
- share
esportes:
- beach_tennis: custom
- beach_volley: custom
- futevolei: custom
- padel: custom
status:
- check-circle
- x-circle
- alert-circle
- info
- clock
usuario:
- user
- users
- settings
- log-out
- bell
reserva:
- calendar
- map-pin
- credit-card
- receipt5.2 Componente de Ícone
vue
<template>
<component
:is="iconComponent"
:size="size"
:stroke-width="strokeWidth"
:class="['icon', `icon--${color}`]"
/>
</template>
<script setup>
import { computed } from 'vue';
import * as icons from 'lucide-vue-next';
const props = defineProps({
name: { type: String, required: true },
size: { type: [Number, String], default: 24 },
strokeWidth: { type: [Number, String], default: 2 },
color: { type: String, default: 'inherit' },
});
const iconComponent = computed(() => {
const pascalCase = props.name
.split('-')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join('');
return icons[pascalCase] || icons.HelpCircle;
});
</script>
<style lang="scss" scoped>
.icon {
flex-shrink: 0;
&--inherit { color: inherit; }
&--primary { color: $color-primary-500; }
&--secondary { color: $color-secondary-500; }
&--success { color: $color-success-500; }
&--error { color: $color-error-500; }
&--warning { color: $color-warning-500; }
&--muted { color: $color-neutral-500; }
}
</style>6. Dark Mode
6.1 Tokens Dark Mode
scss
// Dark Mode Tokens
:root[data-theme="dark"] {
// Cores de superfície
--color-surface-0: #{$color-neutral-900};
--color-surface-1: #{$color-neutral-800};
--color-surface-2: #{$color-neutral-700};
--color-surface-3: #{$color-neutral-600};
// Cores de texto
--color-text-primary: #{$color-neutral-50};
--color-text-secondary: #{$color-neutral-300};
--color-text-muted: #{$color-neutral-500};
// Cores de borda
--color-border: #{$color-neutral-700};
--color-border-hover: #{$color-neutral-600};
// Primárias (mais claras no dark)
--color-primary: #{$color-primary-400};
--color-primary-hover: #{$color-primary-300};
// Backgrounds
--color-bg-overlay: rgba(0, 0, 0, 0.8);
--color-bg-input: #{$color-neutral-800};
}
// Light Mode (default)
:root {
--color-surface-0: #{$color-neutral-0};
--color-surface-1: #{$color-neutral-50};
--color-surface-2: #{$color-neutral-100};
--color-surface-3: #{$color-neutral-200};
--color-text-primary: #{$color-neutral-900};
--color-text-secondary: #{$color-neutral-700};
--color-text-muted: #{$color-neutral-500};
--color-border: #{$color-neutral-200};
--color-border-hover: #{$color-neutral-300};
--color-primary: #{$color-primary-500};
--color-primary-hover: #{$color-primary-600};
--color-bg-overlay: rgba(0, 0, 0, 0.5);
--color-bg-input: #{$color-neutral-0};
}6.2 Componente Theme Toggle
vue
<template>
<button
class="theme-toggle"
:aria-label="isDark ? 'Ativar modo claro' : 'Ativar modo escuro'"
@click="toggleTheme"
>
<SunIcon v-if="isDark" />
<MoonIcon v-else />
</button>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { SunIcon, MoonIcon } from 'lucide-vue-next';
const isDark = ref(false);
onMounted(() => {
// Verifica preferência salva ou do sistema
const saved = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
isDark.value = saved ? saved === 'dark' : prefersDark;
applyTheme();
});
function toggleTheme() {
isDark.value = !isDark.value;
localStorage.setItem('theme', isDark.value ? 'dark' : 'light');
applyTheme();
}
function applyTheme() {
document.documentElement.dataset.theme = isDark.value ? 'dark' : 'light';
}
</script>7. Animações e Transições
7.1 Tokens de Animação
scss
// Duração
$duration-instant: 50ms;
$duration-fast: 100ms;
$duration-normal: 200ms;
$duration-slow: 300ms;
$duration-slower: 500ms;
// Easing
$ease-default: cubic-bezier(0.4, 0, 0.2, 1);
$ease-in: cubic-bezier(0.4, 0, 1, 1);
$ease-out: cubic-bezier(0, 0, 0.2, 1);
$ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
$ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
// Transições pré-definidas
$transition-fast: all $duration-fast $ease-default;
$transition-normal: all $duration-normal $ease-default;
$transition-slow: all $duration-slow $ease-default;7.2 Classes de Animação
scss
// Fade
.fade-enter-active,
.fade-leave-active {
transition: opacity $duration-normal $ease-default;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
// Slide Up
.slide-up-enter-active,
.slide-up-leave-active {
transition: all $duration-normal $ease-out;
}
.slide-up-enter-from,
.slide-up-leave-to {
opacity: 0;
transform: translateY(20px);
}
// Scale
.scale-enter-active,
.scale-leave-active {
transition: all $duration-fast $ease-bounce;
}
.scale-enter-from,
.scale-leave-to {
opacity: 0;
transform: scale(0.95);
}
// Skeleton Loading
@keyframes skeleton-loading {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
.skeleton {
background: linear-gradient(
90deg,
var(--color-surface-1) 25%,
var(--color-surface-2) 50%,
var(--color-surface-1) 75%
);
background-size: 200% 100%;
animation: skeleton-loading 1.5s ease-in-out infinite;
border-radius: $radius-sm;
}8. Acessibilidade
8.1 Checklist WCAG 2.1 AA
yaml
acessibilidade:
perceivable:
contraste:
texto_normal: 4.5:1 mínimo
texto_grande: 3:1 mínimo
elementos_ui: 3:1 mínimo
texto:
redimensionamento: até 200% sem perda
espaçamento: configurável
imagens:
alt_text: obrigatório
decorativas: alt=""
operable:
teclado:
navegacao: Tab, Shift+Tab
ativacao: Enter, Space
fechar: Escape
focus_visible: sempre visível
touch_targets:
tamanho_minimo: 44x44px
espacamento: 8px entre elementos
understandable:
linguagem:
html_lang: pt-BR
abreviacoes: expandidas
erros:
identificacao: clara e próxima
sugestao: quando possível
robust:
semantica:
headings: hierárquicos
landmarks: header, main, nav, footer
aria: apenas quando necessário8.2 Componente Acessível
vue
<template>
<div
class="alert"
:class="`alert--${type}`"
role="alert"
:aria-live="type === 'error' ? 'assertive' : 'polite'"
>
<div class="alert__icon" aria-hidden="true">
<AlertCircleIcon v-if="type === 'error'" />
<CheckCircleIcon v-else-if="type === 'success'" />
<InfoIcon v-else />
</div>
<div class="alert__content">
<h4 v-if="title" class="alert__title">{{ title }}</h4>
<p class="alert__message">{{ message }}</p>
</div>
<button
v-if="dismissible"
class="alert__close"
type="button"
aria-label="Fechar alerta"
@click="$emit('dismiss')"
>
<XIcon aria-hidden="true" />
</button>
</div>
</template>9. Recursos e Ferramentas
9.1 Design Tokens Export
json
{
"color": {
"primary": {
"50": { "value": "#E3F2FD" },
"500": { "value": "#2196F3" },
"900": { "value": "#0D47A1" }
}
},
"spacing": {
"1": { "value": "0.25rem" },
"2": { "value": "0.5rem" },
"4": { "value": "1rem" }
},
"typography": {
"fontFamily": {
"primary": { "value": "Inter, sans-serif" }
}
}
}9.2 Figma/Design Handoff
yaml
figma:
library: Sport Tech Club Design System
url: figma.com/file/xxx
estrutura:
- Foundations
- Colors
- Typography
- Spacing
- Icons
- Components
- Buttons
- Inputs
- Cards
- Navigation
- Patterns
- Forms
- Lists
- Modals
- Templates
- Login
- Dashboard
- BookingEste Design System serve como fonte única de verdade para todas as decisões de design e implementação de UI no Sport Tech Club.