@eox/pages-theme-eox 0.3.2 → 0.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eox/pages-theme-eox",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Vitepress Theme with EOX branding",
6
6
  "main": "src/index.js",
@@ -11,6 +11,7 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "@eox/eslint-config": "^2.0.0",
14
+ "@eox/ui": "^0.1.9",
14
15
  "vitepress": "^1.6.3"
15
16
  }
16
17
  }
package/src/Layout.vue ADDED
@@ -0,0 +1,262 @@
1
+ <template>
2
+ <Layout :class="`layout-${frontmatter.layout}`">
3
+ <!-- <main class="responsive"> -->
4
+ <template #layout-top>
5
+ <slot name="layout-top"></slot>
6
+ <div class="top-nav at-top row center-align">
7
+ <nav class="large-padding no-margin center-align nav-mobile">
8
+ <a href="/">
9
+ <img
10
+ :src="theme.logo"
11
+ :alt="`${theme.siteTitle} logo`"
12
+ class="logo"
13
+ />
14
+ </a>
15
+ <div class="max"></div>
16
+ <button data-ui="#mobile-menu" class="circle transparent">
17
+ <i class="mdi mdi-menu"></i>
18
+ </button>
19
+ <dialog id="mobile-menu" class="max">
20
+ <nav>
21
+ <a data-ui="#mobile-menu" href="/">
22
+ <img
23
+ :src="theme.logo"
24
+ :alt="`${theme.siteTitle} logo`"
25
+ class="logo margin"
26
+ />
27
+ </a>
28
+ <div class="max"></div>
29
+ <button data-ui="#mobile-menu" class="circle transparent">
30
+ <i class="mdi mdi-close primary-text"></i>
31
+ </button>
32
+ </nav>
33
+ <ul class="list border large-space">
34
+ <li v-for="item in theme.nav">
35
+ <a
36
+ data-ui="#mobile-menu"
37
+ :href="item.link"
38
+ class="primary-text"
39
+ >{{ item.text }}</a
40
+ >
41
+ </li>
42
+ </ul>
43
+ </dialog>
44
+ </nav>
45
+ <nav
46
+ class="large-padding no-margin center-align row holder nav-desktop"
47
+ >
48
+ <a href="/">
49
+ <img
50
+ :src="theme.logo"
51
+ :alt="`${theme.siteTitle} logo`"
52
+ class="logo"
53
+ />
54
+ </a>
55
+ <div class="space"></div>
56
+ <nav>
57
+ <ul class="left-align no-margin">
58
+ <li v-for="item in theme.nav">
59
+ <a :href="item.link">{{ item.text }}</a>
60
+ </li>
61
+ </ul>
62
+ </nav>
63
+ <div class="max"></div>
64
+ <a class="button text right-align" href="">
65
+ <span>Contact sales</span>
66
+ <i class="mdi mdi-arrow-right"></i>
67
+ </a>
68
+ <a class="button right-align" href="">
69
+ <span>Log in</span>
70
+ <i class="mdi mdi-arrow-right"></i>
71
+ </a>
72
+ </nav>
73
+ </div>
74
+ <header v-if="frontmatter.hero" class="primary center-align">
75
+ <img
76
+ v-if="frontmatter.hero.image"
77
+ class="background-image"
78
+ :src="frontmatter.hero.image.src"
79
+ />
80
+ <h1 class="large bold" style="font-size: clamp(4rem, 5vw, 94px)">
81
+ {{ frontmatter.hero.text }}
82
+ </h1>
83
+ <p>{{ frontmatter.hero.tagline }}</p>
84
+ <div>
85
+ <a
86
+ v-for="action in frontmatter.hero.actions"
87
+ :href="action.link"
88
+ class="button large medium-elevate cta"
89
+ :class="action.theme"
90
+ >
91
+ <span>{{ action.text }}</span>
92
+ <i class="mdi mdi-arrow-right"></i>
93
+ </a>
94
+ </div>
95
+ </header>
96
+ </template>
97
+ <template #layout-bottom>
98
+ <footer class="surface row center-align">
99
+ <div class="holder">
100
+ <div class="">
101
+ <nav class="padding right-align">
102
+ <img
103
+ :src="theme.logo"
104
+ :alt="`${theme.siteTitle} logo`"
105
+ class="logo"
106
+ />
107
+ <ul>
108
+ <li v-for="item in theme.nav">
109
+ <a :href="item.link">{{ item.text }}</a>
110
+ </li>
111
+ </ul>
112
+ </nav>
113
+ </div>
114
+ <nav class="padding">
115
+ <span v-html="theme.footer.copyright"></span>
116
+ <a href="https://eox.at/impressum" target="_blank">About & Terms</a>
117
+ <a href="https://eox.at/privacy-notice" target="_blank">Privacy</a>
118
+ </nav>
119
+ </div>
120
+ </footer>
121
+ <slot name="layout-bottom"></slot>
122
+ </template>
123
+ <!-- </main> -->
124
+ </Layout>
125
+ <!-- <main class="responsive">
126
+
127
+ </main> -->
128
+ </template>
129
+
130
+ <script setup>
131
+ import DefaultTheme from "vitepress/theme";
132
+ const { Layout } = DefaultTheme;
133
+ import { useData } from "vitepress";
134
+ const { frontmatter, theme } = useData();
135
+ // import FeatureSection from "./components/FeatureSection.vue";
136
+ const scrollListener = () => {
137
+ const nav = document.querySelector(".top-nav");
138
+ // if (window.scrollY > nav.clientHeight) {
139
+ // nav.classList.add("hidden")
140
+ // nav.classList.add("sticky")
141
+ // } else {
142
+ // nav.classList.remove("hidden")
143
+ // }
144
+ if (window.scrollY > window.innerHeight) {
145
+ nav.classList.remove("at-top");
146
+ } else {
147
+ nav.classList.add("at-top");
148
+ }
149
+ };
150
+ window.addEventListener("scroll", scrollListener);
151
+ </script>
152
+
153
+ <style>
154
+ .top-nav {
155
+ position: sticky;
156
+ z-index: 1;
157
+ top: 0;
158
+ background: var(--surface);
159
+ box-shadow: var(--elevate2);
160
+ display: flex;
161
+ width: 100%;
162
+ transition: all 0.3s ease-in-out;
163
+ }
164
+ .top-nav.at-top {
165
+ box-shadow: none;
166
+ }
167
+ .Layout.layout-home .top-nav.at-top {
168
+ background: transparent;
169
+ color: #f7f8f8;
170
+ }
171
+ .Layout.layout-home .top-nav.at-top nav .button {
172
+ color: #00060a;
173
+ background: var(--surface);
174
+ }
175
+ .Layout.layout-home .top-nav.at-top nav .button.text {
176
+ color: #f7f8f8;
177
+ background: none;
178
+ }
179
+ .Layout.layout-home .top-nav.at-top nav > a > .logo {
180
+ filter: brightness(0) invert(1);
181
+ }
182
+ img.logo {
183
+ height: 32px;
184
+ }
185
+ nav.nav-mobile {
186
+ display: flex;
187
+ }
188
+ nav.nav-desktop {
189
+ display: none;
190
+ }
191
+ @media (min-width: 768px) {
192
+ nav.nav-mobile {
193
+ display: none;
194
+ }
195
+ nav.nav-desktop {
196
+ display: flex;
197
+ }
198
+ }
199
+ header {
200
+ margin-top: calc(var(--vp-nav-height) * -1);
201
+ background: radial-gradient(
202
+ 74.48% 130.95% at 50% -12.27%,
203
+ #0f9bff 0%,
204
+ #004170 60%,
205
+ #000c14 100%
206
+ );
207
+ height: 100svh;
208
+ padding: 0 6rem !important;
209
+ }
210
+ @media (max-width: 1024px) {
211
+ header {
212
+ padding: 0 1.5rem !important;
213
+ }
214
+ header h1.large {
215
+ font-size: 3rem;
216
+ }
217
+ }
218
+ header > img.background-image {
219
+ position: absolute;
220
+ width: 100%;
221
+ height: 100%;
222
+ top: 0;
223
+ left: 0;
224
+ object-fit: cover;
225
+ opacity: 0.4;
226
+ }
227
+ header > h1 {
228
+ margin-bottom: 24px;
229
+ }
230
+ header > p {
231
+ font-size: 1.2rem;
232
+ margin-bottom: 40px;
233
+ }
234
+ header .cta.brand {
235
+ background-color: #f7f8f8;
236
+ color: #00060a;
237
+ }
238
+ header .cta.alt {
239
+ background-color: #002742;
240
+ color: #f7f8f8;
241
+ }
242
+ footer {
243
+ padding: 0;
244
+ }
245
+ .top-nav > .holder,
246
+ footer > .holder {
247
+ width: 100%;
248
+ max-width: 1400px;
249
+ }
250
+ footer nav {
251
+ display: flex;
252
+ flex-direction: column;
253
+ }
254
+ footer nav > ul {
255
+ margin: 0;
256
+ }
257
+ @media (min-width: 768px) {
258
+ footer nav {
259
+ flex-direction: row;
260
+ }
261
+ }
262
+ </style>
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <section
3
+ :class="`feature-section full-width ${landing === undefined ? '' : 'landing'}`"
4
+ >
5
+ <div class="holder">
6
+ <div class="text">
7
+ <nav class="primary-text">
8
+ <i :class="`mdi ${icon}`"></i>
9
+ {{ title }}
10
+ </nav>
11
+ <h5 :class="`title primary-text large`">{{ tagline }}</h5>
12
+ <p><slot></slot></p>
13
+ <nav>
14
+ <a :href="link" :class="`button primary medium-elevate`">
15
+ <span>{{ button || `Read more about ${title}` }}</span>
16
+ <i class="mdi mdi-arrow-right"></i>
17
+ </a>
18
+ <a v-if="landing === undefined" href="#" class="button border">
19
+ <span>Contact sales</span>
20
+ <i class="mdi mdi-arrow-right"></i>
21
+ </a>
22
+ </nav>
23
+ </div>
24
+ <img :src="image" :alt="title" />
25
+ </div>
26
+ </section>
27
+ </template>
28
+
29
+ <script setup>
30
+ import { defineProps } from "vue";
31
+ const props = defineProps([
32
+ "button",
33
+ "icon",
34
+ "image",
35
+ "landing",
36
+ "link",
37
+ "tagline",
38
+ "title",
39
+ ]);
40
+ </script>
package/src/index.js CHANGED
@@ -1,8 +1,19 @@
1
1
  import DefaultTheme from "vitepress/theme";
