PlayfulButton.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <template>
  2. <button
  3. class="playful-btn"
  4. :class="['playful-btn--' + variant, 'playful-btn--' + size, {
  5. 'playful-btn--disabled': disabled,
  6. 'playful-btn--clay': variant === 'clay'
  7. }]"
  8. :disabled="disabled"
  9. @click="emitClick"
  10. :aria-label="ariaLabel"
  11. >
  12. <slot></slot>
  13. </button>
  14. </template>
  15. <script>
  16. export default {
  17. name: 'PlayfulButton',
  18. props: {
  19. variant: { type: String, default: 'primary' },
  20. // 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'clay' | 'outline'
  21. size: { type: String, default: 'md' },
  22. // 'xs' | 'sm' | 'md' | 'lg'
  23. disabled: { type: Boolean, default: false },
  24. ariaLabel: { type: String, default: '' },
  25. block: { type: Boolean, default: false }
  26. },
  27. methods: {
  28. emitClick(e) {
  29. if (!this.disabled) this.$emit('click', e)
  30. }
  31. }
  32. }
  33. </script>
  34. <style scoped>
  35. .playful-btn {
  36. display: inline-flex;
  37. align-items: center;
  38. justify-content: center;
  39. border: none;
  40. border-radius: 999px;
  41. font-weight: 700;
  42. transition: transform .15s ease, box-shadow .15s ease, opacity .2s ease;
  43. line-height: 1.4;
  44. }
  45. .playful-btn--block {
  46. display: flex;
  47. width: 100%;
  48. }
  49. /* ---- Primary ---- */
  50. .playful-btn--primary {
  51. background: var(--color-primary, #F97316);
  52. color: #fff;
  53. box-shadow: 0 2px 8px rgba(249, 115, 22, 0.3);
  54. }
  55. /* ---- Secondary ---- */
  56. .playful-btn--secondary {
  57. background: var(--surface, #ffffff);
  58. color: var(--text, #3D2E1E);
  59. border: 2rpx solid var(--border, #FED7AA);
  60. box-shadow: 0 2px 6px rgba(249, 115, 22, 0.06);
  61. }
  62. /* ---- Success ---- */
  63. .playful-btn--success {
  64. background: var(--color-success, #22C55E);
  65. color: #fff;
  66. box-shadow: 0 2px 8px rgba(34, 197, 94, 0.3);
  67. }
  68. /* ---- Warning ---- */
  69. .playful-btn--warning {
  70. background: var(--color-warning, #F59E0B);
  71. color: #fff;
  72. box-shadow: 0 2px 8px rgba(245, 158, 11, 0.3);
  73. }
  74. /* ---- Error ---- */
  75. .playful-btn--error {
  76. background: var(--color-error, #EF4444);
  77. color: #fff;
  78. box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3);
  79. }
  80. /* ---- Clay (孩子端玩具风) ---- */
  81. .playful-btn--clay {
  82. background: linear-gradient(145deg, #FFB347, var(--color-primary, #F97316));
  83. color: #fff;
  84. border: 3rpx solid #FED7AA;
  85. box-shadow:
  86. inset -2px -2px 6px rgba(255, 255, 255, 0.3),
  87. 4px 4px 12px rgba(249, 115, 22, 0.25);
  88. }
  89. /* ---- Outline ---- */
  90. .playful-btn--outline {
  91. background: transparent;
  92. color: var(--color-primary, #F97316);
  93. border: 2rpx solid var(--color-primary, #F97316);
  94. }
  95. /* ---- Sizes ---- */
  96. .playful-btn--xs { font-size: 22rpx; padding: 8rpx 20rpx; }
  97. .playful-btn--sm { font-size: 24rpx; padding: 12rpx 28rpx; }
  98. .playful-btn--md { font-size: 28rpx; padding: 16rpx 36rpx; }
  99. .playful-btn--lg { font-size: 32rpx; padding: 20rpx 48rpx; min-height: 88rpx; }
  100. /* ---- States ---- */
  101. .playful-btn:active:not(:disabled) {
  102. transform: scale(0.97);
  103. }
  104. .playful-btn--clay:active:not(:disabled) {
  105. transform: scale(0.95);
  106. box-shadow:
  107. inset 0 0 8px rgba(0,0,0,0.1),
  108. 2px 2px 6px rgba(249, 115, 22, 0.15);
  109. }
  110. .playful-btn--disabled,
  111. .playful-btn:disabled {
  112. opacity: 0.5;
  113. cursor: not-allowed;
  114. }
  115. .playful-btn:focus {
  116. outline: 2px solid rgba(249, 115, 22, 0.4);
  117. outline-offset: 2px;
  118. }
  119. </style>