Update CI and cube projections
Some checks failed
Deploy to Production / deploy (push) Failing after 5s
Some checks failed
Deploy to Production / deploy (push) Failing after 5s
This commit is contained in:
@@ -1,13 +1,16 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Sun, Moon } from 'lucide-vue-next';
|
import { Sun, Moon, Layers } from 'lucide-vue-next';
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
|
import { useSettings } from '../composables/useSettings';
|
||||||
|
|
||||||
|
const { showProjections, toggleProjections } = useSettings();
|
||||||
const isDark = ref(true);
|
const isDark = ref(true);
|
||||||
|
|
||||||
const setTheme = (dark) => {
|
const setTheme = (dark) => {
|
||||||
isDark.value = dark;
|
isDark.value = dark;
|
||||||
const theme = dark ? 'dark' : 'light';
|
const theme = dark ? 'dark' : 'light';
|
||||||
document.documentElement.dataset.theme = theme;
|
document.documentElement.dataset.theme = theme;
|
||||||
|
localStorage.setItem('theme', theme);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleTheme = () => {
|
const toggleTheme = () => {
|
||||||
@@ -15,7 +18,12 @@ const toggleTheme = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setTheme(true);
|
const savedTheme = localStorage.getItem('theme');
|
||||||
|
if (savedTheme) {
|
||||||
|
setTheme(savedTheme === 'dark');
|
||||||
|
} else {
|
||||||
|
setTheme(true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -26,6 +34,11 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav-container">
|
<div class="nav-container">
|
||||||
|
<!-- Projections Toggle -->
|
||||||
|
<button class="btn-neon nav-btn icon-only" @click="toggleProjections" :title="showProjections ? 'Ukryj rzuty' : 'Pokaż rzuty'" :class="{ active: showProjections }">
|
||||||
|
<Layers :size="20" />
|
||||||
|
</button>
|
||||||
|
|
||||||
<!-- Theme Toggle -->
|
<!-- Theme Toggle -->
|
||||||
<button class="btn-neon nav-btn icon-only" @click="toggleTheme" :title="isDark ? 'Przełącz na jasny' : 'Przełącz na ciemny'">
|
<button class="btn-neon nav-btn icon-only" @click="toggleTheme" :title="isDark ? 'Przełącz na jasny' : 'Przełącz na ciemny'">
|
||||||
<Sun v-if="isDark" :size="20" />
|
<Sun v-if="isDark" :size="20" />
|
||||||
@@ -86,7 +99,13 @@ onMounted(() => {
|
|||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-btn:hover {
|
.nav-btn:hover,
|
||||||
|
.nav-btn.active {
|
||||||
background: rgba(255, 255, 255, 0.2);
|
background: rgba(255, 255, 255, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-btn.active {
|
||||||
|
color: var(--color-primary);
|
||||||
|
box-shadow: 0 0 10px rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
59
src/components/common/Line3D.vue
Normal file
59
src/components/common/Line3D.vue
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
start: {
|
||||||
|
type: Object,
|
||||||
|
required: true // {x, y, z}
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
type: Object,
|
||||||
|
required: true // {x, y, z}
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: 'var(--text-color, #fff)'
|
||||||
|
},
|
||||||
|
thickness: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const style = computed(() => {
|
||||||
|
const dx = props.end.x - props.start.x;
|
||||||
|
const dy = props.end.y - props.start.y;
|
||||||
|
const dz = props.end.z - props.start.z;
|
||||||
|
|
||||||
|
const length = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||||
|
|
||||||
|
if (length === 0) return {};
|
||||||
|
|
||||||
|
const midX = (props.start.x + props.end.x) / 2;
|
||||||
|
const midY = (props.start.y + props.end.y) / 2;
|
||||||
|
const midZ = (props.start.z + props.end.z) / 2;
|
||||||
|
|
||||||
|
// Rotation
|
||||||
|
// Yaw (around Y axis)
|
||||||
|
const yaw = Math.atan2(dz, dx);
|
||||||
|
// Pitch (around Z axis)
|
||||||
|
const pitch = Math.atan2(dy, Math.sqrt(dx * dx + dz * dz));
|
||||||
|
|
||||||
|
return {
|
||||||
|
width: `${length}px`,
|
||||||
|
height: `${props.thickness}px`,
|
||||||
|
backgroundColor: props.color,
|
||||||
|
position: 'absolute',
|
||||||
|
top: '0',
|
||||||
|
left: '0',
|
||||||
|
transformOrigin: 'center center',
|
||||||
|
transform: `translate3d(${midX}px, ${midY}px, ${midZ}px) rotateY(${-yaw}rad) rotateZ(${pitch}rad) translate(-50%, -50%)`,
|
||||||
|
opacity: 0.3, // Delicate
|
||||||
|
pointerEvents: 'none'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="line-3d" :style="style"></div>
|
||||||
|
</template>
|
||||||
25
src/composables/useSettings.js
Normal file
25
src/composables/useSettings.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
let initialShowProjections = false;
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem('showProjections');
|
||||||
|
if (stored !== null) {
|
||||||
|
initialShowProjections = stored === 'true';
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
const showProjections = ref(initialShowProjections);
|
||||||
|
|
||||||
|
export function useSettings() {
|
||||||
|
const toggleProjections = () => {
|
||||||
|
showProjections.value = !showProjections.value;
|
||||||
|
try {
|
||||||
|
localStorage.setItem('showProjections', String(showProjections.value));
|
||||||
|
} catch (e) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
showProjections,
|
||||||
|
toggleProjections
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user