<template>
  <div
    v-loading.lock="loading"
    element-loading-background="rgba(0, 0, 0, 0.8)"
    class="l-flex--col c-designer"
    @contextmenu.prevent
  >
    <audio
      ref="audio"
      :src="bgmUrl"
      :muted.prop="muted"
      autoplay
      @ended="onAudioEnded"
      @error="onAudioError"
    />
    <div class="l-flex__none l-flex--row c-designer__header">
      <i
        class="c-designer__shortcut el-icon-arrow-left u-bold u-pointer"
        @click="onBack"
      />
      <span class="c-designer__name u-bold u-ellipsis">{{ program.name }}</span>
      <span class="c-sibling-item">{{ program.resolutionRatio }}</span>
      <div
        v-if="hasNext"
        class="c-sibling-item c-designer__shortcut u-pointer"
        @click="switchBgm"
      >
        <i class="o-next" />
      </div>
      <div
        v-if="hasAudio"
        class="c-sibling-item c-designer__shortcut u-pointer"
        @click="toggleMute"
      >
        <volume :muted="muted" />
      </div>
      <div class="l-flex__fill c-sibling-item" />
      <button
        v-if="hasWidgets"
        class="c-sibling-item o-button mini"
        @click="onClear"
      >
        <i class="o-button__icon el-icon-delete" />
        清空
      </button>
      <button
        class="c-sibling-item o-button mini"
        @click="onSave"
      >
        <i class="o-button__icon iconfont iconsave" />
        保存
      </button>
    </div>
    <div class="l-flex__fill l-flex">
      <div class="c-designer__side left c-side">
        <div class="c-side__tool">
          <div class="c-side__item">
            组件
          </div>
        </div>
        <el-scrollbar
          class="c-side__scrollbar"
          native
        >
          <div class="c-side__content mini">
            <div
              v-for="(widget, index) in layers"
              ref="widgetElements"
              :key="widget.id"
              class="o-layer"
              :class="{ active: widget.id === selectedWidgetId }"
              @mousedown="onLayerClick($event, index)"
            >
              <widget-shortcut
                class="dark"
                :widget="widget"
                editable
              />
            </div>
            <div
              v-if="node"
              ref="rootElement"
              key="root"
              class="o-layer"
              :class="{ active: !selectedWidgetId }"
              @click="onRootClick"
            >
              <widget-shortcut
                class="dark"
                :widget="node"
                :custom-style="backgroundStyles"
                source-key="bgm"
                background
                editable
              />
            </div>
          </div>
        </el-scrollbar>
      </div>
      <div class="c-designer__main">
        <div class="l-flex--row c-designer__tool">
          <div class="o-scale-slider">
            <div class="l-flex--row o-scale-slider__wrapper">
              <i
                class="el-icon-zoom-out u-pointer"
                @click="scaleDown"
              />
              <el-slider
                v-model="scale"
                class="o-scale-slider__slider"
                :min="minScale"
                :max="maxScale"
              />
              <i
                class="el-icon-zoom-in u-pointer"
                @click="scaleUp"
              />
            </div>
          </div>
          <div
            class="l-flex__none l-flex--row"
            @dragstart="widgetOnDragStart"
            @dragend="widgetOnDragEnd"
          >
            <div
              v-for="cfg in widgetConfigs"
              :key="cfg.key"
              :data-type="cfg.type"
              class="o-widget-cfg"
              draggable
            >
              <span class="o-widget-cfg__icon">
                <svg-icon :icon-class="cfg.icon" />
              </span>
              <span class="o-widget-cfg__text">{{ cfg.label }}</span>
            </div>
          </div>
        </div>
        <div
          ref="wrapper"
          class="c-designer__content"
          @mousedown="onRootClick"
        >
          <div
            class="c-designer__wrapper"
            :style="wrapperStyles"
          >
            <div
              ref="canvas"
              class="c-designer__canvas"
              :style="[transformStyles, styles]"
              @dragover.prevent
              @drop.prevent="widgetOnDrop"
            >
              <div
                class="c-designer__background has-bg"
                :style="backgroundStyles"
              />
              <div
                v-show="grid"
                class="c-designer__grid"
              />
              <widget
                v-for="(item, index) in widgets"
                :key="item.id"
                ref="widgets"
                :scale="100 / scale"
                :node="item"
                :root="node"
                @focus="onWidgetFocus(index)"
                @will-move="onWidgetWillMove"
                @blur="onWidgetBlur"
                @menu="onWidgetMenu($event, index)"
                @dblclick.native="onWidgetDblclick"
              />
            </div>
          </div>
        </div>
      </div>
      <div class="c-designer__side right c-side">
        <div class="c-side__tool">
          <div
            v-for="(tab, index) in dynamicOptions"
            :key="index"
            class="c-side__item u-pointer"
            :class="{ active: optionIndex === index }"
            @click="optionIndex = index"
          >
            {{ tab.label }}
          </div>
        </div>
        <div
          v-for="(tab, index) in dynamicOptions"
          v-show="optionIndex === index"
          :key="index"
          class="c-side__scrollbar c-side__content u-overflow-y--auto"
          :class="{ active: optionIndex === index }"
        >
          <dynamic-item
            v-for="item in tab.list"
            :key="item.key"
            :root="node"
            :node="widget"
            :attr="item"
            @choose="onEditData"
          />
        </div>
      </div>
    </div>
    <content-menu
      :visible.sync="visibleContentMenu"
      :style-obj="styleObj"
      @delete="deleteLayer"
      @copy="copyLayer"
      @top="topLayer"
      @low="lowLayer"
      @up="upLayer"
      @down="downLayer"
    />
    <el-dialog
      :visible.sync="showAssets"
      :title="assetDialogType"
      custom-class="c-dialog large"
      :close-on-click-modal="false"
      :before-close="onCloseAssetsDialog"
    >
      <draggable
        v-if="showAssets"
        v-model="sources"
        class="l-grid--info mini"
        :class="{ dragging }"
        animation="300"
        @start="onSourceDragStart"
        @end="onSourceDragEnd"
      >
        <card
          v-for="(source, index) in sources"
          :key="index"
          :source="source"
          @click="onView"
        >
          <div
            v-if="needTypeTag"
            class="c-card__tag"
          >{{ source.tag }}</div>
          <i
            class="c-card__icon el-icon-delete o-icon--active"
            @mousedown.stop
            @pointerdown.stop
            @click.stop="onDelAsset(index)"
          />
        </card>
      </draggable>
      <template #footer>
        <button
          class="o-button"
          @click="onAddAssets"
        >
          新增
        </button>
        <button
          class="o-button"
          @click="onSaveAssets"
        >
          确定
        </button>
        <button
          class="o-button cancel"
          @click="onCloseAssetsDialog"
        >
          取消
        </button>
      </template>
    </el-dialog>
    <el-dialog
      :visible.sync="showServerAssets"
      :title="assetDialogTitle"
      custom-class="c-dialog"
      append-to-body
    >
      <template v-if="showServerAssets">
        <grid-table :schema="assetSchema">
          <grid-table-item v-slot="item">
            <card
              :source="item"
              @dblclick="onChoosenAsset"
            />
          </grid-table-item>
        </grid-table>
      </template>
    </el-dialog>
    <confirm-dialog
      ref="assetsDialog"
      :title="assetDialogTitle"
      size
      append-to-body
      @confirm="onChoosenAssets"
      @cancel="showServerAssetsMulti = false"
    >
      <template v-if="showServerAssetsMulti">
        <grid-table
          ref="gridTable"
          :schema="assetSchema"
        >
          <grid-table-item v-slot="item">
            <card
              :source="item"
              @click="onToggleGrid"
            >
              <el-checkbox
                v-model="item.selected"
                class="c-card__checkbox"
              />
              <i
                class="c-card__type el-icon-video-play o-icon--active u-pointer"
                @click.stop="onView(item)"
              />
            </card>
          </grid-table-item>
        </grid-table>
      </template>
    </confirm-dialog>
    <preview-dialog
      ref="previewDialog"
      @close="onClosePreview"
    />
  </div>
