From 5a04cb5f143a056df632de794d0b7af21136acd3 Mon Sep 17 00:00:00 2001 From: Yufei Huang Date: Sat, 18 Mar 2023 21:36:15 +0800 Subject: [PATCH 1/2] feat: add icon to external links --- templates/modern/layout/_master.tmpl | 1 - templates/modern/src/markdown.scss | 9 +++++++ templates/modern/src/markdown.ts | 40 +++++++++++++--------------- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/templates/modern/layout/_master.tmpl b/templates/modern/layout/_master.tmpl index 222fd80db28..1cae31d2541 100644 --- a/templates/modern/layout/_master.tmpl +++ b/templates/modern/layout/_master.tmpl @@ -23,7 +23,6 @@ {{#_noindex}}{{/_noindex}} {{#_enableSearch}}{{/_enableSearch}} - {{#_enableNewTab}}{{/_enableNewTab}} {{#docurl}}{{/docurl}} {{#yamlmime}}{{/yamlmime}} {{/redirect_url}} diff --git a/templates/modern/src/markdown.scss b/templates/modern/src/markdown.scss index 483e867e338..e8069584779 100644 --- a/templates/modern/src/markdown.scss +++ b/templates/modern/src/markdown.scss @@ -3,6 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. */ +/* External link icon */ +a.external[href]::after { + font-family: bootstrap-icons, sans-serif; + content: "\F1C5"; + font-size: .65em; + margin: 0 .2em; + display: inline-block; +} + /* Alerts */ .alert h5 { text-transform: uppercase; diff --git a/templates/modern/src/markdown.ts b/templates/modern/src/markdown.ts index fb79c88523e..b994855cda5 100644 --- a/templates/modern/src/markdown.ts +++ b/templates/modern/src/markdown.ts @@ -67,8 +67,8 @@ function renderClickableImage() { function shouldMakeClickable(): boolean { return img.naturalWidth > MIN_CLICKABLE_IMAGE_SIZE && - img.naturalHeight > MIN_CLICKABLE_IMAGE_SIZE && - !imageLinks.includes(img) + img.naturalHeight > MIN_CLICKABLE_IMAGE_SIZE && + !imageLinks.includes(img) } }) } @@ -100,15 +100,13 @@ function renderAlerts() { * Open external links to different host in a new window. */ function renderLinks() { - if (meta('docfx:newtab') === 'true') { - const links = document.links - for (let i = 0; i < links.length; i++) { - const link = links.item(i) - if (link.hostname !== window.location.hostname) { - link.target = '_blank' - } + document.querySelectorAll('article a[href]').forEach(a => { + if (a.hostname !== window.location.hostname && a.innerText.trim() !== '') { + a.target = '_blank' + a.rel = 'noopener noreferrer nofollow' + a.classList.add('external') } - } + }) } /** @@ -163,25 +161,25 @@ function renderTabs() { type: 'data-bi-type' } - const Tab = (function() { + const Tab = (function () { function Tab(li, a, section) { this.li = li this.a = a this.section = section } Object.defineProperty(Tab.prototype, 'tabIds', { - get: function() { return this.a.getAttribute('data-tab').split(' ') }, + get: function () { return this.a.getAttribute('data-tab').split(' ') }, enumerable: true, configurable: true }) Object.defineProperty(Tab.prototype, 'condition', { - get: function() { return this.a.getAttribute('data-condition') }, + get: function () { return this.a.getAttribute('data-condition') }, enumerable: true, configurable: true }) Object.defineProperty(Tab.prototype, 'visible', { - get: function() { return !this.li.hasAttribute('hidden') }, - set: function(value) { + get: function () { return !this.li.hasAttribute('hidden') }, + set: function (value) { if (value) { this.li.removeAttribute('hidden') this.li.removeAttribute('aria-hidden') @@ -194,8 +192,8 @@ function renderTabs() { configurable: true }) Object.defineProperty(Tab.prototype, 'selected', { - get: function() { return !this.section.hasAttribute('hidden') }, - set: function(value) { + get: function () { return !this.section.hasAttribute('hidden') }, + set: function (value) { if (value) { this.a.setAttribute('aria-selected', 'true') this.a.classList.add('active') @@ -213,7 +211,7 @@ function renderTabs() { enumerable: true, configurable: true }) - Tab.prototype.focus = function() { + Tab.prototype.focus = function () { this.a.focus() } return Tab @@ -232,7 +230,7 @@ function renderTabs() { state.groups.push(group) } } - container.addEventListener('click', function(event) { return handleClick(event, state) }) + container.addEventListener('click', function (event) { return handleClick(event, state) }) if (state.groups.length === 0) { return state } @@ -317,7 +315,7 @@ function renderTabs() { } event.preventDefault() info.anchor.href = 'javascript:' - setTimeout(function() { + setTimeout(function () { info.anchor.href = '#' + info.anchor.getAttribute('aria-controls') }) const tabIds = info.tabIds; const group = info.group @@ -331,7 +329,7 @@ function renderTabs() { if (arraysIntersect(state.selectedTabs, tabIds)) { return } - const previousTabId = group.tabs.filter(function(t) { return t.selected })[0].tabIds[0] + const previousTabId = group.tabs.filter(function (t) { return t.selected })[0].tabIds[0] state.selectedTabs.splice(state.selectedTabs.indexOf(previousTabId), 1, tabIds[0]) for (let _b = 0, _c = state.groups; _b < _c.length; _b++) { const group1 = _c[_b] From da22fef48dde065058691bc393e978e752ad7497 Mon Sep 17 00:00:00 2001 From: Yufei Huang Date: Sun, 19 Mar 2023 09:39:32 +0800 Subject: [PATCH 2/2] suppress font-family-no-missing-generic-family-keyword for bootstrap-icons --- templates/.stylelintrc.json | 7 ++++++- templates/modern/src/docfx.scss | 2 +- templates/modern/src/markdown.scss | 4 ++-- templates/modern/src/markdown.ts | 24 ++++++++++++------------ templates/modern/src/toc.scss | 2 +- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/templates/.stylelintrc.json b/templates/.stylelintrc.json index a1b08ce2855..856d46a1e01 100644 --- a/templates/.stylelintrc.json +++ b/templates/.stylelintrc.json @@ -5,6 +5,11 @@ "**/docfx.scss" ], "rules": { - "selector-class-pattern": null + "selector-class-pattern": null, + "font-family-no-missing-generic-family-keyword": [ true, { + "ignoreFontFamilies": [ + "bootstrap-icons" + ] + }] } } diff --git a/templates/modern/src/docfx.scss b/templates/modern/src/docfx.scss index 58ca6336902..77de2debfaa 100644 --- a/templates/modern/src/docfx.scss +++ b/templates/modern/src/docfx.scss @@ -81,7 +81,7 @@ article { } @mixin adjust-icon { - font-family: bootstrap-icons, sans-serif; + font-family: bootstrap-icons; position: relative; margin-right: 0.5em; top: 0.2em; diff --git a/templates/modern/src/markdown.scss b/templates/modern/src/markdown.scss index e8069584779..dc5877ada9f 100644 --- a/templates/modern/src/markdown.scss +++ b/templates/modern/src/markdown.scss @@ -5,9 +5,9 @@ /* External link icon */ a.external[href]::after { - font-family: bootstrap-icons, sans-serif; + font-family: bootstrap-icons; content: "\F1C5"; - font-size: .65em; + font-size: .6rem; margin: 0 .2em; display: inline-block; } diff --git a/templates/modern/src/markdown.ts b/templates/modern/src/markdown.ts index b994855cda5..a95e9bfb76d 100644 --- a/templates/modern/src/markdown.ts +++ b/templates/modern/src/markdown.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -import { breakWord, meta } from './helper' +import { breakWord } from './helper' import AnchorJs from 'anchor-js' import { html, render } from 'lit-html' @@ -161,25 +161,25 @@ function renderTabs() { type: 'data-bi-type' } - const Tab = (function () { + const Tab = (function() { function Tab(li, a, section) { this.li = li this.a = a this.section = section } Object.defineProperty(Tab.prototype, 'tabIds', { - get: function () { return this.a.getAttribute('data-tab').split(' ') }, + get: function() { return this.a.getAttribute('data-tab').split(' ') }, enumerable: true, configurable: true }) Object.defineProperty(Tab.prototype, 'condition', { - get: function () { return this.a.getAttribute('data-condition') }, + get: function() { return this.a.getAttribute('data-condition') }, enumerable: true, configurable: true }) Object.defineProperty(Tab.prototype, 'visible', { - get: function () { return !this.li.hasAttribute('hidden') }, - set: function (value) { + get: function() { return !this.li.hasAttribute('hidden') }, + set: function(value) { if (value) { this.li.removeAttribute('hidden') this.li.removeAttribute('aria-hidden') @@ -192,8 +192,8 @@ function renderTabs() { configurable: true }) Object.defineProperty(Tab.prototype, 'selected', { - get: function () { return !this.section.hasAttribute('hidden') }, - set: function (value) { + get: function() { return !this.section.hasAttribute('hidden') }, + set: function(value) { if (value) { this.a.setAttribute('aria-selected', 'true') this.a.classList.add('active') @@ -211,7 +211,7 @@ function renderTabs() { enumerable: true, configurable: true }) - Tab.prototype.focus = function () { + Tab.prototype.focus = function() { this.a.focus() } return Tab @@ -230,7 +230,7 @@ function renderTabs() { state.groups.push(group) } } - container.addEventListener('click', function (event) { return handleClick(event, state) }) + container.addEventListener('click', function(event) { return handleClick(event, state) }) if (state.groups.length === 0) { return state } @@ -315,7 +315,7 @@ function renderTabs() { } event.preventDefault() info.anchor.href = 'javascript:' - setTimeout(function () { + setTimeout(function() { info.anchor.href = '#' + info.anchor.getAttribute('aria-controls') }) const tabIds = info.tabIds; const group = info.group @@ -329,7 +329,7 @@ function renderTabs() { if (arraysIntersect(state.selectedTabs, tabIds)) { return } - const previousTabId = group.tabs.filter(function (t) { return t.selected })[0].tabIds[0] + const previousTabId = group.tabs.filter(function(t) { return t.selected })[0].tabIds[0] state.selectedTabs.splice(state.selectedTabs.indexOf(previousTabId), 1, tabIds[0]) for (let _b = 0, _c = state.groups; _b < _c.length; _b++) { const group1 = _c[_b] diff --git a/templates/modern/src/toc.scss b/templates/modern/src/toc.scss index 48567f896ba..ca41bb7b0a3 100644 --- a/templates/modern/src/toc.scss +++ b/templates/modern/src/toc.scss @@ -44,7 +44,7 @@ $expand-stub-width: 1.2rem; display: inline-block; width: $expand-stub-width; cursor: pointer; - font-family: bootstrap-icons, sans-serif; + font-family: bootstrap-icons; content: "\F285"; position: absolute; margin-left: -$expand-stub-width;