linkcard
This commit is contained in:
parent
c1183fd0c1
commit
05564d4bbc
|
@ -250,7 +250,7 @@ plugins:
|
|||
friends: /js/plugins/friends.js
|
||||
ghinfo: /js/plugins/ghinfo.js
|
||||
timeline: /js/plugins/timeline.js
|
||||
|
||||
linkcard: /js/plugins/linkcard.js
|
||||
|
||||
marked: https://cdn.bootcdn.net/ajax/libs/marked/4.0.18/marked.min.js
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* link.js v1.1 | https://github.com/xaoxuu/hexo-theme-stellar/
|
||||
* 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来)
|
||||
*
|
||||
* {% link url title [description] [icon:src] %}
|
||||
* {% link url [title] [desc:true/false] [icon:src] %}
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
@ -11,11 +11,11 @@ var util = require('hexo-util');
|
|||
const full_url_for = require('hexo-util').full_url_for.bind(hexo);
|
||||
|
||||
hexo.extend.tag.register('link', function(args) {
|
||||
args = hexo.args.map(args, ['icon'], ['url', 'title', 'description']);
|
||||
args = hexo.args.map(args, ['icon', 'desc'], ['url', 'title']);
|
||||
|
||||
var el = '';
|
||||
el += '<div class="tag-plugin link dis-select">';
|
||||
el += '<a class="link-card' + (args.description ? ' rich' : ' plain') + '" title="' + args.title + '" href="' + args.url + '"';
|
||||
el += '<a class="link-card' + (args.desc ? ' rich' : ' plain') + '" title="' + args.title + '" href="' + args.url + '"';
|
||||
if (args.url.includes('://')) {
|
||||
el += ' target="_blank" rel="external nofollow noopener noreferrer"';
|
||||
}
|
||||
|
@ -31,17 +31,19 @@ hexo.extend.tag.register('link', function(args) {
|
|||
return el;
|
||||
}
|
||||
function loadTitle() {
|
||||
return '<span class="title">' + args.title + '</span>';
|
||||
return '<span class="title">' + (args.title || args.url) + '</span>';
|
||||
}
|
||||
function loadDesc() {
|
||||
return '<span class="desc fs12">' + (args.description || full_url_for(args.url)) + '</span>';
|
||||
return '<span class="cap desc fs12"></span>';
|
||||
}
|
||||
function loadLink() {
|
||||
return '<span class="cap link fs12">' + full_url_for(args.url) + '</span>';
|
||||
}
|
||||
|
||||
if (args.description) {
|
||||
if (args.desc) {
|
||||
// top
|
||||
el += '<div class="top">';
|
||||
el += loadIcon();
|
||||
el += '<span class="desc fs12">' + full_url_for(args.url) + '</span>';
|
||||
el += loadIcon() + loadLink();
|
||||
el += '</div>';
|
||||
// bottom
|
||||
el += '<div class="bottom">';
|
||||
|
@ -50,7 +52,7 @@ hexo.extend.tag.register('link', function(args) {
|
|||
} else {
|
||||
// left
|
||||
el += '<div class="left">';
|
||||
el += loadTitle() + loadDesc();
|
||||
el += loadTitle() + loadLink();
|
||||
el += '</div>';
|
||||
// right
|
||||
el += '<div class="right">';
|
||||
|
|
|
@ -12,7 +12,7 @@ a
|
|||
&:hover
|
||||
color: $color-hover
|
||||
|
||||
p:not([class])
|
||||
.md p:not([class])
|
||||
text-align: convert(hexo-config('style.text-align'))
|
||||
|
||||
hr
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
cursor: pointer
|
||||
min-width 280px
|
||||
max-width: 100%
|
||||
width: 320px
|
||||
@media screen and (max-width: $device-mobile-375)
|
||||
width: 350px
|
||||
@media screen and (max-width: $device-mobile-425)
|
||||
width: 100%
|
||||
box-shadow: $boxshadow-card
|
||||
border-radius: $border-block
|
||||
|
@ -35,54 +35,68 @@
|
|||
text-align: justify
|
||||
|
||||
.md .link-card
|
||||
line-height: 1.2
|
||||
> div
|
||||
pointer-events: none
|
||||
>.left
|
||||
overflow: hidden
|
||||
margin: 0.75rem 0 0.75rem 0.75rem
|
||||
.title
|
||||
font-size: $fs-14
|
||||
span+span
|
||||
margin-top: 0.25rem
|
||||
>.right
|
||||
width: 2.75rem
|
||||
height: 2.75rem
|
||||
margin: 0.75rem
|
||||
overflow: hidden
|
||||
flex-shrink: 0
|
||||
>.top
|
||||
display: flex
|
||||
margin: .75rem 1rem .25rem
|
||||
margin: .75rem 0.75rem .25rem
|
||||
overflow: hidden
|
||||
max-width: 'calc(100% - %s * 2)' % 1rem
|
||||
align-items: center
|
||||
.img
|
||||
line-height: 0
|
||||
height: 16px
|
||||
width: 20px
|
||||
margin-right: 4px
|
||||
width: 16px
|
||||
border-radius: 16px
|
||||
margin-right: 8px
|
||||
background-repeat: no-repeat
|
||||
background-size: contain
|
||||
background-position: left center
|
||||
.desc
|
||||
opacity: .75
|
||||
line-height: 1.5
|
||||
span
|
||||
txt-ellipsis()
|
||||
max-width: 100%
|
||||
>.bottom
|
||||
margin: 0 1rem .75rem 1rem
|
||||
margin: 0 0.75rem 0.75rem 0.75rem
|
||||
.title
|
||||
font-size: $fs-15
|
||||
margin: 4px 0 8px 0
|
||||
>.right
|
||||
width: 2.5rem
|
||||
height: 2.5rem
|
||||
margin: .75rem
|
||||
overflow: hidden
|
||||
flex-shrink: 0
|
||||
>.left
|
||||
overflow: hidden
|
||||
margin: .5rem 0 .5rem 1rem
|
||||
|
||||
.md .link-card
|
||||
line-height: 1.2
|
||||
.title
|
||||
font-size: $fs-14
|
||||
margin: 1px 0 5px 0
|
||||
.desc
|
||||
display: -webkit-box
|
||||
-webkit-box-orient: vertical
|
||||
overflow: hidden
|
||||
-webkit-line-clamp: 2
|
||||
.cap
|
||||
flex-shrink: 0
|
||||
color: var(--text-p3)
|
||||
.link
|
||||
line-height: 1.5
|
||||
opacity: .75
|
||||
txt-ellipsis()
|
||||
.desc
|
||||
display: -webkit-box
|
||||
-webkit-box-orient: vertical
|
||||
overflow: hidden
|
||||
-webkit-line-clamp: 3
|
||||
.img
|
||||
border-radius: 4px
|
||||
|
||||
span
|
||||
margin: 0
|
||||
display: block
|
||||
span.title
|
||||
.title
|
||||
font-weight: 500
|
||||
color: var(--text-p1)
|
||||
span.desc
|
||||
color: var(--text-p3)
|
||||
|
|
|
@ -217,6 +217,11 @@ if (stellar.plugins.lazyload) {
|
|||
if (stellar.plugins.stellar) {
|
||||
for (let key of Object.keys(stellar.plugins.stellar)) {
|
||||
let js = stellar.plugins.stellar[key];
|
||||
if (key == 'linkcard') {
|
||||
stellar.loadScript(js, { defer: true }).then(function () {
|
||||
setCardLink(document.querySelectorAll('a.link-card'));
|
||||
});
|
||||
} else {
|
||||
const els = document.getElementsByClassName('stellar-' + key + '-api');
|
||||
if (els != undefined && els.length > 0) {
|
||||
stellar.jQuery(() => {
|
||||
|
@ -228,6 +233,7 @@ if (stellar.plugins.stellar) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// swiper
|
||||
if (stellar.plugins.swiper) {
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
// 本插件由CardLink定制而成,原项目源码: https://github.com/Lete114/CardLink
|
||||
|
||||
var cardLink = {};
|
||||
cardLink.caches = {};
|
||||
cardLink.server = 'https://api.allorigins.win/raw?url=';
|
||||
|
||||
/**
|
||||
* Remove '/' and '/index.html'
|
||||
* @param {String} params
|
||||
* @returns { String }
|
||||
*/
|
||||
function indexHandler(params) {
|
||||
let path = params.replace(/(\/index\.html|\/)*$/gi, '')
|
||||
if (path.length === 0) path += '/'
|
||||
return path
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if it is a ['https://', 'http://', '//'] protocol
|
||||
* @param {String} url Website url
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
function isHttp(url) {
|
||||
return /^(https?:)?\/\//g.test(url)
|
||||
}
|
||||
|
||||
function renderer(el, obj) {
|
||||
el.querySelector('.title').innerHTML = obj.title;
|
||||
if (obj.icon && obj.icon.length > 0) {
|
||||
el.querySelector('.img').style = 'background-image: url("' + obj.icon + '");';
|
||||
}
|
||||
if (obj.desc && obj.desc.length > 0) {
|
||||
el.querySelector('.desc').innerHTML = obj.desc;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get info
|
||||
* @param {Element} el Element
|
||||
* @param {String} html String type html
|
||||
* @param {String} link Website address
|
||||
*/
|
||||
// eslint-disable-next-line max-statements
|
||||
function getInfo(el, html, link) {
|
||||
try {
|
||||
let title, icon, desc
|
||||
const doc = new DOMParser().parseFromString(html, 'text/html')
|
||||
// If there is no title, no card link is generated
|
||||
title = doc.querySelector('title')
|
||||
if (title) {
|
||||
title = title.textContent
|
||||
|
||||
// Get the src of the first img tag in the body tag
|
||||
// icon = doc.querySelector('body img')
|
||||
// icon = icon && icon.getAttribute('src')
|
||||
|
||||
if (/^data:image/.test(icon)) icon = ''
|
||||
|
||||
// If there is no src then get the site icon
|
||||
if (!icon) {
|
||||
const links = [].slice.call(doc.querySelectorAll('link[rel][href]'))
|
||||
icon = links.find((_el) => _el.rel.includes('icon'))
|
||||
icon = icon && icon.getAttribute('href')
|
||||
}
|
||||
|
||||
desc = doc.querySelector('head meta[name="description"]')
|
||||
|
||||
if (desc) {
|
||||
desc = desc.content;
|
||||
}
|
||||
// If `icon` is not the ['https://', 'http://', '//'] protocol, splice on the `origin` of the a tag
|
||||
if (icon && !isHttp(icon)) icon = new URL(link).origin + icon
|
||||
cardLink.caches[link] = { title, link, icon, desc }
|
||||
|
||||
renderer(el, cardLink.caches[link])
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('CardLink Error: Failed to parse', error)
|
||||
}
|
||||
}
|
||||
|
||||
function fetchPage(link, callback) {
|
||||
fetch(link)
|
||||
.then((result) => result.text())
|
||||
.then(callback)
|
||||
.catch((error) => {
|
||||
const server = cardLink.server
|
||||
// eslint-disable-next-line no-console
|
||||
if (link.includes(server) || !server) return console.error('CardLink Error:', error)
|
||||
fetchPage(server + link, callback)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Create card links
|
||||
* @param {NodeList} nodes A collection of nodes or a collection of arrays,
|
||||
* if it is an array then the array must always contain node element
|
||||
*/
|
||||
function setCardLink(nodes) {
|
||||
// If the `nodes` do not contain a `forEach` method, then the default `a[cardlink]` is used
|
||||
nodes = 'forEach' in (nodes || {}) ? nodes : document.querySelectorAll('a[cardlink]')
|
||||
nodes.forEach((el) => {
|
||||
// If it is not a tag element then it is not processed
|
||||
if (el.nodeType !== 1) return
|
||||
el.removeAttribute('cardlink')
|
||||
const link = el.href
|
||||
|
||||
const cache = cardLink.caches[link]
|
||||
if (cache) return renderer(el, cache)
|
||||
|
||||
if (isHttp(link)) {
|
||||
fetchPage(link, (html) => {
|
||||
getInfo(el, html, link)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue