Skip to content

Commit

Permalink
Moving over bifrost work
Browse files Browse the repository at this point in the history
  • Loading branch information
CarelessCourage committed Sep 10, 2024
1 parent 3c4db37 commit 3c51d46
Show file tree
Hide file tree
Showing 68 changed files with 5,654 additions and 66 deletions.
184 changes: 184 additions & 0 deletions packages/carbonfiber/components/Carbon/Carbon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
<!-- eslint-disable vue/no-mutating-props -->
<script setup lang="ts">
import { onMounted, ref, computed } from 'vue'
import type { CarbonObject, Connection, HookType } from '../../types'
import CarbonHooks from './CarbonHooks.vue'
import { hooks } from '../../data/index'
import { gsap } from 'gsap'
import { Draggable } from 'gsap/Draggable'
import { InertiaPlugin } from 'gsap-trial/InertiaPlugin'
gsap.registerPlugin(InertiaPlugin)
gsap.registerPlugin(Draggable)
const title = 'Carbon'
const props = defineProps<{
carbon: CarbonObject
carbons: CarbonObject[]
bounds?: HTMLDivElement
connections: Connection[]
}>()
const carbonref = ref<HTMLDivElement>()
const draggHandle = ref<HTMLDivElement>()
const inputs = ref<InstanceType<typeof CarbonHooks>>()
const outputs = ref<InstanceType<typeof CarbonHooks>>()
const top = computed(() => `${props.carbon.position[1]}px`)
const left = computed(() => `${props.carbon.position[0]}px`)
function updateReferences() {
connections.value.forEach((connection) => {
// Stores carbon reference in connection object
const isFrom = connection.output.carbon === props.carbon.id
isFrom
? (connection.output.component = props.carbon.component)
: (connection.input.component = props.carbon.component)
})
}
defineExpose({ inputs, outputs, updateReferences })
const connections = computed(() => props.connections.filter(isRelatedConnection))
onMounted(() => {
const carbonEl = carbonref.value
if (!carbonEl) return
updateReferences()
Draggable.create(carbonEl, {
bounds: props.bounds,
trigger: draggHandle.value,
inertia: false,
edgeResistance: 0.9,
onDrag: updateFibers
})
})
function updateFibers() {
// Updates the path out of and into the carbon
connections.value.forEach((connection) => {
connection.component?.update()
})
}
function setFibers(carbonId: string) {
const parentCarbon = props.carbons.find((carbon) => carbon.id === carbonId)
parentCarbon?.component?.updateReferences()
setTimeout(() => updateFibers(), 0)
}
function addHookedCarbon(carbonId: string, type: HookType, hookIndex: number) {
const childId = 'carbon-' + props.carbons.length
props.carbons.push({
id: childId,
position: [200, 200],
component: undefined,
connections: [carbonId],
hooks: hooks
})
addConnection(carbonId, childId, type, hookIndex)
setFibers(carbonId)
}
function addConnection(carbonId: string, childId: string, type: HookType, hookIndex: number) {
const fromOutput = type === 'output' || type === 'sink' // Is this connection being dragged out from a carbon output?
const isOutputInout = type === 'output' || type === 'input' // Is this connection an output to input connection?
props.connections.push({
id: 'connection-' + props.connections.length,
type: isOutputInout ? 'output-input' : 'source-sink',
output: {
carbon: fromOutput ? carbonId : childId,
hook: fromOutput ? hookIndex : 0
},
input: {
carbon: fromOutput ? childId : carbonId,
hook: fromOutput ? 0 : hookIndex
}
})
}
function isRelatedConnection(connection: Connection) {
const isFrom = connection.output.carbon === props.carbon.id
const isTo = connection.input.carbon === props.carbon.id
return isFrom || isTo
}
</script>

<template>
<div ref="carbonref" id="carbon">
<CarbonHooks
ref="inputs"
:carbon="carbon"
type="input"
@hookClick="(index) => addHookedCarbon(carbon.id, 'input', index)"
/>
<div class="core">
<CarbonHooks
:carbon="carbon"
type="input"
@hookClick="(index) => addHookedCarbon(carbon.id, 'input', index)"
/>
<div ref="draggHandle" class="content">
<p>
<strong>{{ title }}</strong>
</p>
</div>
<CarbonHooks
:carbon="carbon"
type="output"
@hookClick="(index) => addHookedCarbon(carbon.id, 'output', index)"
/>
</div>
<CarbonHooks
ref="outputs"
:carbon="carbon"
type="output"
@hookClick="(index) => addHookedCarbon(carbon.id, 'output', index)"
/>
</div>
</template>

