PlayfulButton.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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: opacity .2s ease, box-shadow .15s 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, #5B9BD5);
  52. color: #fff;
  53. box-shadow: 0 2px 8px rgba(91, 155, 213, 0.3);
  54. }
  55. /* ---- Secondary ---- */
  56. .playful-btn--secondary {
  57. background: var(--surface, #ffffff);
  58. color: var(--text, #1E293B);
  59. border: 2rpx solid var(--border, #CBD5E1);
  60. box-shadow: 0 2px 6px rgba(91, 155, 213, 0.08);
  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: var(--color-primary, #5B9BD5);
  83. color: #fff;
  84. border: 2rpx solid var(--border, #CBD5E1);
  85. box-shadow: 0 2px 8px rgba(91, 155, 213, 0.15);
  86. }
  87. /* ---- Outline ---- */
  88. .playful-btn--outline {
  89. background: transparent;
  90. color: var(--color-primary, #5B9BD5);
  91. border: 2rpx solid var(--color-primary, #5B9BD5);
  92. }
  93. /* ---- Sizes ---- */
  94. .playful-btn--xs { font-size: 22rpx; padding: 8rpx 20rpx; }
  95. .playful-btn--sm { font-size: 24rpx; padding: 12rpx 28rpx; }
  96. .playful-btn--md { font-size: 28rpx; padding: 16rpx 36rpx; }
  97. .playful-btn--lg { font-size: 32rpx; padding: 20rpx 48rpx; min-height: 88rpx; }
  98. /* ---- States ---- */
  99. .playful-btn:active:not(:disabled) {
  100. opacity: 0.85;
  101. }
  102. .playful-btn--clay:active:not(:disabled) {
  103. opacity: 0.85;
  104. }
  105. .playful-btn--disabled,
  106. .playful-btn:disabled {
  107. opacity: 0.5;
  108. cursor: not-allowed;
  109. }
  110. .playful-btn:focus {
  111. outline: 2px solid rgba(91, 155, 213, 0.4);
  112. outline-offset: 2px;
  113. }
  114. </style>