mirror of
https://github.com/fawney19/Aether.git
synced 2026-01-09 03:02:26 +08:00
Initial commit
This commit is contained in:
167
frontend/src/views/public/CliSection.vue
Normal file
167
frontend/src/views/public/CliSection.vue
Normal file
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<section
|
||||
ref="sectionRef"
|
||||
class="min-h-screen snap-start flex items-center px-16 lg:px-20 py-20"
|
||||
>
|
||||
<div class="max-w-7xl mx-auto grid md:grid-cols-2 gap-12 items-center">
|
||||
<!-- Content column -->
|
||||
<div :class="contentOrder">
|
||||
<!-- Badge -->
|
||||
<div
|
||||
class="inline-flex items-center gap-2 rounded-full px-3 py-1 text-xs font-medium mb-4 transition-all duration-500"
|
||||
:class="badgeClass"
|
||||
:style="badgeStyle"
|
||||
>
|
||||
<component :is="badgeIcon" class="h-3 w-3" />
|
||||
{{ badgeText }}
|
||||
</div>
|
||||
|
||||
<!-- Title -->
|
||||
<h2
|
||||
class="text-4xl md:text-5xl font-bold text-[#191919] dark:text-white mb-6 transition-all duration-700"
|
||||
:style="titleStyle"
|
||||
>
|
||||
{{ title }}
|
||||
</h2>
|
||||
|
||||
<!-- Description -->
|
||||
<p
|
||||
class="text-lg text-[#666663] dark:text-gray-300 mb-4 transition-all duration-700"
|
||||
:style="descStyle"
|
||||
>
|
||||
{{ description }}
|
||||
</p>
|
||||
|
||||
<!-- Install command -->
|
||||
<div
|
||||
class="mb-4 transition-all duration-700 relative z-10"
|
||||
:style="cardStyleFn(0)"
|
||||
>
|
||||
<div :class="[panelClasses.commandPanel, 'flex flex-wrap items-center gap-3 px-4 py-3']">
|
||||
<PlatformSelect
|
||||
:model-value="platformValue"
|
||||
@update:model-value="$emit('update:platformValue', $event)"
|
||||
:options="platformOptions"
|
||||
class="shrink-0"
|
||||
/>
|
||||
<div class="flex-1 min-w-[180px]">
|
||||
<CodeHighlight :code="installCommand" language="bash" dense />
|
||||
</div>
|
||||
<button
|
||||
@click="$emit('copy', installCommand)"
|
||||
:class="panelClasses.iconButtonSmall"
|
||||
title="复制配置"
|
||||
>
|
||||
<Copy class="h-3.5 w-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Config files -->
|
||||
<div
|
||||
v-for="(config, idx) in configFiles"
|
||||
:key="config.path"
|
||||
class="transition-all duration-700"
|
||||
:class="idx < configFiles.length - 1 ? 'mb-3' : ''"
|
||||
:style="cardStyleFn(idx + 1)"
|
||||
>
|
||||
<div :class="[panelClasses.configPanel, 'overflow-hidden']">
|
||||
<div :class="panelClasses.panelHeader">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-xs font-medium text-[#666663] dark:text-muted-foreground">
|
||||
{{ config.path }}
|
||||
</span>
|
||||
<button
|
||||
@click="$emit('copy', config.content)"
|
||||
:class="panelClasses.iconButtonSmall"
|
||||
title="复制配置"
|
||||
>
|
||||
<Copy class="h-3.5 w-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="panelClasses.codeBody">
|
||||
<div class="config-code-wrapper">
|
||||
<CodeHighlight :code="config.content" :language="config.language" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Logo placeholder column -->
|
||||
<div :class="logoOrder" class="flex items-center justify-center h-full min-h-[300px] relative">
|
||||
<slot name="logo" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, type CSSProperties, type Component } from 'vue'
|
||||
import { Copy } from 'lucide-vue-next'
|
||||
import PlatformSelect from '@/components/PlatformSelect.vue'
|
||||
import CodeHighlight from '@/components/CodeHighlight.vue'
|
||||
import { panelClasses, type PlatformOption } from './home-config'
|
||||
|
||||
// Expose section element for parent scroll tracking
|
||||
const sectionRef = ref<HTMLElement | null>(null)
|
||||
defineExpose({ sectionEl: sectionRef })
|
||||
|
||||
interface ConfigFile {
|
||||
path: string
|
||||
content: string
|
||||
language: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
description: string
|
||||
badgeIcon: Component
|
||||
badgeText: string
|
||||
badgeClass: string
|
||||
platformValue: string
|
||||
platformOptions: PlatformOption[]
|
||||
installCommand: string
|
||||
configFiles: ConfigFile[]
|
||||
// Style props
|
||||
badgeStyle: CSSProperties
|
||||
titleStyle: CSSProperties
|
||||
descStyle: CSSProperties
|
||||
cardStyleFn: (cardIndex: number) => CSSProperties
|
||||
// Layout: 'left' means content on left, 'right' means content on right
|
||||
contentPosition?: 'left' | 'right'
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
contentPosition: 'left'
|
||||
})
|
||||
|
||||
defineEmits<{
|
||||
copy: [text: string]
|
||||
'update:platformValue': [value: string]
|
||||
}>()
|
||||
|
||||
const contentOrder = computed(() =>
|
||||
props.contentPosition === 'right' ? 'md:order-2' : ''
|
||||
)
|
||||
|
||||
const logoOrder = computed(() =>
|
||||
props.contentPosition === 'right' ? 'md:order-1' : ''
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.config-code-wrapper :deep(.code-highlight pre) {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
background-color: transparent !important;
|
||||
padding: 1rem 1.2rem !important;
|
||||
}
|
||||
|
||||
/* Header separator line */
|
||||
.panel-header {
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user