Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions app/components/CustomEdge.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<script lang="ts" setup>
import { computed } from 'vue'
import type { EdgeProps } from '@vue-flow/core'
import {
BaseEdge,
EdgeLabelRenderer,
getBezierPath,
useVueFlow,
} from '@vue-flow/core'

const props = defineProps<EdgeProps>()

const { removeEdges } = useVueFlow()

const path = computed(() => getBezierPath(props))
</script>

<script lang="ts">
export default {
inheritAttrs: false,
}
</script>

<template>
<BaseEdge
:path="path[0]"
:style="{
stroke: '#3b82f6',
strokeWidth: 2,
opacity: 0.8,
}"
/>

<EdgeLabelRenderer>
<div
:style="{
pointerEvents: 'all',
position: 'absolute',
transform: `translate(-50%, -50%) translate(${path[1]}px,${path[2]}px)`,
}"
class="nodrag nopan edge-button-container"
>
<button class="edge-button" @click="removeEdges(id)" title="Remove edge">
<UIcon name="i-lucide-x" class="w-3 h-3" />
</button>
</div>
</EdgeLabelRenderer>
</template>

<style scoped>
.edge-button-container {
opacity: 0;
transition: opacity 0.2s;
}

.edge-button-container:hover,
.vue-flow__edge:hover + .edge-button-container {
opacity: 1;
}

.edge-button {
width: 20px;
height: 20px;
background: #ef4444;
border: 2px solid white;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 12px;
font-weight: bold;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transition: all 0.2s;
}

.edge-button:hover {
background: #dc2626;
transform: scale(1.1);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}
</style>
142 changes: 142 additions & 0 deletions app/components/CustomNode.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<script lang="ts" setup>
import { Handle, Position } from '@vue-flow/core'
import type { NodeProps } from '@vue-flow/core'

interface CustomNodeData {
title: string
subtitle?: string
icon?: string
}

defineProps<NodeProps<CustomNodeData>>()
</script>

<template>
<div class="custom-node group">
<Handle
type="target"
:position="Position.Top"
class="!w-3 !h-3 !bg-primary-500 !border-2 !border-white shadow-md"
/>

<div class="node-content">
<div class="flex items-center gap-3">
<div class="node-icon">
<UIcon
:name="data?.icon || 'i-lucide-box'"
class="w-5 h-5 text-primary-600"
/>
</div>
<div class="node-text">
<h3 class="font-semibold text-gray-900 dark:text-gray-100">
{{ data?.title || label }}
</h3>
<p
v-if="data?.subtitle"
class="text-sm text-gray-600 dark:text-gray-300"
>
{{ data.subtitle }}
</p>
</div>
</div>
</div>

<Handle
type="source"
:position="Position.Bottom"
class="!w-3 !h-3 !bg-primary-500 !border-2 !border-white shadow-md"
/>
</div>
</template>

<style scoped>
.custom-node {
background: white;
border-radius: 0.5rem;
border: 1px solid #e5e7eb;
box-shadow:
0 4px 6px -1px rgb(0 0 0 / 0.1),
0 2px 4px -2px rgb(0 0 0 / 0.1);
transition: all 0.2s;
min-width: 180px;
padding: 16px;
}

@media (prefers-color-scheme: dark) {
.custom-node {
background: #1f2937;
border-color: #374151;
}
}

.custom-node:hover {
box-shadow:
0 10px 15px -3px rgb(0 0 0 / 0.1),
0 4px 6px -4px rgb(0 0 0 / 0.1);
border-color: #bfdbfe;
transform: translateY(-2px);
}

@media (prefers-color-scheme: dark) {
.custom-node:hover {
border-color: #1d4ed8;
}
}

.node-content {
position: relative;
z-index: 10;
}

.node-icon {
width: 2.5rem;
height: 2.5rem;
background: #eff6ff;
border-radius: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
}

@media (prefers-color-scheme: dark) {
.node-icon {
background: rgba(37, 99, 235, 0.1);
}
}

.node-text h3 {
font-size: 1rem;
line-height: 1.25;
font-weight: 600;
color: #111827;
}

@media (prefers-color-scheme: dark) {
.node-text h3 {
color: #f9fafb;
}
}

.node-text p {
font-size: 0.75rem;
line-height: 1.25;
margin-top: 0.25rem;
color: #6b7280;
}

@media (prefers-color-scheme: dark) {
.node-text p {
color: #d1d5db;
}
}

/* Handle styles */
.custom-node :deep(.vue-flow__handle) {
opacity: 0;
transition: opacity 0.2s;
}

.custom-node:hover :deep(.vue-flow__handle) {
opacity: 1;
}
</style>
6 changes: 0 additions & 6 deletions app/components/SponsorSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@
}"
>
<div class="flex flex-col items-center">
<!-- <template v-for="({ tier, sponsors }) of sponsorGroups" :key="tier"> -->
<div class="w-full mb-24">
<!-- <UBadge color="neutral" variant="subtle" class="capitalize mb-2">
{{ tier }} sponsors
</UBadge> -->

