Skip to content

Commit e7a9995

Browse files
committed
Add "First-Class IDE Integration"
1 parent 48e7f3a commit e7a9995

File tree

8 files changed

+229
-3
lines changed

8 files changed

+229
-3
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<script setup lang="ts">
2+
const props = defineProps<{
3+
pluginId: string | number
4+
downloads?: number | null
5+
rating?: number | null
6+
}>()
7+
8+
const pluginUrl = `https://plugins.jetbrains.com/plugin/${props.pluginId}`
9+
10+
const formatDownloads = (num: number): string => {
11+
if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M'
12+
if (num >= 1000) return (num / 1000).toFixed(1) + 'K'
13+
return num.toString()
14+
}
15+
16+
const formatRating = (num: number): string => {
17+
return num.toFixed(1)
18+
}
19+
</script>
20+
21+
<template>
22+
<a :href="pluginUrl" target="_blank" rel="noopener" class="jb-plugin-button">
23+
<span class="jb-plugin-label">Get Plugin</span>
24+
<span v-if="rating || downloads" class="jb-plugin-stats">
25+
<span v-if="rating" class="jb-plugin-rating">
26+
<svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor">
27+
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
28+
</svg>
29+
{{ formatRating(rating) }}
30+
</span>
31+
<span v-if="downloads" class="jb-plugin-downloads visually-hidden">
32+
<svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor">
33+
<path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
34+
</svg>
35+
{{ formatDownloads(downloads) }}
36+
</span>
37+
</span>
38+
</a>
39+
</template>
40+
41+
<style scoped>
42+
.jb-plugin-button {
43+
display: inline-flex;
44+
align-items: center;
45+
gap: 12px;
46+
padding: 8px 16px;
47+
background: linear-gradient(135deg, #ff318c 0%, #fe7940 50%, #f5df36 100%);
48+
border-radius: 8px;
49+
text-decoration: none;
50+
color: #000;
51+
font-weight: 600;
52+
font-size: 14px;
53+
transition: all 0.2s ease;
54+
box-shadow: 0 2px 8px rgba(255, 49, 140, 0.3);
55+
}
56+
57+
.jb-plugin-button:hover {
58+
transform: translateY(-2px);
59+
color: #000;
60+
box-shadow: 0 4px 16px rgba(255, 49, 140, 0.4);
61+
}
62+
63+
.jb-plugin-stats {
64+
display: flex;
65+
gap: 10px;
66+
font-size: 12px;
67+
font-weight: 500;
68+
opacity: 0.85;
69+
}
70+
71+
.jb-plugin-rating,
72+
.jb-plugin-downloads {
73+
display: flex;
74+
align-items: center;
75+
gap: 3px;
76+
}
77+
</style>

.vitepress/theme/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import DefaultTheme from 'vitepress/theme'
44
import BlogSponsor from './BlogSponsor.vue'
55
import GitHubStars from './GitHubStars.vue'
66
import CodeTabs from './CodeTabs.vue'
7+
import JetBrainsPluginButton from './JetBrainsPluginButton.vue'
78
import './style.css'
89

910
export default {
@@ -16,5 +17,6 @@ export default {
1617
},
1718
enhanceApp({ app }) {
1819
app.component('CodeTabs', CodeTabs)
20+
app.component('JetBrainsPluginButton', JetBrainsPluginButton)
1921
},
2022
} satisfies Theme
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
const PLUGIN_ID = 28842
2+
3+
export default {
4+
async load() {
5+
try {
6+
const [pluginRes, ratingRes] = await Promise.all([
7+
fetch(`https://plugins.jetbrains.com/api/plugins/${PLUGIN_ID}`),
8+
fetch(`https://plugins.jetbrains.com/api/plugins/${PLUGIN_ID}/rating`)
9+
])
10+
11+
let downloads = null
12+
let rating = null
13+
14+
if (pluginRes.ok) {
15+
const pluginData = await pluginRes.json()
16+
downloads = pluginData.downloads
17+
}
18+
19+
if (ratingRes.ok) {
20+
const ratingData = await ratingRes.json()
21+
rating = ratingData.meanRating
22+
}
23+
24+
return {
25+
pluginId: PLUGIN_ID,
26+
downloads,
27+
rating
28+
}
29+
} catch (e) {
30+
console.warn('Could not fetch JetBrains plugin stats:', e)
31+
return {
32+
pluginId: PLUGIN_ID,
33+
downloads: null,
34+
rating: null
35+
}
36+
}
37+
}
38+
}

.vitepress/theme/style.css

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@
253253
align-items: flex-start;
254254
}
255255

256+
.home-feature-row-reverse {
257+
flex-direction: row-reverse;
258+
}
259+
256260
.home-feature-text {
257261
flex: 2;
258262
text-align: left;
@@ -297,6 +301,48 @@
297301
min-width: 0;
298302
}
299303