2
+ import Layout from "./Layout.vue";
3
+ import "@eox/ui";
4
+ import "./style.css";
2
5
 
3
6
  export default {
4
7
  extends: DefaultTheme,
5
- enhanceApp({ router, siteData }) {
8
+ Layout,
9
+ enhanceApp({ app, router, siteData }) {
10
+ const modules = import.meta.glob("./components/*.vue");
11
+ for (const path in modules) {
12
+ modules[path]().then((mod) => {
13
+ app.component(path.split("/")[2].replace(".vue", ""), mod.default);
14
+ });
15
+ }
16
+
6
17
  router.onAfterRouteChanged = () => {
7
18
  if (!import.meta.env.SSR) {
8
19
  window.scrollTo(0, 0);
package/src/style.css ADDED
@@ -0,0 +1,227 @@
1
+ @import "@eox/ui/style.css";
2
+
3
+ :root {
4
+ --vp-nav-height: 88px;
5
+ }
6
+
7
+ body {
8
+ margin: 0;
9
+ font-size: 1rem;
10
+ }
11
+
12
+ .VPNav,
13
+ .VPHero,
14
+ .VPHomeHero,
15
+ .VPFooter {
16
+ display: none;
17
+ }
18
+
19
+ .VPContent.is-home {
20
+ padding-top: 0;
21
+ margin-top: 0;
22
+ }
23
+
24
+ .vp-doc a.button {
25
+ text-decoration: none;
26
+ }
27
+
28
+ .vp-doc h1.large,
29
+ .vp-doc h2.large,
30
+ .vp-doc h3.large {
31
+ font-size: normal;
32
+ font-weight: normal;
33
+ line-height: normal;
34
+ border-top: none;
35
+ }
36
+
37
+ *:has(> nav.top:not(.s, .m, .l)) {
38
+ padding-block-start: 0;
39
+ }
40
+
41
+ @media (min-width: 960px) {
42
+ .VPPage {
43
+ width: 100%;
44
+ padding: 48px 64px;
45
+ }
46
+ }
47
+
48
+ @media (min-width: 640px) {
49
+ .VPPage {
50
+ padding: 48px 48px;
51
+ }
52
+ }
53
+
54
+ .VPPage {
55
+ margin: auto;
56
+ width: 100%;
57
+ max-width: 1280px;
58
+ padding: 48px 24px;
59
+ }
60
+
61
+ /**/
62
+ button.text,
63
+ .button.text,
64
+ button.text:hover,
65
+ .button.text:hover {
66
+ background: none;
67
+ color: var(--primary);
68
+ box-shadow: none;
69
+ }
70
+
71
+ /* Feature sections */
72
+ .full-width {
73
+ width: 100svw;
74
+ position: relative;
75
+ left: 50%;
76
+ right: 50%;
77
+ margin-left: -50svw;
78
+ margin-right: -50svw;
79
+ max-inline-size: unset;
80
+ }
81
+ .feature-section {
82
+ padding: 0px;
83
+ display: flex;
84
+ justify-content: center;
85
+ }
86
+ .feature-section .holder {
87
+ display: flex;
88
+ flex-direction: column;
89
+ align-items: center;
90
+ justify-content: space-between;
91
+ padding: 32px 0;
92
+ max-width: 1400px;
93
+ }
94
+ .feature-section.landing .holder {
95
+ background: var(--surface-container-low);
96
+ }
97
+ .feature-section.dark .holder {
98
+ background: radial-gradient(
99
+ farthest-corner at 100% 100%,
100
+ #0f9bff 0%,
101
+ #004170 60%,
102
+ #000c14 100%
103
+ );
104
+ color: #fff;
105
+ }
106
+ .feature-section nav {
107
+ margin: 32px 0 0 0;
108
+ }
109
+ .feature-section.dark button {
110
+ background: #f7f8f8;
111
+ color: #00060a;
112
+ }
113
+ .feature-section .text {
114
+ padding: 48px;
115
+ }
116
+ .feature-section .icon {
117
+ background: #61616133;
118
+ padding: 16px;
119
+ margin-bottom: 24px;
120
+ }
121
+ .feature-section.dark .icon {
122
+ background: #fff3;
123
+ }
124
+ .feature-section .title {
125
+ margin-top: 2rem;
126
+ margin-bottom: 2rem;
127
+ }
128
+ .feature-section img {
129
+ max-width: 80%;
130
+ border-radius: 8px;
131
+ background: var(--surface-bright);
132
+ box-shadow: 0px 11px 15px 0px #00000033;
133
+ }
134
+ @media (min-width: 1024px) {
135
+ .feature-section {
136
+ padding: 64px;
137
+ padding: clamp(64px, 10%, 128px);
138
+ }
139
+ .feature-section:not(.feature-section.landing) {
140
+ padding-top: 0;
141
+ }
142
+ .feature-section .holder {
143
+ flex-direction: row;
144
+ padding: 68px 0;
145
+ border-radius: 12px;
146
+ }
147
+ .feature-section img {
148
+ max-width: 60%;
149
+ transform: translateX(10%);
150
+ }
151
+ .feature-section.reverse.dark .holder {
152
+ background: radial-gradient(
153
+ farthest-corner at 0% 100%,
154
+ #0f9bff 0%,
155
+ #004170 60%,
156
+ #000c14 100%
157
+ );
158
+ }
159
+ .feature-section.reverse .text {
160
+ order: 1;
161
+ }
162
+ .text:not(.feature-section.landing) .text {
163
+ padding: 0;
164
+ }
165
+ .feature-section.reverse img {
166
+ transform: translateX(-10%);
167
+ order: 0;
168
+ }
169
+ }
170
+ @media (min-width: 1280px) {
171
+ .feature-section {
172
+ padding: 128px;
173
+ }
174
+ .feature-section .holder {
175
+ flex-direction: row;
176
+ padding: 68px 0;
177
+ }
178
+ .feature-section img {
179
+ order: 1;
180
+ max-width: 60%;
181
+ transform: translateX(10%);
182
+ }
183
+ }
184
+
185
+ /* slide/fade in images on scroll */
186
+ @media (min-width: 1024px) {
187
+ @media (prefers-reduced-motion: no-preference) {
188
+ @supports (animation-timeline: view()) {
189
+ @keyframes slide-in {
190
+ 0% {
191
+ opacity: 0;
192
+ transform: translateX(0);
193
+ }
194
+ 100% {
195
+ opacity: 1;
196
+ transform: translateX(10%);
197
+ }
198
+ }
199
+ @keyframes slide-in-reverse {
200
+ 0% {
201
+ opacity: 0;
202
+ transform: translateX(10%);
203
+ }
204
+ 100% {
205
+ opacity: 1;
206
+ transform: translateX(-10%);
207
+ }
208
+ }
209
+ .feature-section img {
210
+ --range-start: entry 0%;
211
+ --range-end: entry 150%;
212
+
213
+ animation: slide-in ease;
214
+ animation-timeline: view(block);
215
+ animation-range: var(--range-start) var(--range-end);
216
+ }
217
+ .feature-section.reverse img {
218
+ --range-start: entry 0%;
219
+ --range-end: entry 150%;
220
+
221
+ animation: slide-in-reverse ease;
222
+ animation-timeline: view(block);
223
+ animation-range: var(--range-start) var(--range-end);
224
+ }
225
+ }
226
+ }
227
+ }