/
45case
/
ptable
Обзор
Документация
Войти
/
45case
/
ptable
Код
Запросы
3
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
dev
src/entities/element/ui/ElementIconCard.vue
275 строк
6 KB
Olya
Страница Электроны + сайдбар с характеритстиками (Степень окисления, Конфигурация, Развёрнутая, Уровни энергии, ВЗМО)
24 июл 2026, 11:54
24 июл 2026, 11:54
3cf1d48
Код
Авторство
О чём код?
<script setup lang="ts"> import { computed } from "vue"; import { getElementPropertiesByAtomicNumber } from "../api/getElementProperties"; import { formatElementMass } from "../lib/formatElementMass"; import { ptableAtomicMassAbridgedByZ } from "../lib/ptableAtomicMassAbridged"; import { getElementCategoryLabel } from "../model/category"; import type { PeriodicElement } from "../model/elements"; import { categoryLegendItems } from "@/entities/table/model/categoryLegend"; import { useTableView } from "@/shared/lib/useTableView"; import { getCloseUpShellSlots } from "@/entities/electrons"; const props = defineProps<{ element: PeriodicElement; }>(); const emit = defineEmits<{ "open-article": []; }>(); const { isTableExtended } = useTableView(); const physical = computed(() => getElementPropertiesByAtomicNumber(props.element.atomicNumber), ); const seriesLabel = computed(() => { const match = categoryLegendItems.find( (item) => item.category === props.element.category || item.highlightCategories?.includes(props.element.category), ); return match?.label ?? getElementCategoryLabel(props.element.category); }); const electronShells = computed(() => getCloseUpShellSlots(physical.value?.electronsPerShell), ); const iconMass = computed(() => { const abridged = ptableAtomicMassAbridgedByZ[props.element.atomicNumber]; if (abridged) { return abridged.replace(".", ","); } return formatElementMass(props.element.atomicMass, { atomicNumber: props.element.atomicNumber, source: props.element.atomicMassWeight ?? physical.value?.atomicMassWeight, }); }); function onOpenArticle(event: Event) { event.stopPropagation(); emit("open-article"); } </script> <template> <div v-if="!isTableExtended" class="element-icon-card" :class="element.category" > <span class="element-icon-card__z">{{ element.atomicNumber }}</span> <div class="element-icon-card__body"> <strong class="element-icon-card__symbol">{{ element.symbol }}</strong> <button type="button" class="element-icon-card__name element-icon-card__name--link" :title="`Открыть статью: ${element.name}`" @click="onOpenArticle" > {{ element.name }} </button> <data class="element-icon-card__mass" :value="element.atomicMass ?? undefined" > {{ iconMass }} </data> </div> <ol class="element-icon-card__shells" aria-label="Электроны по оболочкам" > <li v-for="(count, index) in electronShells" :key="index" class="element-icon-card__shell" > {{ count }} </li> </ol> <span class="element-icon-card__category">{{ seriesLabel }}</span> </div> </template> <style scoped> .element-icon-card { display: grid; flex: 0 0 auto; grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: auto minmax(0, 1fr) auto; grid-template-areas: "number shells" "body shells" "category category"; column-gap: 0.4rem; row-gap: 0.16rem; box-sizing: border-box; width: calc(100% - 2.4rem); max-width: 13.6rem; aspect-ratio: 1; margin: 0.55rem auto 0.4rem; padding: 0.48rem 0.48rem 0.4rem; border: 1px solid #1a1a1a; border-radius: 0.35rem; background: var(--aside-card-bg, #5b4444); color: #ffffff; box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.12), 0 1px 3px color-mix(in oklab, var(--color-shadow, #000) 18%, transparent), 0 1px 2px color-mix(in oklab, var(--color-shadow, #000) 28%, transparent); text-align: start; } .element-icon-card.alkali-metal { --aside-card-bg: #6c3b01; } .element-icon-card.alkaline-earth-metal { --aside-card-bg: #846011; } .element-icon-card.transition-metal { --aside-card-bg: #711019; } .element-icon-card.post-transition-metal { --aside-card-bg: #003666; } .element-icon-card.metalloid { --aside-card-bg: #015146; } .element-icon-card.nonmetal, .element-icon-card.halogen { --aside-card-bg: #3e6418; } .element-icon-card.noble-gas { --aside-card-bg: #3a2151; } .element-icon-card.lanthanide { --aside-card-bg: #402c17; } .element-icon-card.actinide { --aside-card-bg: #732e4c; } .element-icon-card.unknown { --aside-card-bg: #3c3a3a; } .element-icon-card__z { grid-area: number; font-family: var(--table-font-data, var(--table-font-ui)); font-size: 0.95rem; font-weight: 700; line-height: 1.1; letter-spacing: -0.025em; color: rgb(255 255 255 / 0.88); } .element-icon-card__body { grid-area: body; display: flex; flex-direction: column; justify-content: center; align-items: flex-start; min-width: 0; gap: 0.14rem; } .element-icon-card__symbol { overflow: hidden; font-size: 3.05rem; font-weight: 700; line-height: 0.9; letter-spacing: -0.04em; color: #ffffff; } .element-icon-card__name { margin: 0; overflow: hidden; max-width: 100%; font-size: 1.05rem; font-weight: 600; line-height: 1.1; letter-spacing: -0.025em; text-overflow: ellipsis; white-space: nowrap; color: rgb(255 255 255 / 0.94); } .element-icon-card__name--link { padding: 0; border: 0; background: transparent; font: inherit; color: inherit; text-align: start; text-decoration: underline; text-underline-offset: 0.12em; cursor: pointer; } .element-icon-card__name--link:hover, .element-icon-card__name--link:focus-visible { color: #99c3ff; outline: none; } .element-icon-card__mass { font-family: var(--table-font-data, var(--table-font-ui)); font-size: 0.92rem; font-weight: 560; line-height: 1.1; color: rgb(255 255 255 / 0.82); } .element-icon-card__shells { grid-area: shells; display: flex; flex-direction: column; justify-content: flex-start; align-items: flex-end; align-self: stretch; margin: 0; padding: 0.05rem 0 0; list-style: none; gap: 0.04rem; min-width: 1.45rem; } .element-icon-card__shell { font-family: var(--table-font-data, var(--table-font-ui)); font-size: 0.82rem; font-weight: 650; line-height: 1.15; font-variant-numeric: tabular-nums; color: rgb(255 255 255 / 0.78); } .element-icon-card__category { grid-area: category; display: block; overflow: hidden; max-width: 100%; font-size: 0.8rem; font-weight: 650; line-height: 1.15; letter-spacing: -0.01em; text-overflow: ellipsis; white-space: nowrap; color: rgb(255 255 255 / 0.78); } </style>