304+
.home-feature-image {
305+
flex: 3;
306+
min-width: 0;
307+
}
308+
309+
.home-feature-image :deep(img) {
310+
width: 100%;
311+
border-radius: 12px;
312+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
313+
}
314+
315+
/* Background image with gradient fade */
316+
.home-feature-bg-image {
317+
flex: 3;
318+
min-width: 0;
319+
position: relative;
320+
min-height: 300px;
321+
border-radius: 12px;
322+
overflow: hidden;
323+
}
324+
325+
.home-feature-bg-image::before {
326+
content: '';
327+
position: absolute;
328+
inset: 0;
329+
background-image: var(--bg-image-light);
330+
background-size: cover;
331+
background-position: left top;
332+
mask-image: linear-gradient(to right, black 60%, transparent 100%);
333+
-webkit-mask-image: linear-gradient(to right, black 60%, transparent 100%);
334+
}
335+
336+
.dark .home-feature-bg-image::before {
337+
background-image: var(--bg-image-dark);
338+
}
339+
340+
/* Reverse: gradient goes left */
341+
.home-feature-row-reverse .home-feature-bg-image::before {
342+
mask-image: linear-gradient(to left, black 60%, transparent 100%);
343+
-webkit-mask-image: linear-gradient(to left, black 60%, transparent 100%);
344+
}
345+
300346
.home-feature-code .code-tabs-ide {
301347
margin: 0;
302348
width: 100%;
@@ -309,8 +355,15 @@
309355
}
310356

311357
.home-feature-text,
312-
.home-feature-code {
358+
.home-feature-code,
359+
.home-feature-image,
360+
.home-feature-bg-image {
313361
flex: none;
314362
width: 100%;
315363
}
364+
365+
.home-feature-bg-image::before {
366+
mask-image: none;
367+
-webkit-mask-image: none;
368+
}
316369
}

index.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ features:
3737
---
3838

3939
<script setup>
40+
import { data as jbPlugin } from './.vitepress/theme/jetbrains-plugin.data'
41+
42+
const ideScreenshot = {
43+
light: '/images/ide-screenshot-light.jpg',
44+
dark: '/images/ide-screenshot-dark.jpg'
45+
}
46+
4047
const assertTabs = [
4148
{ name: 'Assert.php', slot: 'assert', icon: 'testo' },
4249
{ name: 'Expect.php', slot: 'expect', icon: 'testo' },
@@ -147,7 +154,7 @@ public function testInvalidInput(): void
147154

148155
## Multiple Ways to Declare Tests
149156

150-
<div class="home-feature-row home-feature-row-reverse">
157+
<div class="home-feature-row">
151158
<div class="home-feature-text">
152159

153160
Write tests the way that fits your style.
@@ -245,6 +252,27 @@ final class Calculator
245252
</div>
246253
</div>
247254

255+
<div class="home-feature">
256+
257+
## First-Class IDE Integration
258+
259+
<div class="home-feature-row">
260+
<div
261+
class="home-feature-bg-image"
262+
:style="{ '--bg-image-light': `url(${ideScreenshot.light})`, '--bg-image-dark': `url(${ideScreenshot.dark})` }"
263+
></div>
264+
<div class="home-feature-text">
265+
266+
Native plugin for PhpStorm and IntelliJ IDEA.
267+
268+
Full-featured workflow: run and re-run from gutter icons, navigation between tests and code, debugging with breakpoints, test generation, results tree.
269+
270+
<JetBrainsPluginButton :pluginId="jbPlugin.pluginId" :downloads="jbPlugin.downloads" :rating="jbPlugin.rating" />
271+
272+
</div>
273+
</div>
274+
</div>
275+
248276
<div class="sponsors-section">
249277
<h2 class="sponsors-title">Sponsored by</h2>
250278
<div class="sponsors-grid">
647 KB
Loading
745 KB
Loading

ru/index.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ features:
3737
---
3838

3939
<script setup>
40+
import { data as jbPlugin } from '../.vitepress/theme/jetbrains-plugin.data'
41+
42+
const ideScreenshot = {
43+
light: '/images/ide-screenshot-light.jpg',
44+
dark: '/images/ide-screenshot-dark.jpg'
45+
}
46+
4047
const assertTabs = [
4148
{ name: 'Assert.php', slot: 'assert', icon: 'testo' },
4249
{ name: 'Expect.php', slot: 'expect', icon: 'testo' },
@@ -147,7 +154,7 @@ public function testInvalidInput(): void
147154

148155
## Разные способы объявления тестов
149156

150-
<div class="home-feature-row home-feature-row-reverse">
157+
<div class="home-feature-row">
151158
<div class="home-feature-text">
152159

153160
Пишите тесты так, как удобно вам.
@@ -245,6 +252,27 @@ final class Calculator
245252
</div>
246253
</div>
247254

255+
<div class="home-feature">
256+
257+
## Полноценная интеграция с IDE
258+
259+
<div class="home-feature-row">
260+
<div
261+
class="home-feature-bg-image"
262+
:style="{ '--bg-image-light': `url(${ideScreenshot.light})`, '--bg-image-dark': `url(${ideScreenshot.dark})` }"
263+
></div>
264+
<div class="home-feature-text">
265+
266+
Нативный плагин для PhpStorm и IntelliJ IDEA.
267+
268+
Весь привычный функционал: запуск и перезапуск из gutter-иконок, навигация между тестами и кодом, отладка с брейкпоинтами, генерация тестов, дерево результатов.
269+
270+
<JetBrainsPluginButton :pluginId="jbPlugin.pluginId" :downloads="jbPlugin.downloads" :rating="jbPlugin.rating" />
271+
272+
</div>
273+
</div>
274+
</div>
275+
248276
<div class="sponsors-section">
249277
<h2 class="sponsors-title">Спонсоры</h2>
250278
<div class="sponsors-grid">

0 commit comments

Comments
 (0)