Skip to content

Commit bc7fe55

Browse files
author
Dobromir Hristov
authored
Add view in source link to Documentation pages (#366)
closes rdar://95613947
1 parent 2db9e23 commit bc7fe55

File tree

12 files changed

+177
-8
lines changed

12 files changed

+177
-8
lines changed

src/components/DocumentationTopic.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
v-if="primaryContentSections && primaryContentSections.length"
6666
:class="{ 'with-border': !enhanceBackground }"
6767
:conformance="conformance"
68+
:source="remoteSource"
6869
:sections="primaryContentSections"
6970
/>
7071
</div>
@@ -265,6 +266,10 @@ export default {
265266
type: String,
266267
default: '',
267268
},
269+
remoteSource: {
270+
type: Object,
271+
required: false,
272+
},
268273
},
269274
provide() {
270275
// NOTE: this is not reactive: if this.references change, the provided value

src/components/DocumentationTopic/PrimaryContent.vue

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ export default {
6666
type: Object,
6767
required: false,
6868
},
69+
source: {
70+
type: Object,
71+
required: false,
72+
},
6973
sections: {
7074
type: Array,
7175
required: true,
@@ -101,7 +105,10 @@ export default {
101105
}[section.kind];
102106
},
103107
propsFor(section) {
104-
const { conformance } = this;
108+
const {
109+
conformance,
110+
source,
111+
} = this;
105112
const {
106113
bodyContentType,
107114
content,
@@ -117,7 +124,7 @@ export default {
117124
} = section;
118125
return {
119126
[SectionKind.content]: { content },
120-
[SectionKind.declarations]: { conformance, declarations },
127+
[SectionKind.declarations]: { conformance, source, declarations },
121128
[SectionKind.details]: { details },
122129
[SectionKind.parameters]: { parameters },
123130
[SectionKind.possibleValues]: { values },

src/components/DocumentationTopic/PrimaryContent/Declaration.vue

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232
:changeType="changeType"
3333
/>
3434
</template>
35+
<DeclarationSourceLink
36+
v-if="source"
37+
:url="source.url"
38+
:fileName="source.fileName"
39+
/>
3540
<ConditionalConstraints
3641
v-if="conformance"
3742
:constraints="conformance.constraints"
@@ -47,6 +52,7 @@ import OnThisPageSection from 'docc-render/components/DocumentationTopic/OnThisP
4752
import DeclarationGroup from 'docc-render/components/DocumentationTopic/PrimaryContent/DeclarationGroup.vue';
4853
import DeclarationDiff
4954
from 'docc-render/components/DocumentationTopic/PrimaryContent/DeclarationDiff.vue';
55+
import DeclarationSourceLink from 'docc-render/components/DocumentationTopic/PrimaryContent/DeclarationSourceLink.vue';
5056
5157
import { ChangeTypes } from 'docc-render/constants/Changes';
5258
import { multipleLinesClass } from 'docc-render/constants/multipleLines';
@@ -56,6 +62,7 @@ export default {
5662
components: {
5763
DeclarationDiff,
5864
DeclarationGroup,
65+
DeclarationSourceLink,
5966
ConditionalConstraints,
6067
OnThisPageSection,
6168
},
@@ -70,6 +77,10 @@ export default {
7077
type: Object,
7178
required: false,
7279
},
80+
source: {
81+
type: Object,
82+
required: false,
83+
},
7384
declarations: {
7485
type: Array,
7586
required: true,
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<!--
2+
This source file is part of the Swift.org open source project
3+
4+
Copyright (c) 2022 Apple Inc. and the Swift project authors
5+
Licensed under Apache License v2.0 with Runtime Library Exception
6+
7+
See https://swift.org/LICENSE.txt for license information
8+
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
-->
10+
11+
<template>
12+
<a
13+
:href="url"
14+
:title="`Open source file for ${fileName}`"
15+
target="_blank"
16+
class="declaration-source-link"
17+
>
18+
<SwiftFileIcon v-if="isSwiftFile" class="declaration-icon" />
19+
<WordBreak>{{ fileName }}</WordBreak>
20+
</a>
21+
</template>
22+
23+
<script>
24+
import SwiftFileIcon from 'docc-render/components/Icons/SwiftFileIcon.vue';
25+
import WordBreak from 'docc-render/components/WordBreak.vue';
26+
27+
export default {
28+
name: 'DeclarationSourceLink',
29+
components: { WordBreak, SwiftFileIcon },
30+
props: {
31+
url: {
32+
type: String,
33+
required: true,
34+
},
35+
fileName: {
36+
type: String,
37+
required: true,
38+
},
39+
},
40+
computed: {
41+
isSwiftFile: ({ fileName }) => fileName.endsWith('.swift'),
42+
},
43+
};
44+
</script>
45+
46+
<style scoped lang="scss">
47+
@import 'docc-render/styles/_core.scss';
48+
49+
.declaration-source-link {
50+
@include font-styles(body-reduced-tight);
51+
display: flex;
52+
align-items: center;
53+
// nudge up, so its closer to the declaration source
54+
margin-top: -4px;
55+
}
56+
57+
.declaration-icon {
58+
width: 1em;
59+
margin-right: 5px;
60+
}
61+
</style>

src/components/Icons/SwiftFileIcon.vue

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@
1111
<template>
1212
<SVGIcon
1313
class="swift-file-icon"
14-
viewBox="0 0 14 14"
14+
viewBox="0 0 15 14"
1515
>
16-
<path d="M8.033 1l3.967 4.015v7.985h-10v-12zM7.615 2h-4.615v10h8v-6.574z"></path>
17-
<path d="M7 1h1v4h-1z"></path>
18-
<path d="M7 5h5v1h-5z"></path>
16+
<path
17+
d="M14.93,13.56A2.15,2.15,0,0,0,15,13a5.37,5.37,0,0,0-1.27-3.24A6.08,6.08,0,0,0,14,7.91,9.32,9.32,0,0,0,9.21.31a8.51,8.51,0,0,1,1.78,5,6.4,6.4,0,0,1-.41,2.18A45.06,45.06,0,0,1,3.25,1.54,44.57,44.57,0,0,0,7.54,6.9,45.32,45.32,0,0,1,1.47,2.32,35.69,35.69,0,0,0,8.56,9.94a6.06,6.06,0,0,1-3.26.85A9.48,9.48,0,0,1,0,8.91a10,10,0,0,0,8.1,4.72c2.55,0,3.25-1.2,4.72-1.2a2.09,2.09,0,0,1,1.91,1.15C14.79,13.69,14.88,13.75,14.93,13.56Z" />
1918
</SVGIcon>
2019
</template>
2120

@@ -27,3 +26,12 @@ export default {
2726
components: { SVGIcon },
2827
};
2928
</script>
29+
<style scoped lang="scss">
30+
@import 'docc-render/styles/_core.scss';
31+
32+
.swift-file-icon {
33+
&.file-icon {
34+
height: 1rem;
35+
}
36+
}
37+
</style>

src/styles/core/typography/_font-styles.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ $font-styles: (
153153
documentation-figcaption: (
154154
large: 14_21,
155155
),
156+
documentation-declaration-link: (
157+
large: 17_25,
158+
),
156159
// custom typography for /navigation
157160
nav-toggles: (
158161
large: (14_18, nav),

src/views/DocumentationTopic.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ export default {
178178
tags = [],
179179
role,
180180
symbolKind = '',
181+
remoteSource,
181182
} = {},
182183
primaryContentSections,
183184
relationshipsSections,
@@ -212,6 +213,7 @@ export default {
212213
variantOverrides,
213214
symbolKind,
214215
tags: tags.slice(0, 1), // make sure we only show the first tag
216+
remoteSource,
215217
};
216218
},
217219
// The `hierarchy.paths` array will contain zero or more subarrays, each

tests/unit/components/DocumentationTopic.spec.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ const propsData = {
145145
type: 'foo',
146146
},
147147
],
148+
remoteSource: { url: 'foo' },
148149
};
149150

150151
describe('DocumentationTopic', () => {
@@ -355,6 +356,7 @@ describe('DocumentationTopic', () => {
355356
expect(primary.exists()).toBe(true);
356357
expect(primary.props('conformance')).toEqual(propsData.conformance);
357358
expect(primary.props('sections')).toEqual(propsData.primaryContentSections);
359+
expect(primary.props('source')).toEqual(propsData.remoteSource);
358360
});
359361

360362
it('does not render a `PrimaryContent` column when passed undefined as PrimaryContent', () => {

tests/unit/components/DocumentationTopic/PrimaryContent.spec.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ const restEndpointSection = {
147147

148148
const propsData = {
149149
conformance: { availbilityPrefix: [], constraints: [] },
150+
source: { url: 'foo.com' },
150151
sections: [
151152
declarationsSection,
152153
detailsSection,
@@ -186,6 +187,7 @@ describe('PrimaryContent', () => {
186187
checkProps(Declaration, {
187188
conformance: propsData.conformance,
188189
declarations: declarationsSection.declarations,
190+
source: propsData.source,
189191
});
190192
checkProps(PropertyListKeyDetails, { details: detailsSection.details });
191193
checkProps(GenericContent, { content: genericContentSection.content, tag: 'div' });

tests/unit/components/DocumentationTopic/PrimaryContent/Declaration.spec.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@
1010

1111
import { shallowMount } from '@vue/test-utils';
1212
import Declaration from 'docc-render/components/DocumentationTopic/PrimaryContent/Declaration.vue';
13-
import DeclarationToken from 'docc-render/components/DocumentationTopic/PrimaryContent/DeclarationToken.vue';
14-
import DeclarationDiff from 'docc-render/components/DocumentationTopic/PrimaryContent/DeclarationDiff.vue';
13+
import DeclarationToken
14+
from 'docc-render/components/DocumentationTopic/PrimaryContent/DeclarationToken.vue';
15+
import DeclarationDiff
16+
from 'docc-render/components/DocumentationTopic/PrimaryContent/DeclarationDiff.vue';
17+
import DeclarationSourceLink
18+
from '@/components/DocumentationTopic/PrimaryContent/DeclarationSourceLink.vue';
1519

1620
const {
1721
ConditionalConstraints,
@@ -95,6 +99,20 @@ describe('Declaration', () => {
9599
expect(group.props('declaration')).toEqual(propsData.declarations[0]);
96100
});
97101

102+
it('renders a DeclarationSourceLink if `source` is available', () => {
103+
expect(wrapper.find(DeclarationSourceLink).exists()).toBe(false);
104+
wrapper.setProps({
105+
source: {
106+
url: 'foo.com',
107+
fileName: 'Foo.swift',
108+
},
109+
});
110+
expect(wrapper.find(DeclarationSourceLink).props()).toEqual({
111+
url: 'foo.com',
112+
fileName: 'Foo.swift',
113+
});
114+
});
115+
98116
it('renders a `ConditionalConstraints` for availability with `conformance` data', () => {
99117
const conformance = {
100118
availabilityPrefix: [{ type: 'text', text: 'Available when' }],
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* This source file is part of the Swift.org open source project
3+
*
4+
* Copyright (c) 2021-2022 Apple Inc. and the Swift project authors
5+
* Licensed under Apache License v2.0 with Runtime Library Exception
6+
*
7+
* See https://swift.org/LICENSE.txt for license information
8+
* See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
*/
10+
11+
import DeclarationSourceLink
12+
from '@/components/DocumentationTopic/PrimaryContent/DeclarationSourceLink.vue';
13+
import { shallowMount } from '@vue/test-utils';
14+
import SwiftFileIcon from '@/components/Icons/SwiftFileIcon.vue';
15+
import WordBreak from '@/components/WordBreak.vue';
16+
17+
const defaultProps = {
18+
url: 'foo.com',
19+
fileName: 'Foo.swift',
20+
};
21+
22+
const createWrapper = ({ propsData, ...others } = {}) => shallowMount(DeclarationSourceLink, {
23+
propsData: {
24+
...defaultProps,
25+
...propsData,
26+
},
27+
...others,
28+
});
29+
30+
describe('DeclarationSourceLink', () => {
31+
it('renders the DeclarationSourceLink with a swift icon', () => {
32+
const wrapper = createWrapper();
33+
expect(wrapper.find(SwiftFileIcon).exists()).toBe(true);
34+
expect(wrapper.find(WordBreak).text()).toContain(defaultProps.fileName);
35+
expect(wrapper.find('a').attributes('href')).toBe(defaultProps.url);
36+
});
37+
38+
it('does not render the Swift icon for none-swift files', () => {
39+
const wrapper = createWrapper({
40+
propsData: {
41+
fileName: 'foo.js',
42+
},
43+
});
44+
expect(wrapper.find(SwiftFileIcon).exists()).toBe(false);
45+
expect(wrapper.text()).toContain('foo.js');
46+
});
47+
});

tests/unit/views/DocumentationTopic.spec.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ const topicData = {
104104
paths: ['documentation/swift'],
105105
},
106106
],
107+
remoteSource: {
108+
url: 'foo.com',
109+
},
107110
schemaVersion: {
108111
major: 0,
109112
minor: 2,

0 commit comments

Comments
 (0)