slidev-theme-practicum 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +270 -0
- package/components/DebugGrid.vue +50 -0
- package/components/DecorLibrary.vue +1117 -0
- package/components/Header.vue +124 -0
- package/components/Image.vue +82 -0
- package/components/ImageRenderer.vue +126 -0
- package/components/Logo.vue +142 -0
- package/components/Person.vue +89 -0
- package/components/Slide.vue +324 -0
- package/components/Slot.vue +419 -0
- package/components/Text.vue +216 -0
- package/components/Timeline.vue +202 -0
- package/composables/decor-catalog.mjs +339 -0
- package/composables/decor-config.mjs +488 -0
- package/composables/decor-file-store.ts +192 -0
- package/composables/decor-http-store.ts +25 -0
- package/composables/decor-store.ts +39 -0
- package/composables/decor-tuning-overrides.mjs +2 -0
- package/composables/decor-workbench.ts +799 -0
- package/composables/grid-placement.ts +396 -0
- package/composables/image-config.mjs +484 -0
- package/composables/layout-authoring.ts +372 -0
- package/composables/layout-markdown.mjs +56 -0
- package/composables/layout-recipes.ts +347 -0
- package/composables/layout-registry.ts +47 -0
- package/composables/layout-shorthands.ts +891 -0
- package/composables/layout-vnode.ts +43 -0
- package/composables/logo-mark.mjs +5 -0
- package/composables/slide-layout.ts +43 -0
- package/composables/slot-placement.ts +195 -0
- package/composables/slot-rules.ts +147 -0
- package/composables/text-fit-runtime.ts +577 -0
- package/composables/text-priority-fit.mjs +166 -0
- package/composables/text-typography.mjs +138 -0
- package/composables/theme-foundation.ts +192 -0
- package/composables/theme-media.mjs +202 -0
- package/composables/use-theme-config.ts +71 -0
- package/decor-library.md +10 -0
- package/env.d.ts +6 -0
- package/example.md +786 -0
- package/layouts/collection.vue +5 -0
- package/layouts/cover.vue +5 -0
- package/layouts/default.vue +5 -0
- package/layouts/explainer.vue +5 -0
- package/layouts/message.vue +5 -0
- package/layouts/none.vue +5 -0
- package/layouts/section.vue +5 -0
- package/layouts/two-cols.vue +11 -0
- package/package.json +84 -0
- package/public/decor/decor-1.svg +83 -0
- package/public/decor/decor-10.svg +40 -0
- package/public/decor/decor-11.svg +162 -0
- package/public/decor/decor-12.svg +83 -0
- package/public/decor/decor-13.svg +5 -0
- package/public/decor/decor-14.svg +7 -0
- package/public/decor/decor-15.svg +10 -0
- package/public/decor/decor-16.svg +9 -0
- package/public/decor/decor-17.png +0 -0
- package/public/decor/decor-18.png +0 -0
- package/public/decor/decor-19.svg +5 -0
- package/public/decor/decor-2.png +0 -0
- package/public/decor/decor-3.svg +9 -0
- package/public/decor/decor-4.svg +31 -0
- package/public/decor/decor-5.png +0 -0
- package/public/decor/decor-6.png +0 -0
- package/public/decor/decor-7.png +0 -0
- package/public/decor/decor-8.svg +21 -0
- package/public/decor/decor-9.svg +38 -0
- package/public/favicon.svg +11 -0
- package/public/photos/photo-1.png +0 -0
- package/public/photos/photo-10.png +0 -0
- package/public/photos/photo-2.png +0 -0
- package/public/photos/photo-3.png +0 -0
- package/public/photos/photo-4.png +0 -0
- package/public/photos/photo-5.png +0 -0
- package/public/photos/photo-6.png +0 -0
- package/public/photos/photo-7.png +0 -0
- package/public/photos/photo-8.png +0 -0
- package/public/photos/photo-9.png +0 -0
- package/setup/main.ts +3 -0
- package/setup/shiki.ts +10 -0
- package/setup/vite-plugins.ts +106 -0
- package/slidev-theme-practicum.png +0 -0
- package/slidev-theme-practicum.svg +102 -0
- package/styles/example.css +0 -0
- package/styles/index.css +192 -0
- package/styles/vars.css +119 -0
- package/types/slidev-client.d.ts +15 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { useSlideContext } from '@slidev/client'
|
|
4
|
+
import Logo from '../components/Logo.vue'
|
|
5
|
+
import { useThemeConfig } from '../composables/use-theme-config'
|
|
6
|
+
|
|
7
|
+
const props = defineProps({
|
|
8
|
+
variant: {
|
|
9
|
+
type: String as () => 'default' | 'cover',
|
|
10
|
+
default: 'default',
|
|
11
|
+
},
|
|
12
|
+
inverted: {
|
|
13
|
+
type: Boolean,
|
|
14
|
+
default: false,
|
|
15
|
+
},
|
|
16
|
+
title: {
|
|
17
|
+
type: String,
|
|
18
|
+
default: '',
|
|
19
|
+
},
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const { $page } = useSlideContext()
|
|
23
|
+
const { deckTitle, showPageNumber } = useThemeConfig()
|
|
24
|
+
|
|
25
|
+
const resolvedTitle = computed(() => props.title || deckTitle.value)
|
|
26
|
+
const shouldShowPage = computed(() => props.variant !== 'cover' && showPageNumber.value)
|
|
27
|
+
const isInverted = computed(() => props.inverted)
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<header class="Header"
|
|
32
|
+
:class="{
|
|
33
|
+
Header_variant_cover: variant === 'cover',
|
|
34
|
+
Header_inverted: inverted,
|
|
35
|
+
}">
|
|
36
|
+
<div class="Header-Logo">
|
|
37
|
+
<Logo v-if="variant === 'cover'"
|
|
38
|
+
size="full"
|
|
39
|
+
:title="resolvedTitle || 'Theme logo'"
|
|
40
|
+
:foreground="isInverted ? 'var(--theme-color-light-0)' : 'var(--theme-color-dark-0)'"
|
|
41
|
+
:contrast="isInverted ? 'var(--theme-color-dark-0)' : 'var(--theme-color-light-0)'"
|
|
42
|
+
class="Header-LogoImage" />
|
|
43
|
+
<Logo v-else
|
|
44
|
+
size="short"
|
|
45
|
+
:title="resolvedTitle || 'Theme logo'"
|
|
46
|
+
:background="isInverted ? 'var(--theme-color-light-0)' : 'var(--theme-color-dark-0)'"
|
|
47
|
+
:foreground="isInverted ? 'var(--theme-color-dark-0)' : 'var(--theme-color-light-0)'"
|
|
48
|
+
class="Header-LogoImage" />
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<div v-if="resolvedTitle"
|
|
52
|
+
class="Header-DeckTitle">
|
|
53
|
+
<span>{{ resolvedTitle }}</span>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<div v-if="shouldShowPage"
|
|
57
|
+
class="Header-Page">
|
|
58
|
+
<span>{{ $page }}</span>
|
|
59
|
+
</div>
|
|
60
|
+
</header>
|
|
61
|
+
</template>
|
|
62
|
+
|
|
63
|
+
<style scoped>
|
|
64
|
+
.Header {
|
|
65
|
+
display: grid;
|
|
66
|
+
grid-template-columns: repeat(var(--theme-grid-columns), minmax(0, 1fr));
|
|
67
|
+
column-gap: var(--theme-grid-gap);
|
|
68
|
+
align-items: start;
|
|
69
|
+
width: 100%;
|
|
70
|
+
padding-top: calc(var(--theme-grid-module) * 3);
|
|
71
|
+
color: var(--theme-text-muted);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.Header-Logo {
|
|
75
|
+
grid-column: 1 / 4;
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: flex-start;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.Header-LogoImage {
|
|
81
|
+
display: block;
|
|
82
|
+
height: calc(var(--theme-grid-module) * 5);
|
|
83
|
+
width: auto;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.Header_variant_cover .Header-LogoImage {
|
|
87
|
+
height: calc(var(--theme-grid-module) * 6);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.Header-DeckTitle {
|
|
91
|
+
grid-column: 7 / 12;
|
|
92
|
+
justify-self: stretch;
|
|
93
|
+
text-align: left;
|
|
94
|
+
color: inherit;
|
|
95
|
+
font-size: var(--theme-text-size-1);
|
|
96
|
+
line-height: var(--theme-text-line-1);
|
|
97
|
+
min-width: 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.Header-DeckTitle > span {
|
|
101
|
+
display: block;
|
|
102
|
+
overflow: hidden;
|
|
103
|
+
text-overflow: ellipsis;
|
|
104
|
+
white-space: nowrap;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.Header-Page {
|
|
108
|
+
grid-column: 12 / 13;
|
|
109
|
+
justify-self: end;
|
|
110
|
+
text-align: right;
|
|
111
|
+
color: inherit;
|
|
112
|
+
font-size: var(--theme-text-size-0);
|
|
113
|
+
line-height: var(--theme-text-line-0);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.Header_variant_cover .Header-DeckTitle,
|
|
117
|
+
.Header_variant_cover .Header-Page {
|
|
118
|
+
display: none;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.Header_inverted {
|
|
122
|
+
color: var(--theme-text-muted-on-contrast);
|
|
123
|
+
}
|
|
124
|
+
</style>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, type PropType } from 'vue'
|
|
3
|
+
import { createThemeMedia } from '../composables/theme-media.mjs'
|
|
4
|
+
import ImageRenderer from './ImageRenderer.vue'
|
|
5
|
+
|
|
6
|
+
type ImageFit = 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'
|
|
7
|
+
|
|
8
|
+
const props = defineProps({
|
|
9
|
+
src: {
|
|
10
|
+
type: String,
|
|
11
|
+
default: '',
|
|
12
|
+
},
|
|
13
|
+
alt: {
|
|
14
|
+
type: String,
|
|
15
|
+
default: '',
|
|
16
|
+
},
|
|
17
|
+
fit: {
|
|
18
|
+
type: String as PropType<ImageFit>,
|
|
19
|
+
default: 'cover',
|
|
20
|
+
},
|
|
21
|
+
position: {
|
|
22
|
+
type: String,
|
|
23
|
+
default: 'center',
|
|
24
|
+
},
|
|
25
|
+
anchor: {
|
|
26
|
+
type: String,
|
|
27
|
+
default: '',
|
|
28
|
+
},
|
|
29
|
+
x: {
|
|
30
|
+
type: [Number, String],
|
|
31
|
+
default: 0,
|
|
32
|
+
},
|
|
33
|
+
y: {
|
|
34
|
+
type: [Number, String],
|
|
35
|
+
default: 0,
|
|
36
|
+
},
|
|
37
|
+
zoom: {
|
|
38
|
+
type: [Number, String],
|
|
39
|
+
default: 1,
|
|
40
|
+
},
|
|
41
|
+
rotate: {
|
|
42
|
+
type: [Number, String],
|
|
43
|
+
default: 0,
|
|
44
|
+
},
|
|
45
|
+
color: {
|
|
46
|
+
type: String,
|
|
47
|
+
default: '',
|
|
48
|
+
},
|
|
49
|
+
opacity: {
|
|
50
|
+
type: [Number, String],
|
|
51
|
+
default: 1,
|
|
52
|
+
},
|
|
53
|
+
backgroundColor: {
|
|
54
|
+
type: String,
|
|
55
|
+
default: '',
|
|
56
|
+
},
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const media = createThemeMedia()
|
|
60
|
+
|
|
61
|
+
const layer = computed(() =>
|
|
62
|
+
media.resolveImage({
|
|
63
|
+
src: props.src,
|
|
64
|
+
alt: props.alt,
|
|
65
|
+
fit: props.fit,
|
|
66
|
+
position: props.position,
|
|
67
|
+
anchor: props.anchor,
|
|
68
|
+
x: props.x,
|
|
69
|
+
y: props.y,
|
|
70
|
+
zoom: props.zoom,
|
|
71
|
+
rotate: props.rotate,
|
|
72
|
+
color: props.color,
|
|
73
|
+
opacity: props.opacity,
|
|
74
|
+
backgroundColor: props.backgroundColor,
|
|
75
|
+
}, 'image'),
|
|
76
|
+
)
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<template>
|
|
80
|
+
<ImageRenderer v-if="layer"
|
|
81
|
+
:layer="layer" />
|
|
82
|
+
</template>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, type PropType } from 'vue'
|
|
3
|
+
|
|
4
|
+
type NormalizedImageData = {
|
|
5
|
+
src: string
|
|
6
|
+
fit: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'
|
|
7
|
+
position: string
|
|
8
|
+
anchor: string
|
|
9
|
+
x: string
|
|
10
|
+
y: string
|
|
11
|
+
zoom: number
|
|
12
|
+
rotate: string
|
|
13
|
+
color: string
|
|
14
|
+
opacity: number
|
|
15
|
+
backgroundColor: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type ThemeMediaLayer = {
|
|
19
|
+
image: NormalizedImageData
|
|
20
|
+
render: {
|
|
21
|
+
kind: 'img' | 'mask'
|
|
22
|
+
decorative: boolean
|
|
23
|
+
alt: string
|
|
24
|
+
cssVars: Record<string, string>
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const props = defineProps({
|
|
29
|
+
layer: {
|
|
30
|
+
type: Object as PropType<ThemeMediaLayer | null>,
|
|
31
|
+
default: null,
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const resolvedImage = computed(() => props.layer?.image ?? null)
|
|
36
|
+
|
|
37
|
+
const isMaskedDecor = computed(() => {
|
|
38
|
+
return props.layer?.render.kind === 'mask'
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const containerStyle = computed(() => {
|
|
42
|
+
if (props.layer)
|
|
43
|
+
return props.layer.render.cssVars
|
|
44
|
+
|
|
45
|
+
return {}
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const resolvedAlt = computed(() => props.layer?.render.alt ?? '')
|
|
49
|
+
const resolvedDecorative = computed(() => props.layer?.render.decorative ?? !resolvedAlt.value)
|
|
50
|
+
|
|
51
|
+
const imageRole = computed(() => {
|
|
52
|
+
if (resolvedDecorative.value || !resolvedAlt.value)
|
|
53
|
+
return undefined
|
|
54
|
+
|
|
55
|
+
return 'img'
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
const imageAriaLabel = computed(() => {
|
|
59
|
+
if (resolvedDecorative.value || !resolvedAlt.value)
|
|
60
|
+
return undefined
|
|
61
|
+
|
|
62
|
+
return resolvedAlt.value
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const imageAriaHidden = computed(() => {
|
|
66
|
+
return resolvedDecorative.value || !resolvedAlt.value ? 'true' : undefined
|
|
67
|
+
})
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<template>
|
|
71
|
+
<div v-if="resolvedImage" class="ImageRenderer" :style="containerStyle">
|
|
72
|
+
<div v-if="isMaskedDecor"
|
|
73
|
+
class="ImageRenderer-Decor"
|
|
74
|
+
:role="imageRole"
|
|
75
|
+
:aria-label="imageAriaLabel"
|
|
76
|
+
:aria-hidden="imageAriaHidden" />
|
|
77
|
+
<img v-else
|
|
78
|
+
:src="resolvedImage.src"
|
|
79
|
+
:alt="resolvedDecorative ? '' : resolvedAlt"
|
|
80
|
+
class="ImageRenderer-Asset"
|
|
81
|
+
:aria-hidden="imageAriaHidden" />
|
|
82
|
+
</div>
|
|
83
|
+
</template>
|
|
84
|
+
|
|
85
|
+
<style scoped>
|
|
86
|
+
.ImageRenderer {
|
|
87
|
+
position: relative;
|
|
88
|
+
display: block;
|
|
89
|
+
width: 100%;
|
|
90
|
+
height: 100%;
|
|
91
|
+
overflow: hidden;
|
|
92
|
+
border-radius: inherit;
|
|
93
|
+
background-color: var(--theme-image-background, transparent);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.ImageRenderer-Asset,
|
|
97
|
+
.ImageRenderer-Decor {
|
|
98
|
+
display: block;
|
|
99
|
+
width: 100%;
|
|
100
|
+
height: 100%;
|
|
101
|
+
border-radius: inherit;
|
|
102
|
+
opacity: var(--theme-image-opacity, 1);
|
|
103
|
+
transform:
|
|
104
|
+
translate(var(--theme-image-x, 0), var(--theme-image-y, 0))
|
|
105
|
+
rotate(var(--theme-image-rotate, 0deg))
|
|
106
|
+
scale(var(--theme-image-zoom, 1));
|
|
107
|
+
transform-origin: var(--theme-image-origin, center);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.ImageRenderer-Asset {
|
|
111
|
+
object-fit: var(--theme-image-fit, cover);
|
|
112
|
+
object-position: var(--theme-image-position, center);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.ImageRenderer-Decor {
|
|
116
|
+
background-color: var(--theme-image-color, currentColor);
|
|
117
|
+
mask-image: var(--theme-image-mask);
|
|
118
|
+
mask-repeat: no-repeat;
|
|
119
|
+
mask-position: var(--theme-image-position, center);
|
|
120
|
+
mask-size: var(--theme-image-mask-size, contain);
|
|
121
|
+
-webkit-mask-image: var(--theme-image-mask);
|
|
122
|
+
-webkit-mask-repeat: no-repeat;
|
|
123
|
+
-webkit-mask-position: var(--theme-image-position, center);
|
|
124
|
+
-webkit-mask-size: var(--theme-image-mask-size, contain);
|
|
125
|
+
}
|
|
126
|
+
</style>
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, useId } from 'vue'
|
|
3
|
+
import { shortLogoMarkPath, shortLogoMarkRectX, shortLogoMarkRadius, shortLogoMarkSize, shortLogoMarkTransform } from '../composables/logo-mark.mjs'
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
size: {
|
|
7
|
+
type: String as () => 'short' | 'full',
|
|
8
|
+
default: 'short',
|
|
9
|
+
},
|
|
10
|
+
title: {
|
|
11
|
+
type: String,
|
|
12
|
+
default: 'Theme logo',
|
|
13
|
+
},
|
|
14
|
+
background: {
|
|
15
|
+
type: String,
|
|
16
|
+
default: 'var(--theme-color-dark-0)',
|
|
17
|
+
},
|
|
18
|
+
foreground: {
|
|
19
|
+
type: String,
|
|
20
|
+
default: 'var(--theme-color-light-0)',
|
|
21
|
+
},
|
|
22
|
+
contrast: {
|
|
23
|
+
type: String,
|
|
24
|
+
default: 'var(--theme-color-light-0)',
|
|
25
|
+
},
|
|
26
|
+
favicon: {
|
|
27
|
+
type: Boolean,
|
|
28
|
+
default: false,
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const clipId = useId()
|
|
33
|
+
const isFull = computed(() => props.size === 'full')
|
|
34
|
+
const isFavicon = computed(() => !isFull.value && props.favicon)
|
|
35
|
+
const shortLogoStyle = computed(() => ({
|
|
36
|
+
'--theme-logo-short-background': props.background,
|
|
37
|
+
'--theme-logo-short-foreground': props.foreground,
|
|
38
|
+
}))
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<template>
|
|
42
|
+
<svg v-if="isFull"
|
|
43
|
+
width="330"
|
|
44
|
+
height="48"
|
|
45
|
+
viewBox="0 0 330 48"
|
|
46
|
+
fill="none"
|
|
47
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
48
|
+
class="Logo"
|
|
49
|
+
:style="{
|
|
50
|
+
'--theme-logo-full-foreground': props.foreground,
|
|
51
|
+
'--theme-logo-full-contrast': props.contrast,
|
|
52
|
+
}"
|
|
53
|
+
role="img"
|
|
54
|
+
:aria-label="props.title">
|
|
55
|
+
<title>{{ props.title }}</title>
|
|
56
|
+
<g :clip-path="`url(#${clipId})`">
|
|
57
|
+
<circle cx="23.0016" cy="23.0016" r="23.0016" fill="#FC3F1D" />
|
|
58
|
+
<path d="M26.242 36.8255H31.0475V9.22363H24.0577C17.0281 9.22363 13.3347 12.8377 13.3347 18.1595C13.3347 22.409 15.3601 24.911 18.9742 27.4925L12.6992 36.8255H17.9019L24.8917 26.3805L22.4691 24.7522C19.5302 22.7664 18.1005 21.2176 18.1005 17.8815C18.1005 14.9426 20.1656 12.9568 24.0974 12.9568H26.242V36.8255Z"
|
|
59
|
+
fill="white" />
|
|
60
|
+
</g>
|
|
61
|
+
<rect x="49.0703"
|
|
62
|
+
width="46.0032"
|
|
63
|
+
height="46.0032"
|
|
64
|
+
rx="17.2512"
|
|
65
|
+
fill="var(--theme-logo-full-foreground)" />
|
|
66
|
+
<path fill-rule="evenodd"
|
|
67
|
+
clip-rule="evenodd"
|
|
68
|
+
d="M72.9351 5.63477L72.9351 21.3443L85.7096 12.3995L86.6991 13.8127L73.7934 22.8493L88.0794 29.511L87.3504 31.0745L72.9359 24.3529V40.2527H71.2108V32.8571L69.9266 40.1402L68.2276 39.8406L70.0528 29.4897L65.6461 38.94L64.0826 38.2109L69.7354 26.0885L59.4119 34.7509L58.303 33.4293L69.4227 24.0989L54.9628 25.3639L54.8125 23.6454L69.9235 22.3234L58.3037 12.5732L59.4126 11.2517L71.21 21.151L71.21 5.63477H72.9351Z"
|
|
69
|
+
fill="var(--theme-logo-full-contrast)" />
|
|
70
|
+
<path fill-rule="evenodd"
|
|
71
|
+
clip-rule="evenodd"
|
|
72
|
+
d="M130.356 40.2752V5.63867H107.531V40.2752H113.561V10.3233H124.326V40.2752H130.356ZM141.102 18.4468C141.866 17.2175 142.813 16.2872 143.943 15.6559C145.105 15.0247 146.385 14.709 147.78 14.709C149.175 14.709 150.455 14.9914 151.617 15.5562C152.78 16.1211 153.777 16.9683 154.608 18.0979C155.438 19.1943 156.086 20.5565 156.551 22.1845C157.016 23.7793 157.249 25.6233 157.249 27.7164C157.249 29.8096 157 31.6701 156.501 33.2981C156.036 34.9261 155.372 36.3049 154.508 37.4346C153.677 38.531 152.647 39.3616 151.418 39.9264C150.222 40.4912 148.91 40.7736 147.481 40.7736C144.856 40.7736 142.78 39.6274 141.251 37.3349V47.5016H135.321V15.2074H140.803L141.102 18.4468ZM145.986 36.089C147.714 36.089 148.993 35.4245 149.823 34.0955C150.687 32.7665 151.119 30.6402 151.119 27.7164C151.119 24.7927 150.72 22.6829 149.923 21.3871C149.126 20.0582 147.913 19.3937 146.285 19.3937C144.624 19.3937 143.378 20.0249 142.547 21.2875C141.717 22.55 141.285 24.5767 141.251 27.3676V27.7663C141.251 30.69 141.633 32.8164 142.398 34.1454C143.195 35.4411 144.391 36.089 145.986 36.089ZM173.173 28.8626H174.021V34.2948C173.655 34.8597 173.123 35.3414 172.426 35.7401C171.728 36.1056 170.848 36.2883 169.784 36.2883C168.522 36.2883 167.575 35.9727 166.944 35.3414C166.346 34.6769 166.047 33.8131 166.047 32.7499C166.047 31.3212 166.595 30.3245 167.691 29.7597C168.788 29.1617 170.615 28.8626 173.173 28.8626ZM180.25 40.2753C180.051 38.2486 179.951 36.2053 179.951 34.1453V23.1812C179.951 20.1246 179.17 17.965 177.609 16.7025C176.08 15.4399 173.738 14.8087 170.582 14.8087C168.588 14.8087 166.844 15.0579 165.349 15.5562C163.854 16.0546 162.658 16.5696 161.761 17.1012V22.035C162.159 21.736 162.658 21.437 163.256 21.1379C163.887 20.8389 164.552 20.5731 165.249 20.3406C165.98 20.108 166.744 19.9252 167.542 19.7923C168.339 19.6262 169.12 19.5432 169.884 19.5432C171.313 19.5432 172.359 19.8256 173.024 20.3904C173.688 20.922 174.021 21.8689 174.021 23.2311V24.6265H173.074C168.522 24.6265 165.199 25.3408 163.106 26.7695C161.013 28.1649 159.967 30.1418 159.967 32.7001C159.967 35.2584 160.664 37.2186 162.06 38.5808C163.488 39.943 165.349 40.6241 167.641 40.6241C169.369 40.6241 170.681 40.3915 171.579 39.9264C172.476 39.428 173.207 38.8798 173.771 38.2818H174.021C174.054 38.614 174.104 38.9629 174.17 39.3284C174.27 39.6938 174.369 40.0095 174.469 40.2753H180.25ZM190.65 28.1651V40.2755H184.72V15.2076H190.65V26.9691L199.023 15.2076H205.003L196.631 26.9691L206.15 40.2755H199.422L190.65 28.1651ZM220.321 40.2755V19.8922H227.299V15.2076H207.414V19.8922H214.391V40.2755H220.321ZM236.541 15.2076V30.7566L245.612 15.2076H250.894V40.2755H245.163V24.7762L236.093 40.2755H230.81V15.2076H236.541ZM261.804 40.2755V28.1651L270.575 40.2755H277.303L267.784 26.9691L276.157 15.2076H270.176L261.804 26.9691V15.2076H255.873V40.2755H261.804ZM283.251 48.0002C282.653 48.0002 282.154 47.9503 281.756 47.8507C281.357 47.7842 281.025 47.7011 280.759 47.6015C280.46 47.4686 280.211 47.3191 280.011 47.1529V42.3188C280.676 42.9833 281.573 43.3155 282.702 43.3155C283.533 43.3155 284.198 43.1328 284.696 42.7673C285.194 42.4351 285.61 41.9699 285.942 41.3719L277.32 15.2076H283.55L289.082 34.0957L294.613 15.2076H300.345L292.52 38.9299C292.088 40.2256 291.623 41.4217 291.125 42.5181C290.626 43.6145 290.028 44.5614 289.331 45.3588C288.633 46.1894 287.786 46.8373 286.789 47.3025C285.826 47.7676 284.646 48.0002 283.251 48.0002ZM329.757 40.2755H323.976V21.5369L317.895 40.2755H313.061L307.629 21.5867V40.2755H302.596V15.2076H311.217L316.101 31.9029L321.534 15.2076H329.657L329.757 40.2755Z"
|
|
73
|
+
fill="var(--theme-logo-full-foreground)" />
|
|
74
|
+
<defs>
|
|
75
|
+
<clipPath :id="clipId">
|
|
76
|
+
<rect width="46.0032" height="46.0032" fill="white" />
|
|
77
|
+
</clipPath>
|
|
78
|
+
</defs>
|
|
79
|
+
</svg>
|
|
80
|
+
|
|
81
|
+
<svg v-else-if="isFavicon"
|
|
82
|
+
width="43"
|
|
83
|
+
height="43"
|
|
84
|
+
viewBox="0 0 43 43"
|
|
85
|
+
fill="none"
|
|
86
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
87
|
+
class="Logo"
|
|
88
|
+
:style="shortLogoStyle"
|
|
89
|
+
role="img"
|
|
90
|
+
:aria-label="props.title">
|
|
91
|
+
<title>{{ props.title }}</title>
|
|
92
|
+
<g :transform="shortLogoMarkTransform">
|
|
93
|
+
<rect :x="shortLogoMarkRectX"
|
|
94
|
+
:width="shortLogoMarkSize"
|
|
95
|
+
:height="shortLogoMarkSize"
|
|
96
|
+
:rx="shortLogoMarkRadius"
|
|
97
|
+
fill="var(--theme-logo-short-background)" />
|
|
98
|
+
<path fill-rule="evenodd"
|
|
99
|
+
clip-rule="evenodd"
|
|
100
|
+
:d="shortLogoMarkPath"
|
|
101
|
+
fill="var(--theme-logo-short-foreground)" />
|
|
102
|
+
</g>
|
|
103
|
+
</svg>
|
|
104
|
+
|
|
105
|
+
<svg v-else
|
|
106
|
+
width="89"
|
|
107
|
+
height="43"
|
|
108
|
+
viewBox="0 0 89 43"
|
|
109
|
+
fill="none"
|
|
110
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
111
|
+
class="Logo"
|
|
112
|
+
:style="shortLogoStyle"
|
|
113
|
+
role="img"
|
|
114
|
+
:aria-label="props.title">
|
|
115
|
+
<title>{{ props.title }}</title>
|
|
116
|
+
<g :clip-path="`url(#${clipId})`">
|
|
117
|
+
<circle cx="21.5" cy="21.5" r="21.5" fill="var(--theme-logo-short-background)" />
|
|
118
|
+
<path d="M24.5298 34.4211H29.0216V8.62109H22.4881C15.9174 8.62109 12.4651 11.9992 12.4651 16.9736C12.4651 20.9457 14.3583 23.2844 17.7364 25.6974L11.8711 34.4211H16.7341L23.2676 24.6579L21.0032 23.1359C18.2561 21.2798 16.9197 19.832 16.9197 16.7138C16.9197 13.9667 18.8501 12.1106 22.5252 12.1106H24.5298V34.4211Z"
|
|
119
|
+
fill="var(--theme-logo-short-foreground)" />
|
|
120
|
+
</g>
|
|
121
|
+
<rect :x="shortLogoMarkRectX"
|
|
122
|
+
:width="shortLogoMarkSize"
|
|
123
|
+
:height="shortLogoMarkSize"
|
|
124
|
+
:rx="shortLogoMarkRadius"
|
|
125
|
+
fill="var(--theme-logo-short-background)" />
|
|
126
|
+
<path fill-rule="evenodd"
|
|
127
|
+
clip-rule="evenodd"
|
|
128
|
+
:d="shortLogoMarkPath"
|
|
129
|
+
fill="var(--theme-logo-short-foreground)" />
|
|
130
|
+
<defs>
|
|
131
|
+
<clipPath :id="clipId">
|
|
132
|
+
<rect width="43" height="43" fill="white" />
|
|
133
|
+
</clipPath>
|
|
134
|
+
</defs>
|
|
135
|
+
</svg>
|
|
136
|
+
</template>
|
|
137
|
+
|
|
138
|
+
<style scoped>
|
|
139
|
+
.Logo {
|
|
140
|
+
display: block;
|
|
141
|
+
}
|
|
142
|
+
</style>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import Image from './Image.vue'
|
|
3
|
+
import Text from './Text.vue'
|
|
4
|
+
|
|
5
|
+
type PersonFlowAlign = 'start' | 'middle' | 'end'
|
|
6
|
+
|
|
7
|
+
const props = withDefaults(defineProps<{
|
|
8
|
+
name: string
|
|
9
|
+
title?: string
|
|
10
|
+
avatar?: string
|
|
11
|
+
avatarFit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'
|
|
12
|
+
avatarPosition?: string
|
|
13
|
+
avatarAnchor?: string
|
|
14
|
+
avatarX?: number | string
|
|
15
|
+
avatarY?: number | string
|
|
16
|
+
avatarZoom?: number | string
|
|
17
|
+
align?: PersonFlowAlign
|
|
18
|
+
}>(), {
|
|
19
|
+
title: '',
|
|
20
|
+
avatar: '',
|
|
21
|
+
avatarFit: 'cover',
|
|
22
|
+
avatarPosition: 'center',
|
|
23
|
+
avatarAnchor: '',
|
|
24
|
+
avatarX: 0,
|
|
25
|
+
avatarY: 0,
|
|
26
|
+
avatarZoom: 1,
|
|
27
|
+
align: 'start',
|
|
28
|
+
})
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<div class="Person"
|
|
33
|
+
:class="{
|
|
34
|
+
Person_align_start: props.align === 'start',
|
|
35
|
+
Person_align_middle: props.align === 'middle',
|
|
36
|
+
Person_align_end: props.align === 'end',
|
|
37
|
+
}">
|
|
38
|
+
<div v-if="props.avatar" class="Person-Avatar">
|
|
39
|
+
<Image :src="props.avatar"
|
|
40
|
+
:fit="props.avatarFit"
|
|
41
|
+
:position="props.avatarPosition"
|
|
42
|
+
:anchor="props.avatarAnchor"
|
|
43
|
+
:x="props.avatarX"
|
|
44
|
+
:y="props.avatarY"
|
|
45
|
+
:zoom="props.avatarZoom" />
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<div class="Person-Meta">
|
|
49
|
+
<Text size="3">{{ props.name }}</Text>
|
|
50
|
+
<Text v-if="props.title" size="1" color="text-muted">{{ props.title }}</Text>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<style scoped>
|
|
56
|
+
.Person {
|
|
57
|
+
display: flex;
|
|
58
|
+
align-items: start;
|
|
59
|
+
gap: calc(var(--theme-grid-module) * 2);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.Person_align_start {
|
|
63
|
+
margin-top: 0;
|
|
64
|
+
margin-bottom: 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.Person_align_middle {
|
|
68
|
+
margin-top: auto;
|
|
69
|
+
margin-bottom: auto;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.Person_align_end {
|
|
73
|
+
margin-top: auto;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.Person-Avatar {
|
|
77
|
+
flex: 0 0 var(--theme-cell-width);
|
|
78
|
+
width: var(--theme-cell-width);
|
|
79
|
+
height: var(--theme-cell-width);
|
|
80
|
+
overflow: hidden;
|
|
81
|
+
border-radius: var(--theme-panel-radius);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.Person-Meta {
|
|
85
|
+
display: flex;
|
|
86
|
+
flex-direction: column;
|
|
87
|
+
align-items: flex-start;
|
|
88
|
+
}
|
|
89
|
+
</style>
|