<script setup lang="ts">
type PageStateType = 'loading' | 'empty' | 'error' | 'unavailable'

interface Props {
  state: PageStateType
  title: string
  description?: string
  actionLabel?: string
}

withDefaults(defineProps<Props>(), {
  description: '',
  actionLabel: '',
})

const emit = defineEmits<{
  action: []
}>()
</script>

<template>
  <view
    class="page-state"
    :class="`page-state--${state}`"
    :aria-live="state === 'loading' ? 'polite' : 'assertive'"
  >
    <view class="page-state__visual" aria-hidden="true">
      <view v-if="state === 'loading'" class="page-state__spinner" />
      <text v-else-if="state === 'error'" class="page-state__symbol">!</text>
      <text v-else-if="state === 'unavailable'" class="page-state__symbol">i</text>
      <view v-else class="page-state__empty-icon">
        <view class="page-state__empty-line" />
      </view>
    </view>

    <text class="page-state__title">{{ title }}</text>
    <text v-if="description" class="page-state__description">{{ description }}</text>

    <button
      v-if="actionLabel && state !== 'loading'"
      class="page-state__action"
      hover-class="page-state__action--hover"
      @click="emit('action')"
    >
      {{ actionLabel }}
    </button>
  </view>
</template>

<style scoped lang="scss">
.page-state {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 480rpx;
  padding: 64rpx 48rpx;
  color: #18201d;
  text-align: center;
}

.page-state__visual {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 104rpx;
  height: 104rpx;
  margin-bottom: 28rpx;
  color: #167a5b;
  background: #e8f4ee;
  border-radius: 50%;
}

.page-state__spinner {
  width: 48rpx;
  height: 48rpx;
  border: 6rpx solid #bcd8cc;
  border-top-color: #167a5b;
  border-radius: 50%;
  animation: page-state-spin 0.8s linear infinite;
}

.page-state__symbol {
  font-size: 50rpx;
  font-weight: 700;
  line-height: 72rpx;
}

.page-state__empty-icon {
  position: relative;
  box-sizing: border-box;
  width: 54rpx;
  height: 42rpx;
  border: 4rpx solid currentcolor;
  border-radius: 8rpx;
}

.page-state__empty-line {
  position: absolute;
  top: 12rpx;
  left: 11rpx;
  width: 24rpx;
  height: 4rpx;
  background: currentcolor;
  border-radius: 2rpx;
}

.page-state--error .page-state__visual {
  color: #b84235;
  background: #fff0ee;
}

.page-state--unavailable .page-state__visual {
  color: #68756f;
  background: #f0f2f1;
}

.page-state__title {
  font-size: 32rpx;
  font-weight: 700;
  line-height: 46rpx;
  color: #18201d;
}

.page-state__description {
  max-width: 560rpx;
  margin-top: 12rpx;
  font-size: 26rpx;
  line-height: 40rpx;
  color: #66736d;
}

.page-state__action {
  width: auto;
  min-width: 216rpx;
  height: 72rpx;
  padding: 0 36rpx;
  margin: 32rpx 0 0;
  font-size: 26rpx;
  font-weight: 600;
  line-height: 72rpx;
  color: #fff;
  background: #167a5b;
  border: 0;
  border-radius: 36rpx;
}

.page-state__action::after {
  border: 0;
}

.page-state__action--hover {
  background: #0e6247;
}

@keyframes page-state-spin {
  to {
    transform: rotate(360deg);
  }
}
</style>