</template>

<script>
import domToImage from 'dom-to-image'
import { updateProgram } from '@/api/program'
import {
  getAssets,
  getThumbnailUrl
} from '@/api/asset'
import {
  State,
  AssetType
} from '@/constant'
import {
  widgets,
  normalize,
  getOptions,
  copy,
  fix,
  getDuration,
  toJSON
} from './core/utils'
import mixin from './mixin'
import Draggable from 'vuedraggable'
import Widget from './core/widget/Widget.vue'
import ContentMenu from './components/ContentMenu.vue'
import DynamicItem from './components/DynamicItem.vue'

export default {
  name: 'BigScreenDesigner',
  components: {
    Draggable,
    Widget,
    ContentMenu,
    DynamicItem
  },
  mixins: [mixin],
  data () {
    return {
      loading: false,
      snapping: false,
      padding: 16,
      optionIndex: 0,
      widgetConfigs: widgets,
      grid: false,
      visibleContentMenu: false,
      styleObj: null,
      widgetAttr: null,
      showAssets: false,
      sources: null,
      dragging: false,
      dragScale: false,
      showServerAssets: false,
      showServerAssetsMulti: false
    }
  },
  computed: {
    hasWidgets () {
      return this.widgets.length > 0
    },
    dynamicOptions () {
      if (this.widget) {
        return getOptions(this.widget.type)
      }
      return []
    },
    layers () {
      return this.widgets.slice().reverse()
    },
    assetType () {
      if (this.widgetAttr?.type === 'data') {
        return this.widgetAttr.options.type
      }
      return []
    },
    assetSchema () {
      return {
        condition: { originalName: '', type: this.assetType[0] },
        list: this.getAssets,
        transform: this.transformAsset,
        filters: (
          this.assetType.length > 1
            ? [
              {
                key: 'type', type: 'select', options: this.assetType.map(type => {
                  return {
                    value: type,
                    label: this.getAssetType(type)
                  }
                })
              }
            ]
            : []
        ).concat([
          { key: 'originalName', type: 'search', placeholder: '媒资名称' }
        ])
      }
    },
    needTypeTag () {
      return this.assetType.length > 1
    },
    assetDialogType () {
      return this.assetType.length
        ? this.assetType.length > 1
          ? '媒资'
          : this.getAssetType(this.assetType[0])
        : ''
    },
    assetDialogTitle () {
      return `请选择${this.assetDialogType}`
    },
    selectedWidgetId () {
      return this.widget?.id
    },
    wrapperStyles () {
      return this.node
        ? {
          width: `${this.node.width * this.scale / 100}px`,
          height: `${this.node.height * this.scale / 100}px`
        }
        : null
    }
  },
  watch: {
    selectedWidgetIndex (val, old) {
      if (old > -1) {
        const id = this.widgets[old]?.id
        id && this.$refs.widgets[this.$refs.widgets.findIndex(w => w.node.id === id)]?.$refs.draggable.setActive(false)
      }
      if (val > -1) {
        const id = this.widgets[val]?.id
        id && this.$refs.widgets[this.$refs.widgets.findIndex(w => w.node.id === id)]?.$refs.draggable.setActive(true)
      }
      this.optionIndex = 0
    },
    widget () {
      this.node && setTimeout(() => {
        if (this.selectedWidgetIndex === -1) {
          this.$refs.rootElement.scrollIntoView({ behavior: 'smooth', block: 'start' })
        } else {
          this.$refs.widgetElements.find(element => element.classList.contains('active')).scrollIntoView({ behavior: 'smooth', block: 'start' })
        }
      })
    }
  },
  methods: {
    getAssetType (type) {
      switch (type) {
        case AssetType.IMAGE:
          return '图片'
        case AssetType.VIDEO:
          return '视频'
        case AssetType.AUDIO:
          return '音频'
        default:
          return '媒资'
      }
    },
    onClear () {
      this.$confirm(
        '清空后所有数据将丢失',
        '清空画布',
        { type: 'warning' }
      ).then(() => {
        this.selectedWidgetIndex = -1
        const { width, height } = this.node
        this.initCanvas({ width, height })
      })
    },
    widgetOnDragStart (evt) {
      evt.dataTransfer.setData('type', evt.target.dataset.type)
      this.dragging = true
    },
    widgetOnDragEnd () {
      this.dragging = false
    },
    widgetOnDrop (evt) {
      const type = evt.dataTransfer.getData('type')
      if (type) {
        let { offsetX: left, offsetY: top } = evt
        const node = normalize({ type })
        top -= node.height / 2
        if (top < 0) {
          top = 0
        }
        left -= node.width / 2
        if (left < 0) {
          left = 0
        }
        node.top = top
        node.left = left
        this.node.widgets.push(node)
        this.$nextTick(() => {
          this.selectedWidgetIndex = this.widgets.length - 1
        })
      }
    },
    onWidgetFocus (index) {
      this.selectedWidgetIndex = index
      this.visibleContentMenu = false
    },
    onWidgetWillMove () {
      this.grid = true
    },
    onWidgetBlur () {
      this.grid = false
    },
    onWidgetMenu (evt, index) {
      this.selectedWidgetIndex = index
      this.onRightClick(evt)
    },
    onWidgetDblclick () {
      const attr = this.dynamicOptions[0]?.list.find(({ type }) => type === 'data')
      if (attr) {
        this.onEditData(attr)
      }
    },
    onLayerClick (evt, index) {
      this.selectedWidgetIndex = this.widgets.length - 1 - index
      this.onRightClick(evt)
    },
    onRootClick () {
      this.selectedWidgetIndex = -1
    },
    onRightClick (evt) {
      const { button, clientY: top, clientX: left } = evt
      if (button !== 2) {
        return
      }
      evt.stopPropagation()
      if (top || left) {
        this.styleObj = {
          display: 'block',
          top: `${top}px`,
          left: `${left}px`
        }
      }
      this.visibleContentMenu = true
    },
    // 删除
    deleteLayer () {
      this.widgets.splice(this.selectedWidgetIndex, 1)
      this.$nextTick(() => {
        this.selectedWidgetIndex = -1
      })
    },
    // 复制
    copyLayer () {
      this.widgets.splice(this.selectedWidgetIndex + 1, 0, copy(this.widget))
      this.$message({
        type: 'success',
        message: '复制成功，已为您选择复制后的组件'
      })
      this.$nextTick(() => {
        this.selectedWidgetIndex += 1
      })
    },
    // 置顶
    topLayer () {
      if (this.selectedWidgetIndex < this.widgets.length - 1) {
        this.widgets.push(this.widgets.splice(
          this.selectedWidgetIndex,
          1
        )[0])
        this.$nextTick(() => {
          this.selectedWidgetIndex = this.widgets.length - 1
        })
      }
    },
    // 置底
    lowLayer () {
      if (this.selectedWidgetIndex > 0) {
        this.widgets.unshift(this.widgets.splice(
          this.selectedWidgetIndex,
          1
        )[0])
        this.$nextTick(() => {
          this.selectedWidgetIndex = 0
        })
      }
    },
    // 上移一层
    upLayer () {
      if (this.selectedWidgetIndex < this.widgets.length - 1) {
        this.widgets[this.selectedWidgetIndex] = this.widgets.splice(
          this.selectedWidgetIndex + 1,
          1,
          this.widgets[this.selectedWidgetIndex]
        )[0]
        this.$nextTick(() => {
          this.selectedWidgetIndex += 1
        })
      }
    },
    // 下移一层
    downLayer () {
      if (this.selectedWidgetIndex > 0) {
        this.widgets[this.selectedWidgetIndex] = this.widgets.splice(
          this.selectedWidgetIndex - 1,
          1,
          this.widgets[this.selectedWidgetIndex]
        )[0]
        this.$nextTick(() => {
          this.selectedWidgetIndex -= 1
        })
      }
    },
    changeAttr (value) {
      const { key, options } = this.widgetAttr
      this.widget[key] = value
      if (options) {
        const { callback } = options
        callback && callback.call(this.widget, this.node)
      }
    },
    onEditData (attr) {
      this.widgetAttr = attr
      if (attr.options && attr.options.solo) {
        this.showServerAssets = true
      } else {
        this.sources = this.widget[attr.key].map(this.transformDataToSource)
        this.showAssets = true
      }
    },
    onCloseAssetsDialog () {
      this.$choosenAssets = []
      this.widgetAttr = null
      this.showAssets = false
      this.showServerAssets = false
    },
    getAssets (params) {
      this.$choosenAssets = []
      return getAssets({
        status: State.RESOLVED,
        ...params
      })
    },
    transformAsset ({ type, originalName, keyName, thumbnail, duration, size, md5 }) {
      const asset = {
        selected: false,
        type,
        name: originalName,
        keyName,
        size,
        md5,
        thumbnail
      }
      if (type === AssetType.IMAGE) {
        asset.duration = this.widget.interval
      } else {
        asset.duration = Number(duration) || 0
      }
      if (thumbnail) {
        asset.thumbnailUrl = getThumbnailUrl(thumbnail)
      } else {
        asset.icon = `${type === AssetType.VIDEO ? 'video' : 'audio'}-bg`
      }
      return this.addTag(asset)
    },
    transformToData ({ type, name, keyName, thumbnail, duration, size, md5 }) {
      const source = {
        type,
        name,
        keyName,
        size,
        md5,
        duration
      }
      if (type !== AssetType.IMAGE && thumbnail) {
        source.thumbnail = thumbnail
      }
      return source
    },
    transformDataToSource (data) {
      const source = { ...data }
      if (data.thumbnail) {
        source.thumbnailUrl = getThumbnailUrl(data.thumbnail)
      } else if (source.type === AssetType.IMAGE) {
        source.thumbnailUrl = getThumbnailUrl(data.keyName)
      } else {
        switch (source.type) {
          case AssetType.VIDEO:
            source.icon = 'video-bg'
            break
          case AssetType.AUDIO:
            source.icon = 'audio-bg'
            break
          default:
            break
        }
      }
      return this.addTag(source)
    },
    addTag (data) {
      if (this.needTypeTag) {
        data.tag = this.getAssetType(data.type)
      }
      return data
    },
    onChoosenAsset (asset) {
      this.changeAttr([this.transformToData(asset)])
      this.onCloseAssetsDialog()
    },
    onAddAssets () {
      this.showServerAssetsMulti = true
      this.$refs.assetsDialog.show()
    },
    onToggleGrid (asset) {
      asset.selected = !asset.selected
    },
    onChoosenAssets (done) {
      const assets = this.$refs.gridTable.getData().filter(({ selected }) => selected)
      if (assets.length) {
        this.sources = this.sources.concat(assets)
      }
      this.showServerAssetsMulti = false
      done()
    },
    onSaveAssets () {
      this.changeAttr(this.sources.map(this.transformToData))
      this.onCloseAssetsDialog()
    },
    onView ({ type, keyName }) {
      this.onViewAsset({ type: type || this.widgetAttr.options.type, url: keyName })
    },
    onViewAsset (asset) {
      this.$muted = this.muted
      if (!this.muted) {
        this.muted = true
      }
      this.$refs.previewDialog.show(asset)
    },
    onClosePreview () {
      this.muted = this.$muted
    },
    onDelAsset (index) {
      this.sources.splice(index, 1)
    },
    onSourceDragStart () {
      this.dragging = true
    },
    onSourceDragEnd () {
      this.dragging = false
    },
    scaleDown () {
      this.scale = Math.max(this.scale - 10, this.minScale)
    },
    scaleUp () {
      this.scale = Math.min(this.scale + 10, this.maxScale)
    },
    onSave () {
      this.check().then(() => {
        this.selectedWidgetIndex = -1
        this.loading = true
        this.$nextTick(() => {
          this._save().finally(() => {
            this.loading = false
          })
        })
      })
    },
    check () {
      const warning = fix(this.node)
      if (warning) {
        return this.$confirm(
          warning,
          '继续保存',
          { type: 'warning' }
        )
      }
      return Promise.resolve()
    },
    async _save () {
      try {
        const base64 = await this.snap()
        const result = await updateProgram({
          id: this.program.id,
          duration: getDuration(this.node),
          itemJsonStr: JSON.stringify(toJSON(this.node)),
          base64
        })
        if (result) {
          if (window.opener) {
            window.opener.postMessage({
              id: this.program.id,
              base64
            })
            this.$message({
              type: 'success',
              dangerouslyUseHTMLString: true,
              duration: 5000,
              message: `保存成功, <span style="text-decoration: underline; cursor: pointer;" onclick="window.close()">返回节目列表</span>？`
            })
          } else {
            this.$message({
              type: 'success',
              message: '保存成功'
            })
          }
        } else {
          this.$message({
            type: 'warning',
            message: '保存失败'
          })
        }
      } catch (e) {
        console.warn(e)
        this.$message({
          type: 'warning',
          message: '保存失败'
        })
      }
    },
    snap () {
      this.snapping = true
      return domToImage.toJpeg(this.$refs.canvas, {
        filter (node) {
          const { tagName } = node
          if (tagName === 'CANVAS') {
            return /^data:.+;base64,.+/.test(node.toDataURL())
          }
          return tagName !== 'VIDEO' && tagName !== 'IFRAME'
        },
        width: this.node.width * this.scale / 100 | 0,
        height: this.node.height * this.scale / 100 | 0,
        quality: 0.1
      }).finally(() => {
        this.snapping = false
      })
    }
  }
}
</script>