<div class="w-full border border-default rounded-lg">
<table class="w-full">
<tbody>
Expand Down Expand Up @@ -69,7 +64,6 @@
</table>
</div>
</div>
<!-- </template> -->
</div>
</UPageSection>
</template>
Expand Down
38 changes: 19 additions & 19 deletions app/composables/useNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,31 @@ function _useHeaderLinks() {
target: '_blank',
search: false,
},
{
label: 'Tutorial',
icon: 'i-lucide-graduation-cap',
to: '#',
search: false,
disabled: true,
},
// {
// label: 'Tutorial',
// icon: 'i-lucide-graduation-cap',
// to: '#',
// search: false,
// disabled: true,
// },
{
label: 'Plugins',
to: '/plugins',
icon: 'i-lucide-puzzle',
search: false,
},
{
label: 'Deploy',
to: '/deploy',
icon: 'i-lucide-rocket',
search: false,
},
{
label: 'Templates',
icon: 'i-lucide-app-window',
to: '/templates',
search: false,
},
// {
// label: 'Deploy',
// to: '/deploy',
// icon: 'i-lucide-rocket',
// search: false,
// },
// {
// label: 'Templates',
// icon: 'i-lucide-app-window',
// to: '/templates',
// search: false,
// },
{
label: 'Blog',
icon: 'i-lucide-newspaper',
Expand Down
62 changes: 33 additions & 29 deletions app/pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<script lang="ts" setup>
import { link } from '#build/ui'
import { LazyMDC } from '#components'
import type { TabsItem } from '@nuxt/ui'
import { defaultJavaScriptRegexConstructor } from 'shiki'
// import { defaultJavaScriptRegexConstructor } from 'shiki'

definePageMeta({
heroBackground: '-z-10',
Expand Down Expand Up @@ -194,36 +193,41 @@ defineOgImageComponent('OgImageMain', {})
'flex flex-col lg:grid py-16 sm:py-24 lg:py-32 gap-8 sm:gap-16 lg:grid-cols-[5fr_7fr] lg:items-center',
}"
>
<UPageCard
title="Domain driven design"
class="overflow-auto lg:absolute [@media(min-width:2400px)]:relative lg:-mt-16 [@media(min-width:2400px)]:mt-8 right-0 [@media(min-width:2400px)]:right-auto w-screen lg:w-[calc(50%-2rem)] [@media(min-width:2400px)]:w-full max-w-[800px] [@media(min-width:2400px)]:mx-auto rounded-none lg:rounded-l-[calc(var(--ui-radius)*4)] [@media(min-width:2400px)]:rounded-2xl -mx-4 sm:-mx-6 lg:mx-0"
variant="subtle"
:ui="{
container: 'sm:pt-4.5 lg:pr-0 [@media(min-width:2400px)]:px-6 w-full',
}"
<!-- <VueFlow
v-model:nodes="nodes"
v-model:edges="edges"
fit-view-on-init
class="vue-flow-litestar"
:default-zoom="0.8"
:min-zoom="0.3"
:max-zoom="2"
:pan-on-scroll="true"
:zoom-on-scroll="true"
:zoom-on-pinch="true"
:zoom-on-double-click="false"
:connect-on-click="false"
:nodes-draggable="true"
:edges-updatable="true"
@edge-update-start="() => {}"
@edge-update="() => {}"
@edge-update-end="() => {}"
>
<LazyMDC :value="page.development.code" />
</UPageCard>
<!-- <template #description>
<MDC
:value="page.development.description"
cache-key="index-component-customization-description"
<Controls
class="!bg-background/80 !border !border-border"
:style="{
backgroundColor: 'var(--ui-bg-elevated)',
borderColor: 'var(--ui-border-accented)',
}"
/>
</template>

<div class="grid grid-cols-2 gap-8">
<div
v-for="feature in page.development.features"
:key="feature.title"
class="text-center p-6"
>
<div class="w-16 h-16 bg-primary/10 rounded-2xl flex items-center justify-center mx-auto mb-4">
<UIcon :name="feature.icon" class="text-primary text-2xl" />
</div>
<h3 class="font-semibold text-lg mb-3">{{ feature.title }}</h3>
<p class="text-sm text-muted-foreground leading-relaxed">{{ feature.description }}</p>
</div>
</div> -->
<template #node-custom="nodeProps">
<CustomNode v-bind="nodeProps" />
</template>

<template #edge-custom="edgeProps">
<CustomEdge v-bind="edgeProps" />
</template>
</VueFlow> -->
</UPageSection>

<USeparator />
Expand Down
8 changes: 4 additions & 4 deletions app/pages/plugins/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ watch(filteredPlugins, () => {
})

const copyAllInstallCommands = () => {
const pluginNames = pluginsToAdd.value.map((plugin) => plugin.name).join(' ')
const pluginNames = pluginsToAdd.value.map((plugin) => plugin.pypi).join(' ')
const command = `${selectedPackageManager.value.command} ${pluginNames}`
copy(command, {
title: 'Install command copied to clipboard:',
Expand Down Expand Up @@ -298,9 +298,9 @@ initializePlugins()
<UPageBody>
<div class="flex items-center gap-2 mb-4 text-muted">
<UIcon name="i-lucide-info" class="size-4" />
<span class="text-xs"
>Shift+click to select plugins for bulk installation</span
>
<span class="text-xs">
Shift+click to select plugins for bulk installation
</span>
</div>

<UPageGrid
Expand Down
Loading