sidebar
This commit is contained in:
parent
ae540ed6f8
commit
1b635741b9
|
@ -13,6 +13,7 @@ declare module 'vue' {
|
|||
Gallery: typeof import('./src/components/Promo/gallery.vue')['default']
|
||||
Game: typeof import('./src/components/Game.vue')['default']
|
||||
Home: typeof import('./src/components/Home.vue')['default']
|
||||
IMdiArrowRight: typeof import('~icons/mdi/arrow-right')['default']
|
||||
IMdiChevronLeft: typeof import('~icons/mdi/chevron-left')['default']
|
||||
IMdiClose: typeof import('~icons/mdi/close')['default']
|
||||
IMdiFile: typeof import('~icons/mdi/file')['default']
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
@font-face {
|
||||
font-family: 'open-sans';
|
||||
src: url('../fonts/open-sans.ttf');
|
||||
}
|
||||
|
||||
$accentColor: rgb(126, 126, 223);
|
||||
|
||||
.container {
|
||||
font-family: 'open-sans';
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font-size: 6rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.main {
|
||||
ul {
|
||||
font-size: 4rem;
|
||||
|
||||
li {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: initial;
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
color: $accentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,16 @@
|
|||
@import 'grid.scss';
|
||||
|
||||
@font-face {
|
||||
font-family: 'main';
|
||||
src: url('../fonts/main.otf');
|
||||
}
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'logo';
|
||||
src: url('../fonts/logo.ttf');
|
||||
}
|
||||
|
||||
a[href] {
|
||||
color: #048280;
|
||||
|
||||
|
@ -7,3 +18,5 @@ a[href] {
|
|||
color: #a47f62;
|
||||
}
|
||||
}
|
||||
|
||||
@import 'sidebar.scss';
|
|
@ -1,110 +0,0 @@
|
|||
|
||||
$blackColor: #181818;
|
||||
$accentColor: #ef570c;
|
||||
$redColor: #f83300;
|
||||
|
||||
@font-face {
|
||||
font-family: 'logo';
|
||||
src: url('../fonts/logo.ttf');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'main';
|
||||
src: url('../fonts/main.otf');
|
||||
}
|
||||
|
||||
.container {
|
||||
font-family: 'main';
|
||||
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.15) 0%, rgba(0, 0, 0, 0.15) 100%), radial-gradient(at top center, rgba(255, 255, 255, 0.40) 0%, rgba(0, 0, 0, 0.40) 120%) $blackColor;
|
||||
background-blend-mode: multiply, multiply;
|
||||
color: #fff;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.header {
|
||||
justify-content: center;
|
||||
}
|
||||
.main,
|
||||
.header,
|
||||
.sidebar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.menu {
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
font-size: 2.5rem;
|
||||
|
||||
li {
|
||||
padding: 0.5rem 0;
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
|
||||
&,
|
||||
&:hover,
|
||||
&:active,
|
||||
&:visited {
|
||||
color: $accentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.model {
|
||||
max-width: 33vw;
|
||||
}
|
||||
|
||||
.product {
|
||||
gap: 1rem;
|
||||
position: relative;
|
||||
|
||||
&-image {
|
||||
flex-basis: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&-description {
|
||||
font-size: 1.75rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
&-model {
|
||||
max-height: 80%;
|
||||
|
||||
&-icon {
|
||||
position: absolute;
|
||||
font-size: 4rem;
|
||||
right: 0;
|
||||
top: 0;
|
||||
color: $accentColor;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.logo {
|
||||
&-header {
|
||||
font-family: 'logo';
|
||||
font-size: 4rem;
|
||||
padding: 1rem;
|
||||
|
||||
background: linear-gradient(45deg, $redColor, $accentColor);
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
&-img {
|
||||
width: 54%;
|
||||
display: block;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
$bg: #2D3031;
|
||||
$textColor: #fff;
|
||||
$textColor2: #9A9697;
|
||||
$primary: #E75B12;
|
||||
|
||||
.homelink {
|
||||
position: absolute;
|
||||
right: 2rem;
|
||||
top: 4rem;
|
||||
|
||||
transition: right 300ms linear;
|
||||
|
||||
a {
|
||||
background-color: $bg;
|
||||
color: $textColor;
|
||||
line-height: 1;
|
||||
font-size: 3rem;
|
||||
height: 7rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 1rem;
|
||||
opacity: 0.97;
|
||||
|
||||
svg {
|
||||
transition: all 400ms linear;
|
||||
}
|
||||
}
|
||||
|
||||
&.open {
|
||||
right: 20vw;
|
||||
|
||||
svg {
|
||||
transform: scale(-1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
width: 19vw;
|
||||
top: 4rem;
|
||||
right: -50%;
|
||||
bottom: 0;
|
||||
transition: all 300ms linear;
|
||||
line-height: 1.25;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
|
||||
&.open {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
&-content {
|
||||
max-height: 100%;
|
||||
overflow: auto;
|
||||
|
||||
background-color: $bg;
|
||||
border-top-left-radius: 2rem;
|
||||
border-bottom-left-radius: 2rem;
|
||||
|
||||
padding: 1.5rem;
|
||||
|
||||
color: $textColor;
|
||||
font-family: 'main';
|
||||
}
|
||||
|
||||
&-list {
|
||||
|
||||
}
|
||||
|
||||
&-list-item {
|
||||
font-size: 1.875rem;
|
||||
color: $textColor2;
|
||||
|
||||
display: flex;
|
||||
|
||||
input {
|
||||
margin-right: 2rem;
|
||||
|
||||
&.checked + label {
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: 'logo';
|
||||
font-size: 1.875rem;
|
||||
text-align: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1rem;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
background-color: darken($textColor2, 30%);
|
||||
opacity: 0.97;
|
||||
border-radius: 1rem;
|
||||
height: 3.75rem;
|
||||
color: $primary;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-decoration: none;
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
<style lang="scss" scoped>
|
||||
@import '../assets/home.scss';
|
||||
</style>
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
Выберите шаблон (демо)
|
||||
</div>
|
||||
<div class="sidebar"></div>
|
||||
<div class="main">
|
||||
<ul>
|
||||
<li>
|
||||
<RouterLink to="promo">Промо</RouterLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -4,30 +4,30 @@ import {
|
|||
Box3, Color, DoubleSide, Group, Mesh, PlaneGeometry,
|
||||
MeshStandardMaterial, MeshStandardMaterialParameters,
|
||||
Vector2, Vector3,
|
||||
Object3D
|
||||
} from 'three';
|
||||
|
||||
import { useTresContext, useSeek, useTexture, useLoop } from '@tresjs/core';
|
||||
import { useGLTF } from '@tresjs/cientos'
|
||||
|
||||
import Env from './env.vue'
|
||||
import PostProcessing from './post_processing.vue'
|
||||
|
||||
import { IMAGE_URL, PROMOBG, SERVER_URL, } from '../../constants'
|
||||
import { usePromoSidebar } from '../../stores/promo_sidebar';
|
||||
import { usePromoScene } from '../../stores/promo_scene';
|
||||
import { useClickable } from '../../stores/clickable';
|
||||
import { mobileAndTabletCheck } from '../../helpers';
|
||||
|
||||
const props = defineProps(['source', 'loaded', 'loaded_pan'])
|
||||
|
||||
const models = ref<model3DType[]>([])
|
||||
const clickable = ref<clickableAreaType[]>([])
|
||||
const clickable_items = ref<any[]>([])
|
||||
const clickable_refs = ref<any[]>([])
|
||||
const envVars = reactive({}) as EnvVars
|
||||
|
||||
const sidebar = usePromoSidebar();
|
||||
const sidebar_scene = usePromoScene()
|
||||
const sidebar_scene = usePromoScene();
|
||||
const clickable = useClickable()
|
||||
|
||||
const { controls, camera, scene, raycaster, renderer } = useTresContext()
|
||||
const { pause, resume } = useLoop()
|
||||
const { seekByName, seekAllByName, seek } = useSeek()
|
||||
|
@ -40,7 +40,6 @@ const { scene: pointer_pin } = await useGLTF('/pointer.glb')
|
|||
|
||||
const timer = ref(10)
|
||||
setInterval(() => {
|
||||
// console.log({ timer: timer.value })
|
||||
if (timer.value > 0) {
|
||||
timer.value -= 1
|
||||
} else if (timer.value == 0 && !(controls.value as any).autoRotate && (controls.value as any).enabled) {
|
||||
|
@ -87,11 +86,11 @@ const loadModels = async () => {
|
|||
|
||||
(controls.value as any).reset()
|
||||
|
||||
const sidebar_items = []
|
||||
const sidebar_items = [] as PromoScene[]
|
||||
clickable_items.value = []
|
||||
|
||||
for (let index = 0; index < data.length; index++) {
|
||||
const element = data[index];
|
||||
sidebar_items.push({ ...element })
|
||||
const item = {} as model3DType
|
||||
|
||||
item.modelUrl = `${IMAGE_URL}/${element.model_file}`
|
||||
|
@ -115,7 +114,7 @@ const loadModels = async () => {
|
|||
|
||||
const res = await fetch(`${SERVER_URL}/api/obj/clickable/?source=${element.id}`)
|
||||
const clickable_areas = await res.json()
|
||||
clickable.value.push(...clickable_areas)
|
||||
clickable.list.push(...clickable_areas)
|
||||
}
|
||||
|
||||
let c = new Color()
|
||||
|
@ -155,10 +154,8 @@ const loadModels = async () => {
|
|||
ground.name = "ground"
|
||||
models.value.push({ name: 'ground', modelFile: ground })
|
||||
|
||||
sidebar_scene.setData(sidebar_items)
|
||||
|
||||
for (let index = 0; index < clickable.value.length; index++) {
|
||||
const element = clickable.value[index];
|
||||
for (let index = 0; index < clickable.list.length; index++) {
|
||||
const element = clickable.list[index];
|
||||
const find_element = seekByName(scene.value, element.object_name)
|
||||
if (!find_element) continue
|
||||
if (find_element && !(find_element as Group).isGroup) {
|
||||
|
@ -167,14 +164,6 @@ const loadModels = async () => {
|
|||
(find_element as Mesh).localToWorld(world_position);
|
||||
|
||||
const p = raw_data.min_distance * 0.05
|
||||
// const plane = new PlaneGeometry(p, p, 32)
|
||||
|
||||
// const mesh_material = new MeshBasicMaterial({ side: DoubleSide })
|
||||
// mesh_material.color = new Color('red')
|
||||
// if (element.image) {
|
||||
// const map = new TextureLoader().load(`${IMAGE_URL}/${element.image}`);
|
||||
// mesh_material.map = map
|
||||
// }
|
||||
|
||||
const point = pointer_pin.clone()
|
||||
point.position.set(world_position.x, p * 3, world_position.z)
|
||||
|
@ -185,9 +174,17 @@ const loadModels = async () => {
|
|||
if (clickable_items.value.find(el => el.name == point.name)) continue
|
||||
clickable_items.value.push(point)
|
||||
clickable_refs.value.push(ref(`${element.id}_clickable`))
|
||||
|
||||
sidebar_items.push({
|
||||
id: element.id,
|
||||
name: element.name
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
sidebar_scene.name = raw_data.name;
|
||||
sidebar_scene.setData(sidebar_items)
|
||||
|
||||
const loaded = seekByName(scene.value, 'loaded')
|
||||
if (loaded) {
|
||||
const box = new Box3();
|
||||
|
@ -227,8 +224,8 @@ onAfterRender(() => {
|
|||
let oldObj = [] as { uuid: string, color: Color }[]
|
||||
const passShader = (obj: Mesh | Group) => {
|
||||
if (obj instanceof Mesh) {
|
||||
oldObj.push({ uuid: obj.uuid, color: obj.material.color })
|
||||
obj.material.color = new Color(1, 0, 0)
|
||||
oldObj.push({ uuid: obj.uuid, color: (obj.material as MeshStandardMaterial).color });
|
||||
(obj.material as MeshStandardMaterial).color = new Color(1, 0, 0)
|
||||
} else if (obj instanceof Group) {
|
||||
for (let c in obj.children) {
|
||||
passShader(obj.children[c])
|
||||
|
@ -236,27 +233,7 @@ const passShader = (obj: Mesh | Group) => {
|
|||
}
|
||||
}
|
||||
const openSidebar = (id: number) => {
|
||||
const target = clickable.value.find(el => el.id == id)
|
||||
if (!target) return
|
||||
const sidebar_data = {
|
||||
title: target.name,
|
||||
description: target.description
|
||||
} as PromoSidebarData
|
||||
if (target?.target) {
|
||||
sidebar_data.target = target.target.toString()
|
||||
sidebar_data.target_name = target.target_name
|
||||
}
|
||||
sidebar.setData(sidebar_data)
|
||||
sidebar.open()
|
||||
|
||||
const elements = [
|
||||
seekByName(scene.value, target.name),
|
||||
seekByName(scene.value, target.object_name),
|
||||
].filter(Boolean)
|
||||
|
||||
elements.forEach((element) => {
|
||||
passShader(element)
|
||||
})
|
||||
sidebar.open(id)
|
||||
}
|
||||
|
||||
loadModels()
|
||||
|
@ -316,24 +293,6 @@ const clickEvent = (event: MouseEvent) => {
|
|||
openSidebar(parseInt(names[0].replace('_clickable', '')))
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => sidebar_scene.list, () => {
|
||||
sidebar_scene.list.forEach(element => {
|
||||
const el = seekByName(scene.value, element.name)
|
||||
if (!el) return
|
||||
if (el.visible !== element.is_enabled) {
|
||||
el.visible = element.is_enabled
|
||||
}
|
||||
});
|
||||
}, { deep: true })
|
||||
watch(() => sidebar.is_open, () => {
|
||||
if (sidebar.is_open == false) {
|
||||
oldObj.forEach(el => {
|
||||
const obj = seek(scene.value, 'uuid', el.uuid) as Mesh
|
||||
obj.material.color = el.color
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<TresGroup name="loaded">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import type { Ref } from 'vue'
|
||||
import { RouterLink, useRoute } from 'vue-router';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import { Vector3 } from 'three';
|
||||
import { TresCanvas } from '@tresjs/core';
|
||||
|
@ -55,6 +55,14 @@ watch(() => route.params.target, () => {
|
|||
}
|
||||
}, { deep: true })
|
||||
|
||||
|
||||
const sidebarFunc = () => {
|
||||
if (sidebar.is_open) {
|
||||
sidebar.close()
|
||||
} else {
|
||||
sidebar.open()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
|
@ -68,8 +76,8 @@ watch(() => route.params.target, () => {
|
|||
<LoadModels :source="source" :loaded="set_model_load_status" :loaded_pan="loadedPan" />
|
||||
</Suspense>
|
||||
</TresCanvas>
|
||||
<div class="homelink">
|
||||
<a href="#" @click.prevent="sidebar.open" v-if="!sidebar.is_open">
|
||||
<div class="homelink" :class="[{ open: sidebar.is_open }]">
|
||||
<a href="#" @click.prevent="sidebarFunc">
|
||||
<i-mdi-chevron-left />
|
||||
</a>
|
||||
</div>
|
||||
|
@ -93,21 +101,4 @@ watch(() => route.params.target, () => {
|
|||
filter: blur(10px);
|
||||
transition: all 300ms linear;
|
||||
}
|
||||
|
||||
.homelink {
|
||||
position: absolute;
|
||||
right: 2rem;
|
||||
top: 4rem;
|
||||
|
||||
a {
|
||||
background-color: #2D3031;
|
||||
color: #fff;
|
||||
line-height: 1;
|
||||
font-size: 3rem;
|
||||
height: 7rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -10,15 +10,28 @@ const sidebar_obj = ref()
|
|||
|
||||
const route = useRoute()
|
||||
|
||||
const opened_desc = ref()
|
||||
|
||||
const openedChange = () => {
|
||||
sidebar.open(opened_desc.value)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="sidebar" :class="[{ 'open': sidebar.is_open }]" ref="sidebar_obj">
|
||||
<a href="#" @click.prevent="sidebar.close" class="sidebar-close">
|
||||
<i-mdi-close />
|
||||
</a>
|
||||
<div class="sidebar-content">
|
||||
<template v-if="!sidebar.is_open"></template>
|
||||
<template v-else-if="sidebar.title">
|
||||
<template v-if="!sidebar.is_open"></template>
|
||||
<template v-else>
|
||||
<div class="sidebar-content">
|
||||
<h2>{{ sidebar_scene.name }}</h2>
|
||||
<div class="sidebar-list">
|
||||
<div class="sidebar-list-item" v-for="item in sidebar_scene.list">
|
||||
<input type="radio" v-model=opened_desc :value="item.id" :id="item.id"
|
||||
:checked="opened_desc == item.id" @change="openedChange"
|
||||
:class="[{ checked: opened_desc == item.id }]" />
|
||||
<label :for="item.id">{{ item.name }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-content" v-if="sidebar.title">
|
||||
<h2>{{ sidebar.title }}</h2>
|
||||
<template v-if="sidebar.description">
|
||||
<template v-for="p in sidebar.description.split('\n')">
|
||||
|
@ -26,134 +39,9 @@ const route = useRoute()
|
|||
</template>
|
||||
</template>
|
||||
<RouterLink class="btn" :to="`/${route.params.item}/${sidebar.target}`" v-if="sidebar.target">
|
||||
{{ sidebar.target_name }}
|
||||
<i-mdi-arrow-right />
|
||||
</RouterLink>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="sidebar-list-item" v-for="item in sidebar_scene.list">
|
||||
<input type="checkbox" v-model="item.is_enabled" :id="item.name" :disabled="item.can_not_disable" />
|
||||
<label :for="item.name">
|
||||
<h3>{{ item.name }}</h3>
|
||||
<template v-for="p in (item.description || '').split('\n')">
|
||||
<p>{{ p }}</p>
|
||||
</template>
|
||||
</label>
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
.sidebar {
|
||||
min-width: 20vw;
|
||||
max-width: 23vw;
|
||||
background-color: #fff;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: -50%;
|
||||
bottom: 0;
|
||||
transition: all 300ms linear;
|
||||
line-height: 1.25;
|
||||
|
||||
padding: 3rem 2rem 2rem;
|
||||
|
||||
@media(max-width:768px) {
|
||||
padding-top: 2rem;
|
||||
padding-left: 0.75rem;
|
||||
padding-right: 0.75rem;
|
||||
max-width: 48%;
|
||||
}
|
||||
|
||||
&.open {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
&-close {
|
||||
position: absolute;
|
||||
left: 1.5rem;
|
||||
top: 0.5rem;
|
||||
font-size: 2rem;
|
||||
color: black;
|
||||
|
||||
@media(max-width:768px) {
|
||||
left: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
max-height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&-list-item {
|
||||
display: flex;
|
||||
|
||||
label {
|
||||
flex-grow: 1;
|
||||
margin-left: 0.25rem
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
text-align: center;
|
||||
font-size: 2rem;
|
||||
margin: 1rem;
|
||||
|
||||
@media(max-width:768px) {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
p,
|
||||
h3 {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.25rem;
|
||||
|
||||
@media(max-width:768px) {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
|
||||
@media(max-width:768px) {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
|
||||
background: #4FD1C5;
|
||||
background: linear-gradient(90deg, rgba(129, 230, 217, 1) 0%, rgba(79, 209, 197, 1) 100%);
|
||||
color: #313133;
|
||||
transition: .2s linear;
|
||||
|
||||
padding: 1rem 1.5rem;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1.3px;
|
||||
|
||||
border-radius: 1000px;
|
||||
|
||||
box-shadow: 12px 12px 24px rgba(79, 209, 197, .64);
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
box-shadow: 0 0 0 2px white, inset 0 0 0 4px #3C82F8;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -65,12 +65,7 @@ interface PromoSidebar extends PromoSidebarData {
|
|||
}
|
||||
interface PromoScene {
|
||||
id: number
|
||||
model_file: string
|
||||
name: string
|
||||
description?: string
|
||||
parent?: number
|
||||
is_enabled: boolean
|
||||
can_not_disable: boolean
|
||||
}
|
||||
interface EnvVars {
|
||||
focus: number,
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import { defineStore } from 'pinia'
|
||||
interface state {
|
||||
list: clickableAreaType[]
|
||||
}
|
||||
export const useClickable = defineStore('clickable', {
|
||||
state: () => {
|
||||
return {
|
||||
list: []
|
||||
} as state
|
||||
},
|
||||
})
|
|
@ -1,76 +0,0 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { SERVER_URL } from '../constants'
|
||||
import { chunks } from '../helpers'
|
||||
|
||||
export const useFloorplanStore = defineStore('floorplan', {
|
||||
state: () => {
|
||||
return {
|
||||
items: [] as { id: string, title: string }[],
|
||||
title: undefined,
|
||||
np_array: [] as number[][],
|
||||
prepared_array: [] as number[][],
|
||||
chunk_size: undefined as number | undefined,
|
||||
threshold: undefined as number | undefined,
|
||||
points: [] as { type: string, title: string, points: { x: number, y: number } }[]
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
async getList() {
|
||||
try {
|
||||
const res = await fetch(`${SERVER_URL}/api/floorplan/`, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
})
|
||||
const data = await res.json()
|
||||
this.items = data
|
||||
// this.title = data.title
|
||||
// this.np_array = data.np_field
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
},
|
||||
async getData(id: number) {
|
||||
try {
|
||||
const res = await fetch(`${SERVER_URL}/api/floorplan/${id}`, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
})
|
||||
const data = await res.json()
|
||||
this.title = data.title
|
||||
this.np_array = data.np_field
|
||||
this.chunk_size = data.d_size || 8
|
||||
this.threshold = data.d_border || 20
|
||||
|
||||
this.prepared_array = [...chunks(data.np_field, this.chunk_size as number)].map(line => {
|
||||
const line_data = [] as any[][]
|
||||
line.map((item: any) => [...chunks(item, this.chunk_size as number)]).map((item) => {
|
||||
item.map((one_line, k) => {
|
||||
if (!line_data[k]) line_data[k] = []
|
||||
line_data[k].push(...one_line)
|
||||
})
|
||||
})
|
||||
return line_data.map(el => {
|
||||
return el.filter(e => e > 0).length > (this.threshold as number) ? 1 : 0
|
||||
})
|
||||
});
|
||||
await this.getPoints(id)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
},
|
||||
async getPoints(id: number) {
|
||||
const res = await fetch(`${SERVER_URL}/api/floorplan/${id}/points`, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
})
|
||||
const data = await res.json()
|
||||
this.points = data.points
|
||||
}
|
||||
}
|
||||
})
|
|
@ -1,24 +0,0 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { SERVER_URL } from '../constants'
|
||||
|
||||
export const useProductStore = defineStore('product', {
|
||||
state: () => {
|
||||
return {
|
||||
// for initially empty lists
|
||||
list: [] as ProductInfo[],
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
async getData() {
|
||||
try {
|
||||
const res = await fetch(`${SERVER_URL}/api/products`)
|
||||
const data = await res.json()
|
||||
if (data.length) {
|
||||
this.list = data
|
||||
}
|
||||
} catch (error) {
|
||||
this.list = []
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
|
@ -1,8 +1,15 @@
|
|||
import { defineStore } from 'pinia'
|
||||
|
||||
type state = {
|
||||
name: string,
|
||||
list: PromoScene[]
|
||||
}
|
||||
export const usePromoScene = defineStore('promo_scene', {
|
||||
state: () => {
|
||||
return { list: [] as PromoScene[] }
|
||||
return {
|
||||
name: '',
|
||||
list: []
|
||||
} as state
|
||||
},
|
||||
actions: {
|
||||
setData(data: PromoScene[]) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { useClickable } from './clickable'
|
||||
|
||||
export const usePromoSidebar = defineStore('promo_sidebar', {
|
||||
state: () => {
|
||||
|
@ -12,9 +13,25 @@ export const usePromoSidebar = defineStore('promo_sidebar', {
|
|||
} as PromoSidebar
|
||||
},
|
||||
actions: {
|
||||
open() {
|
||||
open(id: number) {
|
||||
if (id) {
|
||||
const clickable = useClickable()
|
||||
const target = clickable.list.find(el => el.id == id)
|
||||
if (!target) return
|
||||
const sidebar_data = {
|
||||
title: target.name,
|
||||
description: target.description
|
||||
} as PromoSidebarData
|
||||
if (target?.target) {
|
||||
sidebar_data.target = target.target.toString()
|
||||
sidebar_data.target_name = target.target_name
|
||||
}
|
||||
this.setData(sidebar_data)
|
||||
}
|
||||
|
||||
this.is_open = true
|
||||
this.loading = true
|
||||
|
||||
},
|
||||
setData(data: PromoSidebarData) {
|
||||
this.$state = Object.assign(this.$state, data)
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"name": "interactive-table",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
Loading…
Reference in New Issue