PlayfulButton.vue 3.1 KB

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