design-systems: add 74 brand DESIGN.md files (VoltAgent/awesome-design-md)
- 74 brands: airbnb, stripe, apple, figma, linear, vercel, etc. - 147 files: DESIGN.md + README.md per brand (~2.1 MB) - Each DESIGN.md contains structured brand analysis (colors, typography, components) - Updated 00-overview.md with new design-systems directory
This commit is contained in:
1 parent
e3738f2b3e
commit
76c4c5b4fe
233 files changed
+54886
-1
No files matched your search
@@ -0,0 +1,151 @@
|
||||
---
|
||||
name: motion/magnetic-button
|
||||
title: Magnetic Button Effect
|
||||
description: Buttons that follow cursor within radius. Creates premium tactile feel.
|
||||
tags: [motion, magnetic, button, micro-interaction, premium]
|
||||
source: raycast.com, linear.app, brad.co, amppz.com
|
||||
---
|
||||
|
||||
# Magnetic Button Effect
|
||||
|
||||
## Что это
|
||||
Кнопки и элементы, которые притягиваются к курсору мыши в пределах радиуса. Создаёт ощущение тактильности и премиальности.
|
||||
|
||||
## Параметры
|
||||
|
||||
| Параметр | Значение |
|
||||
|----------|----------|
|
||||
| **Radius** | 60–100px |
|
||||
| **Strength** | 0.1–0.3 |
|
||||
| **Easing** | `cubic-bezier(0.25, 0.1, 0.25, 1)` |
|
||||
| **Duration** | 0.3s |
|
||||
|
||||
## Реализация
|
||||
|
||||
```html
|
||||
<button class="magnetic-btn">Hover me</button>
|
||||
```
|
||||
|
||||
```css
|
||||
.magnetic-btn {
|
||||
padding: 16px 32px;
|
||||
background: var(--color-accent);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
transition: transform 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
|
||||
}
|
||||
```
|
||||
|
||||
```javascript
|
||||
class MagneticButton {
|
||||
constructor(element, strength = 0.2, radius = 80) {
|
||||
this.el = element;
|
||||
this.strength = strength;
|
||||
this.radius = radius;
|
||||
this.rect = element.getBoundingClientRect();
|
||||
this.isHovering = false;
|
||||
this.animationId = null;
|
||||
this.pos = { x: 0, y: 0 };
|
||||
this.target = { x: 0, y: 0 };
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.el.addEventListener('mouseenter', (e) => {
|
||||
this.isHovering = true;
|
||||
this.rect = this.el.getBoundingClientRect();
|
||||
});
|
||||
|
||||
this.el.addEventListener('mouseleave', () => {
|
||||
this.isHovering = false;
|
||||
this.target = { x: 0, y: 0 };
|
||||
this.animate();
|
||||
});
|
||||
|
||||
this.el.addEventListener('mousemove', (e) => {
|
||||
const x = e.clientX - this.rect.left - this.rect.width / 2;
|
||||
const y = e.clientY - this.rect.top - this.rect.height / 2;
|
||||
this.target = { x: x * this.strength, y: y * this.strength };
|
||||
});
|
||||
|
||||
this.animate();
|
||||
}
|
||||
|
||||
animate() {
|
||||
if (this.isHovering) {
|
||||
this.pos.x += (this.target.x - this.pos.x) * 0.1;
|
||||
this.pos.y += (this.target.y - this.pos.y) * 0.1;
|
||||
} else {
|
||||
this.pos.x *= 0.9;
|
||||
this.pos.y *= 0.9;
|
||||
}
|
||||
|
||||
this.el.style.transform = `translate(${this.pos.x}px, ${this.pos.y}px)`;
|
||||
this.animationId = requestAnimationFrame(() => this.animate());
|
||||
}
|
||||
|
||||
destroy() {
|
||||
cancelAnimationFrame(this.animationId);
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
document.querySelectorAll('.magnetic-btn').forEach(el => {
|
||||
new MagneticButton(el);
|
||||
});
|
||||
```
|
||||
|
||||
## Варианты силы притяжения
|
||||
|
||||
```javascript
|
||||
// Слабое (для текста)
|
||||
new MagneticButton(el, 0.1, 60);
|
||||
|
||||
// Среднее (для кнопок)
|
||||
new MagneticButton(el, 0.2, 80);
|
||||
|
||||
// Сильное (для крупных элементов)
|
||||
new MagneticButton(el, 0.3, 100);
|
||||
```
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
| ❌ Плохо | ✅ Хорошо |
|
||||
|----------|-----------|
|
||||
| `strength: 0.5` — слишком резко | `strength: 0.1–0.3` |
|
||||
| Без `mouseleave` сброса | Всегда сбрасывать в 0,0 |
|
||||
| Без `requestAnimationFrame` | Использовать RAF |
|
||||
| На мобильных без mouse | Проверять `matchMedia('(pointer: fine)')` |
|
||||
|
||||
## Mobile Fallback
|
||||
|
||||
```javascript
|
||||
if (window.matchMedia('(pointer: fine)').matches) {
|
||||
document.querySelectorAll('.magnetic-btn').forEach(el => {
|
||||
new MagneticButton(el);
|
||||
});
|
||||
}
|
||||
// На мобильных — просто hover-эффект
|
||||
```
|
||||
|
||||
## CV Service Validation
|
||||
|
||||
```bash
|
||||
# Проверить micro-interactions
|
||||
curl -s -X POST http://localhost:8001/design/analyze \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"image_base64": "...", "full_analysis": false}' | python3 -c "
|
||||
import sys, json
|
||||
d = json.load(sys.stdin)
|
||||
motion = d['dimensions'].get('motion_quality', {})
|
||||
print(f\"Motion Quality: {motion.get('score', 'N/A')}/10\")
|
||||
"
|
||||
```
|
||||
|
||||
Ожидается: `motion_quality` > 6.
|
||||
Reference in new issue
Block a user