<style>
#carbon {
position: absolute;
top: v-bind(top);
left: v-bind(left);
z-index: 1;
display: grid;
grid-template-columns: auto 1fr auto;
justify-items: center;
align-items: center;
background-color: var(--accent-120);
color: var(--base-20);
border-radius: var(--radius);
}
#carbon .core {
display: grid;
min-height: var(--space-6);
}
#carbon .core p {
line-height: 1;
}
#carbon .core .edges {
flex-direction: row;
}
#carbon .core .content {
display: flex;
justify-content: center;
align-items: center;
padding: var(--space-2);
min-height: var(--space-5);
border: 2px solid var(--accent-60);
border-radius: var(--radius);
height: 100%;
width: 100%;
}
</style>
61 changes: 61 additions & 0 deletions packages/carbonfiber/components/Carbon/CarbonHooks.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import type { CarbonObject } from '../../types'
import { gsap } from 'gsap'
import { Draggable } from 'gsap/Draggable'
import { InertiaPlugin } from 'gsap-trial/InertiaPlugin'
gsap.registerPlugin(InertiaPlugin)
gsap.registerPlugin(Draggable)
const props = defineProps<{
carbon: CarbonObject
type: string
}>()
const emit = defineEmits({
hookClick: (index: number) => true
})
const hooks = ref<HTMLDivElement[]>([])
const carbonHooks = computed(() => props.carbon.hooks.filter((hook) => hook.type === props.type))
defineExpose({ hooks })
function storeRef(el: any, index: number) {
hooks.value[index] = el
}
</script>

<template>
<div class="edges">
<div
v-for="hook in carbonHooks"
:key="hook.index"
:ref="(e) => storeRef(e, hook.index)"
class="hook"
@click="emit('hookClick', hook.index)"
></div>
</div>
</template>

<style>
#carbon .hook {
height: var(--space-atom);
aspect-ratio: 1 / 1;
background: var(--accent);
}
#carbon .hook:hover {
background: var(--accent-40);
}
#carbon .edges {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
gap: var(--space-1);
height: 100%;
}
</style>
23 changes: 23 additions & 0 deletions packages/carbonfiber/components/Connections.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup lang="ts">
import type { Connection } from '../types'
import FiberPath from './Fiber.vue'
type FiberType = InstanceType<typeof FiberPath>
defineProps<{
bounds?: HTMLDivElement
connections: Connection[]
}>()
</script>

<template>
<div v-for="connection in connections" :key="connection.id">
<FiberPath
v-if="connection.output.component && connection.input.component"
:ref="(e) => (connection.component = e as FiberType)"
:bounds="bounds"
:output="connection.output.component?.outputs?.hooks[connection.output.hook]"
:input="connection.input.component?.inputs?.hooks[connection.input.hook]"
/>
</div>
</template>
76 changes: 76 additions & 0 deletions packages/carbonfiber/components/Fiber.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<script setup lang="ts">
import { computed, defineProps, onMounted, defineExpose } from 'vue'
import { useResizeObserver } from '@vueuse/core'
import { useFiber } from '../composables/useFiber'
interface FiberProps {
bounds?: HTMLDivElement
output?: HTMLDivElement
input?: HTMLDivElement
}
const { output, input, bounds } = defineProps<FiberProps>()
const fiber = useFiber({
board: bounds,
output: output,
input: input
})
defineExpose({ update: fiber.update })
const data = computed(() => {
const path = fiber.path.value
const flipped = path.reversed ? !path.flipped : path.flipped
return createPathData(flipped)
})
function createPathData(flipped: boolean) {
const path = fiber.path.value
const width = path.width - path.padding
const height = path.height
const curve = width * path.curve
const strokeOffset = path.stroke / 2
const top = strokeOffset + path.padding
const bottom = height - strokeOffset - path.padding
const start = flipped ? top : bottom
const end = `${width}, ${flipped ? bottom : top}`
const startCurve = `${curve}, ${flipped ? top : bottom}`
const endCurve = `${width - curve}, ${flipped ? bottom : top}`
return `M${path.padding}, ${start} C${startCurve}, ${endCurve}, ${end}`
}
onMounted(() => {
setTimeout(() => fiber.update(), 0)
useResizeObserver(bounds, () => {
fiber.update()
})
})
</script>

<template>
<div :ref="(e) => fiber.set(e as HTMLDivElement)" id="rome" class="ancor">
<svg
:width="fiber.path.value.width"
:height="fiber.path.value.height"
xmlns="http://www.w3.org/2000/svg"
>
<path :d="data" :stroke-width="fiber.path.value.stroke" stroke-linecap="round" />
</svg>
</div>
</template>

<style scoped>
#rome {
position: absolute;
z-index: 0;
}
#rome svg path {
fill: transparent;
stroke: var(--accent);
}
</style>
../composables/useFiber
Loading

0 comments on commit 3c51d46

Please sign in to comment.