<style lang="scss" scoped>
$theme: #181b23;
$dark: #121418;
$light: #1f232e;
$hover: lighten($theme, 10%);
$active: darken($theme, 5%);
$border: #242835;

.c-designer {
  height: 100%;
  min-width: 1080px;
  min-height: 600px;
  background-color: $theme;
  overflow: hidden;

  &__header {
    height: 53px;
    padding: 0 24px 0 10px;
    color: $info;
    font-size: 12px;
    line-height: 1;
    border-bottom: 1px solid $border;
  }

  &__shortcut {
    display: inline-flex;
    justify-content: center;
    align-items: center;
    width: 36px;
    height: 36px;
    font-size: 18px;
    border-radius: 50%;
    transition: background-color 0.4s;

    &:hover {
      background-color: $hover;
    }

    &:active {
      background-color: $active;
    }
  }

  &__name {
    max-width: 400px;
    padding: 0 $spacing 0 6px;
    font-size: 18px;
  }

  &__side {
    flex: none;
    min-height: 0;

    &.left {
      width: 144px;
    }

    &.right {
      width: 196px;
    }
  }

  &__main {
    flex: 1 0 0;
    display: flex;
    flex-direction: column;
    position: relative;
    min-width: 0;
  }

  &__content {
    flex: 1 0 0;
    position: relative;
    padding: 16px;
    overflow: auto;
    background: $dark url("~@/assets/dot.png") 0 0 / 16px 16px repeat;
  }

  &__tool {
    flex: 0 0 60px;
    color: $info;
    border-left: 1px solid $border;
    border-right: 1px solid $border;
  }

  &__wrapper {
    min-width: 100%;
    min-height: 100%;
  }

  &__canvas {
    position: relative;
    background-color: #000;
    overflow: visible;
  }

  &__background {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: currentColor;
    z-index: -1;
  }

  &__grid {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-size: 30px 30px, 30px 30px;
    background-image: linear-gradient(hsla(0, 0%, 100%, 0.1) 1px, transparent 0),
      linear-gradient(90deg, hsla(0, 0%, 100%, 0.1) 1px, transparent 0);
  }
}

