Skip to content

Commit 0e106af

Browse files
marinaaisaDobromir Hristov
andauthored
Add anchor for section titles for quick sharing of sections (#408)
* [r96943502] chore: started adding anchor to titles * [r96943502] feat: create SectionTitle component * [r96943502] feat: add SectionTitle to more headings * [r96943502] chore: make anchor optional for those that already have an anchor * [r96943502] test: fix current tests * [r96943502] test: add tests for SectionTitle component * [r96943502] fix: TopicsTable component * [r96943502] test: fix failing test * [r96943502] fix: address feedback * [r96943502] chore: it does not render anchor if target ide is true * [r96943502] test: add new tests for scrollToElement * [r96943502] fix: address feedback * [r96943502] fix: prevent jumping issues * [r96943502] fix: address feedback * [r96943502] chore: delete extra anchors to avoid duplication of ids * [r96943502] styles: [WIP] update UI * [r96943502] styles: [WIP] update UI with link icon * [r96943502] fix: address feedback * [r96943502] fix: adding padding right to header anchor so icon does not dissapear when hovering on it * [r96943502] chore: add aria label for AX * [r94221573] chore: address design feedback + refactor vars * [r94150776] fix: address feedback Co-authored-by: Dobromir Hristov <[email protected]>
1 parent 009f87b commit 0e106af

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+416
-135
lines changed

src/components/ContentNode.vue

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<script>
1212
import Aside from './ContentNode/Aside.vue';
1313
import CodeListing from './ContentNode/CodeListing.vue';
14+
import LinkableHeading from './ContentNode/LinkableHeading.vue';
1415
import CodeVoice from './ContentNode/CodeVoice.vue';
1516
import DictionaryExample from './ContentNode/DictionaryExample.vue';
1617
import EndpointExample from './ContentNode/EndpointExample.vue';
@@ -230,14 +231,13 @@ function renderNode(createElement, references) {
230231
};
231232
return createElement(EndpointExample, { props }, renderChildren(node.summary || []));
232233
}
233-
case BlockType.heading:
234-
return createElement(`h${node.level}`, {
235-
attrs: {
236-
id: node.anchor,
237-
},
238-
}, (
239-
node.text
240-
));
234+
case BlockType.heading: {
235+
const props = {
236+
anchor: node.anchor,
237+
level: node.level,
238+
};
239+
return createElement(LinkableHeading, { props }, node.text);
240+
}
241241
case BlockType.orderedList:
242242
return createElement('ol', {
243243
attrs: {
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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+
<component
13+
:id="anchor"
14+
:is="`h${level}`"
15+
>
16+
<router-link
17+
v-if="anchor && !isTargetIDE"
18+
:to="{ hash: `#${anchor}` }"
19+
class="header-anchor"
20+
aria-label="Scroll to section"
21+
@click="handleFocusAndScroll(anchor)"
22+
>
23+
<slot />
24+
<LinkIcon class="icon" aria-hidden="true"/>
25+
</router-link>
26+
<template v-else>
27+
<slot />
28+
</template>
29+
</component>
30+
</template>
31+
32+
<script>
33+
import scrollToElement from 'docc-render/mixins/scrollToElement';
34+
import LinkIcon from 'theme/components/Icons/LinkIcon.vue';
35+
36+
export default {
37+
name: 'LinkableHeading',
38+
mixins: [scrollToElement],
39+
components: {
40+
LinkIcon,
41+
},
42+
props: {
43+
anchor: {
44+
type: String,
45+
required: false,
46+
},
47+
level: {
48+
type: Number,
49+
default: () => 2,
50+
validator: v => v >= 1 && v <= 6,
51+
},
52+
},
53+
inject: {
54+
isTargetIDE: {
55+
default: () => false,
56+
},
57+
},
58+
};
59+
</script>
60+
61+
<style scoped lang="scss">
62+
@import 'docc-render/styles/_core.scss';
63+
$icon-margin: 7px;
64+
65+
.header-anchor {
66+
color: inherit;
67+
text-decoration: none;
68+
position: relative;
69+
padding-right: $icon-size-default + $icon-margin;
70+
display: inline-block;
71+
72+
.icon {
73+
position: absolute;
74+
bottom: .2em;
75+
display: none;
76+
height: $icon-size-default;
77+
margin-left: $icon-margin;
78+
}
79+
80+
&:hover .icon {
81+
display: inline;
82+
}
83+
}
84+
</style>

src/components/DocumentationTopic/ContentTable.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,19 @@
1515
:title="title"
1616
>
1717
<div class="container">
18-
<h2 class="title">{{title}}</h2>
18+
<LinkableHeading class="title" :anchor="anchor">{{ title }}</LinkableHeading>
1919
<slot />
2020
</div>
2121
</OnThisPageSection>
2222
</template>
2323

2424
<script>
25+
import LinkableHeading from 'docc-render/components/ContentNode/LinkableHeading.vue';
2526
import OnThisPageSection from './OnThisPageSection.vue';
2627
2728
export default {
2829
name: 'ContentTable',
29-
components: { OnThisPageSection },
30+
components: { OnThisPageSection, LinkableHeading },
3031
props: {
3132
anchor: {
3233
type: String,

src/components/DocumentationTopic/ContentTableSection.vue

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
<div class="contenttable-section">
1313
<div class="section-title">
1414
<slot name="title">
15-
<h3 class="title">{{ title }}</h3>
15+
<LinkableHeading
16+
:level="3"
17+
class="title"
18+
:anchor="anchorComputed"
19+
>{{ title }}</LinkableHeading>
1620
</slot>
1721
</div>
1822
<div class="section-content">
@@ -24,13 +28,24 @@
2428
</template>
2529

2630
<script>
31+
import LinkableHeading from 'docc-render/components/ContentNode/LinkableHeading.vue';
32+
import { anchorize } from 'docc-render/utils/strings';
33+
2734
export default {
2835
name: 'ContentTableSection',
36+
components: { LinkableHeading },
2937
props: {
3038
title: {
3139
type: String,
3240
required: true,
3341
},
42+
anchor: {
43+
type: String,
44+
default: null,
45+
},
46+
},
47+
computed: {
48+
anchorComputed: ({ title, anchor }) => anchor || anchorize(title),
3449
},
3550
};
3651
</script>

src/components/DocumentationTopic/OnThisPageSection.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
-->
1010

1111
<template>
12-
<section :id="anchor"><slot /></section>
12+
<section><slot /></section>
1313
</template>
1414

1515
<script>

src/components/DocumentationTopic/PrimaryContent/Declaration.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
class="declaration"
1515
title="Declaration"
1616
>
17-
<h2>Declaration</h2>
17+
<LinkableHeading anchor="declaration">Declaration</LinkableHeading>
1818
<template v-if="hasModifiedChanges">
1919
<DeclarationDiff
2020
:class="[changeClasses, multipleLinesClass]"
@@ -48,6 +48,7 @@
4848
<script>
4949
import ConditionalConstraints from 'docc-render/components/DocumentationTopic/ConditionalConstraints.vue';
5050
import OnThisPageSection from 'docc-render/components/DocumentationTopic/OnThisPageSection.vue';
51+
import LinkableHeading from 'docc-render/components/ContentNode/LinkableHeading.vue';
5152
5253
import DeclarationGroup from 'docc-render/components/DocumentationTopic/PrimaryContent/DeclarationGroup.vue';
5354
import DeclarationDiff
@@ -65,6 +66,7 @@ export default {
6566
DeclarationSourceLink,
6667
ConditionalConstraints,
6768
OnThisPageSection,
69+
LinkableHeading,
6870
},
6971
constants: { ChangeTypes, multipleLinesClass },
7072
inject: ['identifier', 'store'],

src/components/DocumentationTopic/PrimaryContent/Parameters.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
class="parameters"
1515
title="Parameters"
1616
>
17-
<h2>Parameters</h2>
17+
<LinkableHeading anchor="parameters">Parameters</LinkableHeading>
1818
<dl>
1919
<template v-for="param in parameters">
2020
<dt class="param-name" :key="`${param.name}:name`">
@@ -31,12 +31,14 @@
3131
<script>
3232
import ContentNode from 'docc-render/components/DocumentationTopic/ContentNode.vue';
3333
import OnThisPageSection from 'docc-render/components/DocumentationTopic/OnThisPageSection.vue';
34+
import LinkableHeading from 'docc-render/components/ContentNode/LinkableHeading.vue';
3435
3536
export default {
3637
name: 'Parameters',
3738
components: {
3839
ContentNode,
3940
OnThisPageSection,
41+
LinkableHeading,
4042
},
4143
props: {
4244
parameters: {

src/components/DocumentationTopic/PrimaryContent/PossibleValues.vue

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

1111
<template>
1212
<OnThisPageSection anchor="possibleValues" title="PossibleValues">
13-
<h2>Possible Values</h2>
13+
<LinkableHeading anchor="possibleValues">Possible Values</LinkableHeading>
1414
<dl class="datalist">
1515
<template v-for="value in values">
1616
<dt class="param-name" :key="`${value.name}:name`">
@@ -28,10 +28,16 @@
2828
import OnThisPageSection from 'docc-render/components/DocumentationTopic/OnThisPageSection.vue';
2929
import ContentNode from 'docc-render/components/ContentNode.vue';
3030
import WordBreak from 'docc-render/components/WordBreak.vue';
31+
import LinkableHeading from 'docc-render/components/ContentNode/LinkableHeading.vue';
3132
3233
export default {
3334
name: 'PossibleValues',
34-
components: { ContentNode, OnThisPageSection, WordBreak },
35+
components: {
36+
ContentNode,
37+
OnThisPageSection,
38+
LinkableHeading,
39+
WordBreak,
40+
},
3541
props: {
3642
values: {
3743
type: Array,

src/components/DocumentationTopic/PrimaryContent/PropertyListKeyDetails.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
class="details"
1515
title="Details"
1616
>
17-
<h2>Details</h2>
17+
<LinkableHeading anchor="details">Details</LinkableHeading>
1818
<dl>
1919
<template v-if="isSymbol">
2020
<dt class="detail-type" :key="`${details.name}:name`">
@@ -45,12 +45,14 @@
4545
<script>
4646
import PropertyListKeyType from 'docc-render/components/DocumentationTopic/PrimaryContent/PropertyListKeyType.vue';
4747
import OnThisPageSection from 'docc-render/components/DocumentationTopic/OnThisPageSection.vue';
48+
import LinkableHeading from 'docc-render/components/ContentNode/LinkableHeading.vue';
4849
4950
export default {
5051
name: 'PropertyListKeyDetails',
5152
components: {
5253
PropertyListKeyType,
5354
OnThisPageSection,
55+
LinkableHeading,
5456
},
5557
props: {
5658
details: {

src/components/DocumentationTopic/PrimaryContent/PropertyTable.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
<template>
1212
<OnThisPageSection :anchor="anchor" :title="title">
13-
<h2>{{ title }}</h2>
13+
<LinkableHeading :anchor="anchor">{{ title }}</LinkableHeading>
1414
<ParametersTable :parameters="properties" :changes="propertyChanges" class="property-table">
1515
<template slot="symbol" slot-scope="{ name, type, content, changes, deprecated }">
1616
<div class="property-name" :class="{ deprecated: deprecated }">
@@ -60,6 +60,7 @@
6060

6161
<script>
6262
import { anchorize } from 'docc-render/utils/strings';
63+
import LinkableHeading from 'docc-render/components/ContentNode/LinkableHeading.vue';
6364
import WordBreak from 'docc-render/components/WordBreak.vue';
6465
import ContentNode from 'docc-render/components/DocumentationTopic/ContentNode.vue';
6566
@@ -83,6 +84,7 @@ export default {
8384
ContentNode,
8485
OnThisPageSection,
8586
ParametersTable,
87+
LinkableHeading,
8688
},
8789
props: {
8890
title: {

src/components/DocumentationTopic/PrimaryContent/RestBody.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
<template>
1212
<OnThisPageSection :anchor="anchor" :title="title">
13-
<h2>{{ title }}</h2>
13+
<LinkableHeading :anchor="anchor">{{ title }}</LinkableHeading>
1414
<ParametersTable :parameters="[bodyParam]" :changes="bodyChanges" keyBy="key">
1515
<template slot="symbol" slot-scope="{ type, content, changes, name }">
1616
<PossiblyChangedType
@@ -84,6 +84,7 @@
8484
import { anchorize } from 'docc-render/utils/strings';
8585
import ContentNode from 'docc-render/components/DocumentationTopic/ContentNode.vue';
8686
import OnThisPageSection from 'docc-render/components/DocumentationTopic/OnThisPageSection.vue';
87+
import LinkableHeading from 'docc-render/components/ContentNode/LinkableHeading.vue';
8788
8889
import WordBreak from 'docc-render/components/WordBreak.vue';
8990
import apiChangesProvider from 'docc-render/mixins/apiChangesProvider';
@@ -107,6 +108,7 @@ export default {
107108
ContentNode,
108109
OnThisPageSection,
109110
ParametersTable,
111+
LinkableHeading,
110112
},
111113
constants: { ChangesKey },
112114
props: {

src/components/DocumentationTopic/PrimaryContent/RestEndpoint.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010

1111
<template>
1212
<OnThisPageSection :anchor="anchor" :title="title">
13-
<h2>{{ title }}</h2>
13+
<LinkableHeading :anchor="anchor">{{ title }}</LinkableHeading>
1414
<DeclarationSource :tokens="tokens" />
1515
</OnThisPageSection>
1616
</template>
1717

1818
<script>
1919
import { anchorize } from 'docc-render/utils/strings';
2020
import OnThisPageSection from 'docc-render/components/DocumentationTopic/OnThisPageSection.vue';
21+
import LinkableHeading from 'docc-render/components/ContentNode/LinkableHeading.vue';
2122
import DeclarationSource
2223
from 'docc-render/components/DocumentationTopic/PrimaryContent/DeclarationSource.vue';
2324
@@ -29,6 +30,7 @@ export default {
2930
components: {
3031
DeclarationSource,
3132
OnThisPageSection,
33+
LinkableHeading,
3234
},
3335
props: {
3436
title: {

src/components/DocumentationTopic/PrimaryContent/RestParameters.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
<template>
1212
<OnThisPageSection :anchor="anchor" :title="title">
13-
<h2>{{ title }}</h2>
13+
<LinkableHeading :anchor="anchor">{{ title }}</LinkableHeading>
1414
<ParametersTable :parameters="parameters" :changes="parameterChanges">
1515
<template slot="symbol" slot-scope="{ name, type, content, changes, deprecated }">
1616
<div class="param-name" :class="{ deprecated: deprecated }">
@@ -55,6 +55,7 @@
5555
import { anchorize } from 'docc-render/utils/strings';
5656
import ContentNode from 'docc-render/components/DocumentationTopic/ContentNode.vue';
5757
import OnThisPageSection from 'docc-render/components/DocumentationTopic/OnThisPageSection.vue';
58+
import LinkableHeading from 'docc-render/components/ContentNode/LinkableHeading.vue';
5859
5960
import WordBreak from 'docc-render/components/WordBreak.vue';
6061
import apiChangesProvider from 'docc-render/mixins/apiChangesProvider';
@@ -76,6 +77,7 @@ export default {
7677
ContentNode,
7778
OnThisPageSection,
7879
ParametersTable,
80+
LinkableHeading,
7981
},
8082
props: {
8183
title: {

0 commit comments

Comments
 (0)