签入版本

This commit is contained in:
2026-09-12 23:12:15 +08:00
commit 91998056ca
1841 changed files with 341325 additions and 0 deletions
@@ -0,0 +1,151 @@
<script setup lang="ts">
import { computed } from "vue";
import { VPDocAsideSponsors } from "vitepress/theme";
import sponsors from "./sponsors.json";
// to avoid the never[] type in json
interface Sponsor {
alt: string;
href: string;
imgSrcDark: string;
imgSrcLight: string;
}
const asideSponsors = computed(() => {
return [
{
size: "mini",
items: sponsors.platinum.length
? sponsors.platinum.map((sponsor: Sponsor) => ({
name: sponsor.alt,
url: sponsor.href,
img: sponsor.imgSrcLight,
}))
: [
{
name: "Become a sponsor",
url: "https://www.djangoadmin.cn",
img: "/sponsor/djangoadmin.png",
},
],
},
{
size: "xmini",
// TODO: use gold instead once I have some
items: sponsors.silver.map((sponsor: Sponsor) => ({
name: sponsor.alt,
url: sponsor.href,
img: sponsor.imgSrcLight,
})),
},
];
});
</script>
<template>
<VPDocAsideSponsors :data="asideSponsors" />
<a class="banner mp" href="https://www.djangoadmin.cn" target="_blank">
<img width="22" height="22" src="/sponsor/djangoadmin.png" />
<span>
<p class="extra-info">赋能开发者</p>
<p class="heading">企业级中台解决方案</p>
<p class="extra-info">助力企业发展</p>
</span>
</a>
<a class="banner cert" href="https://www.djangoadmin.cn" target="_blank">
<img width="22" height="22" src="/sponsor/djangoadmin.png" />
<span>
<p class="extra-info">赋能开发者</p>
<p class="heading">企业级中台解决方案</p>
<p class="extra-info">助力企业发展</p>
</span>
</a>
</template>
<style scoped>
.VPDocAsideSponsors {
margin-top: 8px !important;
}
:deep(.vp-sponsor-grid.mini .vp-sponsor-grid-image) {
max-width: 158px;
max-height: 48px;
}
:deep(.vp-sponsor-grid.xmini .vp-sponsor-grid-image) {
max-width: 80px;
max-height: 32px;
}
.banner {
margin: 0.25rem 0;
padding: 0.4rem 0;
border-radius: 14px;
position: relative;
font-size: 0.9rem;
font-weight: 700;
line-height: 1.1rem;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
gap: 1rem;
background-color: var(--vp-c-bg-alt);
border: 2px solid var(--vp-c-bg-alt);
transition: border-color 0.5s;
}
.banner:last-of-type {
margin-bottom: 1rem;
}
.banner:hover {
border: 2px solid var(--vp-c-brand-1);
}
.banner.cert:hover {
border: 2px solid var(--vp-c-green-1);
}
.banner img {
transition: transform 0.5s;
transform: scale(1.25);
}
.banner:hover img {
transform: scale(1.75);
}
.banner .extra-info {
color: var(--vp-c-text-1);
opacity: 0;
font-size: 0.7rem;
padding-left: 0.1rem;
transition: opacity 0.5s;
}
.banner .heading {
background-image: linear-gradient(
120deg,
var(--vp-c-brand-3) 16%,
var(--vp-c-brand-2),
var(--vp-c-brand-1)
);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.banner.cert .heading {
background-image: linear-gradient(
120deg,
var(--vp-c-green-3) 16%,
var(--vp-c-green-2),
var(--vp-c-green-1)
);
}
.banner:hover .extra-info {
opacity: 0.9;
}
</style>
@@ -0,0 +1,59 @@
<script setup lang="ts">
import HomeSponsorsGroup from "./HomeSponsorsGroup.vue";
import sponsors from "./sponsors.json";
import { useData } from "vitepress";
const { site } = useData();
const translations = {
en: "Become a sponsor",
"en-US": "Become a Sponsor!",
"zh-CN": "成为赞助商!",
};
</script>
<template>
<div class="sponsors_outer">
<div>
<HomeSponsorsGroup
v-if="sponsors.platinum.length"
name="Platinum"
size="96"
/>
<HomeSponsorsGroup
v-if="sponsors.bronze.length"
name="Bronze"
size="38"
/>
<HomeSponsorsGroup
v-if="sponsors.silver.length"
name="Silver"
size="24"
/>
<div class="cta">
<a
class="become-sponsor"
href="/zh/other/sponsor.html"
target="_self"
>{{ translations[site.lang] || translations.en }}</a
>
</div>
</div>
</div>
</template>
<style scoped>
.sponsors_outer {
text-align: center;
padding: 35px 40px 45px;
background-color: var(--vp-c-bg-accent);
/* transition when toggling dark mode */
transition: background-color 300ms ease-in-out, color 300ms ease-in-out;
}
.cta {
margin-top: 2rem;
}
</style>
@@ -0,0 +1,122 @@
<template>
<h3>{{ getNameText() }} 赞助商</h3>
<p>
<a
v-for="sponsor in list"
:key="sponsor.href"
:href="sponsor.href"
:title="sponsor.alt"
target="_blank"
rel="sponsored noopener"
class="sponsor_wrapper"
:class="
isDark && sponsor.imgSrcLight === sponsor.imgSrcDark && 'apply-bg'
"
>
<img
:src="sponsor.imgSrc"
:class="
isDark &&
sponsor.imgSrcLight === sponsor.imgSrcDark &&
'invert-colors'
"
:alt="sponsor.alt"
:style="{ height: size + 'px' }"
/>
</a>
</p>
</template>
<script setup lang="ts">
import sponsors from "./sponsors.json";
import { computed } from "vue";
import { useData } from "vitepress";
const props = withDefaults(
defineProps<{
name: "Gold" | "Platinum" | "Silver" | "Bronze";
size?: number | string;
}>(),
{
size: 140,
}
);
/**
* 获取赞助商等级
*/
const getNameText = () => {
switch (props.name) {
case "Gold":
return "黄金";
break;
case "Platinum":
return "铂金";
break;
case "Silver":
return "白金";
break;
case "Bronze":
return "青铜";
break;
default:
return "白金";
break;
}
};
const { isDark } = useData();
const list = computed(() =>
sponsors[props.name.toLowerCase()].map((sponsor) => ({
...sponsor,
imgSrc: isDark.value ? sponsor.imgSrcDark : sponsor.imgSrcLight,
}))
);
</script>
<style scoped>
.sponsor_wrapper {
padding: 5px;
margin: 0 3px;
border-radius: 5px;
display: inline-block;
text-decoration: none;
vertical-align: middle;
transition: background-color 300ms ease-in-out;
}
p {
margin: 0;
}
h3 {
font-size: 1.35rem;
font-weight: 600;
margin: 0.75em 0;
}
img {
transition: all 0.3s ease;
filter: grayscale(100%);
opacity: 0.66;
}
html:not(.light) img.invert-colors {
filter: invert(1) grayscale(100%);
background-color: transparent;
}
.sponsor_wrapper.apply-bg:hover {
background-color: var(--c-text);
}
.sponsor_wrapper:hover img {
filter: none !important;
opacity: 1;
}
</style>
@@ -0,0 +1,176 @@
<script setup lang="ts">
import { useData } from "vitepress";
import { computed, ref } from "vue";
// TODO: split into 2 components
const { site } = useData();
const translations = {
videoLink: {
"en-US":
"Master this and much more with the official video course by the author of Pinia",
"zh-CN": "通过 Pinia 作者的官方视频课程掌握更多内容",
},
videoEmbed: {
"en-US": "Master this and much more with a free video from Mastering Pinia",
"zh-CN": "通过 VideoModule 的免费视频掌握更多内容",
},
watchMoreA: {
"en-US": "Watch more on ",
"zh-CN": "获取 ",
},
watchMoreB: {
"en-US": "",
"zh-CN": " 官方授权",
},
};
const props = defineProps<{ href: string; title: string; mpLink?: string }>();
const isVideo = computed(() => props.href.startsWith("/"));
const isVideoOpen = ref(false);
</script>
<template>
<div class="mp">
<template v-if="isVideo">
<div class="video-embed" v-if="isVideoOpen">
<div style="padding: 56.25% 0 0 0; position: relative">
<iframe
loading="lazy"
title="Gumlet video player"
false
:src="
href +
'?preload=false&autoplay=true&loop=false&disable_player_controls=false'
"
style="
border: none;
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
"
allow="
accelerometer;
gyroscope;
autoplay;
encrypted-media;
picture-in-picture;
fullscreen;
"
frameborder="0"
allowfullscreen
>
</iframe>
</div>
<div class="watch-more">
{{ translations.watchMoreA[site.lang] }}
<a
:href="mpLink || 'https://www.djangoadmin.cn'"
target="_blank"
rel="noopener"
>
小蚂蚁云
<img src="../../../public/logo.svg" alt="小蚂蚁云" />
</a>
{{ translations.watchMoreB[site.lang] }}
</div>
</div>
<button class="cta" :title v-else @click="isVideoOpen = true">
<div class="text">
<slot>{{ translations.videoEmbed[site.lang] }}</slot>
</div>
</button>
</template>
<a
v-else
:href="href"
target="_blank"
rel="noopener"
:title="title"
class="no-icon cta"
>
<div class="text">
<slot>{{ translations.videoLink[site.lang] }}</slot>
</div>
</a>
</div>
</template>
<style scoped>
.mp {
margin-top: 20px;
}
.mp:has(.cta) {
position: relative;
transition: border-color 0.5s;
padding: 1em 1.25em;
background-color: var(--vp-code-block-bg);
border-radius: 1em;
border: 2px solid var(--vp-c-bg-alt);
}
.mp:has(.cta):hover {
border: 2px solid var(--vp-c-brand-1);
}
.cta:hover {
color: var(--vp-c-brand-1);
text-decoration: underline;
}
.watch-more {
text-align: end;
font-size: 0.8em;
background-color: var(--vp-code-block-bg);
border-radius: 0 0 1em 1em;
padding-right: 1em;
}
.watch-more img {
height: 1em;
display: inline-block;
/* vertical-align: middle; */
}
.cta {
font-size: inherit;
color: var(--c-text);
position: relative;
display: flex;
gap: 1em;
grid-template-columns: 1fr auto;
align-items: center;
justify-content: space-between;
padding-left: 36px;
}
.cta .content {
flex-grow: 1;
}
.cta:before {
content: "";
position: absolute;
display: block;
width: 30px;
height: 30px;
top: calc(50% - 15px);
left: -4px;
border-radius: 50%;
background-color: var(--vp-c-brand-1);
}
html.dark .cta:after {
--play-icon-color: #000;
}
.cta:after {
content: "";
position: absolute;
display: block;
width: 0;
height: 0;
top: calc(50% - 5px);
left: 8px;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 9px solid var(--play-icon-color, #fff);
}
</style>
@@ -0,0 +1,38 @@
{
"platinum": [],
"gold": [],
"silver": [
{
"alt": "企业级中台解决方案",
"href": "https://www.djangoadmin.cn",
"imgSrcDark": "/sponsor/djangoadmin.png",
"imgSrcLight": "/sponsor/djangoadmin.png"
},
{
"alt": "企业级中台解决方案",
"href": "https://www.djangoadmin.cn",
"imgSrcDark": "/sponsor/djangoadmin.png",
"imgSrcLight": "/sponsor/djangoadmin.png"
}
],
"bronze": [
{
"alt": "企业级中台解决方案",
"href": "https://www.djangoadmin.cn",
"imgSrcDark": "/sponsor/djangoadmin.png",
"imgSrcLight": "/sponsor/djangoadmin.png"
},
{
"alt": "企业级中台解决方案",
"href": "https://www.djangoadmin.cn",
"imgSrcDark": "/sponsor/djangoadmin.png",
"imgSrcLight": "/sponsor/djangoadmin.png"
},
{
"alt": "企业级中台解决方案",
"href": "https://www.djangoadmin.cn",
"imgSrcDark": "/sponsor/djangoadmin.png",
"imgSrcLight": "/sponsor/djangoadmin.png"
}
]
}