.c-side {
  display: flex;
  flex-direction: column;

  &__tool {
    flex: none;
    display: flex;
    border-bottom: 1px solid $border;
    background-color: $light;
  }

  &__item {
    flex: 1 0 0;
    color: #9fa6b8;
    font-size: 16px;
    text-align: center;
    line-height: 60px;
    user-select: none;

    &.active {
      color: $blue;
      background-color: $theme;
    }
  }

  &__content {
    padding: 10px 16px;

    &.mini {
      padding: 10px;
    }
  }

  &__scrollbar {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    min-height: 0;

    ::v-deep {
      .el-scrollbar__wrap {
        flex: 1 1 0;
        min-height: 0;
        margin-bottom: 0 !important;
      }
    }
  }
}

.o-widget-cfg {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  user-select: none;
  cursor: pointer;

  & + & {
    margin-left: 32px;
  }

  &.active {
    background-color: #31455d;
  }

  &__icon {
    flex: none;
    display: inline-flex;
    justify-content: center;
    align-items: center;
    width: 32px;
    height: 32px;
    color: #fff;
    font-size: 22px;
    border-radius: $radius;
    background-color: $blue;
  }

  &__text {
    margin-top: 6px;
    color: #9fa5b8;
    font-size: 12px;
    line-height: 1;
  }
}

.o-layer {
  color: $gray--dark;
  user-select: none;
  border-radius: $radius;
  background-color: #252d42;
  overflow: hidden;
  cursor: pointer;

  & + & {
    margin-top: 10px;
  }

  &.active {
    color: #fff;
    outline: 2px solid $blue;
    background-color: $blue;
  }
}

.l-grid--info.dragging .c-card .c-card__icon {
  display: none;
}

.c-card {
  color: $info;

  &:hover &__icon {
    display: inline-block;
  }

  &__icon {
    display: none;
    position: absolute;
    top: 0;
    right: 0;
    padding: 6px;
    font-size: 16px;
    border-radius: 50%;
    background-color: rgba(#000, 0.4);
    z-index: 9;
  }

  &__tag {
    position: absolute;
    top: 0;
    left: 0;
    padding: 4px 6px;
    font-size: 12px;
    line-height: 1;
    border-bottom-right-radius: $radius;
    background-color: rgba(#000, 0.4);
  }

  &__checkbox {
    position: absolute;
    top: 10px;
    left: 10px;
    pointer-events: none;
    z-index: 9;
  }

  &__type {
    position: absolute;
    top: 50%;
    left: 50%;
    padding: 2px;
    font-size: 24px;
    border-radius: 50%;
    background-color: rgba(#000, 0.4);
    transform: translate(-50%, -50%);
  }
}

.o-scale-slider {
  justify-content: flex-start;
  min-width: 48px;
  width: auto;
  padding: 0 $spacing;
  font-size: 20px;

  &__wrapper {
    width: 184px;
    transition: width 0.1s;
    overflow: hidden;
  }

  &__slider {
    width: 100px;
    margin: 0 16px;
  }

  .el-icon-zoom-in + .svg-icon {
    margin-left: 16px;
  }

  .svg-icon {
    font-size: 16px;
  }
}
</style>
