mirror of
https://github.com/kremalicious/portfolio.git
synced 2024-12-22 17:23:22 +01:00
make vcard work again
* switch out problematic dependency
This commit is contained in:
parent
b53849fae1
commit
e1787e39e6
@ -13,6 +13,7 @@
|
||||
"deploy": "./deploy.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"camel-case": "^3.0.0",
|
||||
"file-saver": "^1.3.8",
|
||||
"gatsby": "^1.9.259",
|
||||
"gatsby-image": "^1.0.51",
|
||||
|
@ -4,8 +4,12 @@ import PropTypes from 'prop-types'
|
||||
|
||||
const SEO = ({ project, meta }) => {
|
||||
const title = project.title ? project.title : meta.title
|
||||
const description = project.description ? project.description : meta.description
|
||||
const image = project.img ? project.img.childImageSharp.twitterImage.src : meta.img.childImageSharp.resize.src
|
||||
const description = project.description
|
||||
? project.description
|
||||
: meta.description
|
||||
const image = project.img
|
||||
? project.img.childImageSharp.twitterImage.src
|
||||
: meta.img.childImageSharp.resize.src
|
||||
const url = project.slug ? `${meta.url}/${project.slug}` : meta.url
|
||||
|
||||
return (
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
// import vCard from 'vcf'
|
||||
import FileSaver from 'file-saver'
|
||||
import vCard from '../../lib/vcf/vcard'
|
||||
import Social from '../molecules/Social'
|
||||
import './Footer.scss'
|
||||
|
||||
@ -12,22 +12,20 @@ class Footer extends Component {
|
||||
}
|
||||
|
||||
constructVcard() {
|
||||
// const meta = this.props.meta
|
||||
// const contact = new vCard()
|
||||
// const photo = meta.avatarBase64
|
||||
|
||||
// contact.set('fn', meta.title)
|
||||
// contact.set('title', meta.tagline)
|
||||
// contact.set('email', meta.email)
|
||||
// contact.set('url', meta.url, { type: 'Portfolio' })
|
||||
// contact.add('url', meta.social.Blog, { type: 'Blog' })
|
||||
// contact.set('nickname', 'kremalicious')
|
||||
// contact.add('x-socialprofile', meta.social.Twitter, { type: 'twitter' })
|
||||
// contact.add('x-socialprofile', meta.social.GitHub, { type: 'GitHub' })
|
||||
// contact.set('photo', photo, { encoding: 'b', type: 'JPEG' })
|
||||
|
||||
// const vcard = contact.toString('3.0')
|
||||
// this.downloadVcard(vcard, meta)
|
||||
const meta = this.props.meta
|
||||
const contact = new vCard()
|
||||
const photo = meta.avatarBase64
|
||||
contact.set('fn', meta.title)
|
||||
contact.set('title', meta.tagline)
|
||||
contact.set('email', meta.email)
|
||||
contact.set('url', meta.url, { type: 'Portfolio' })
|
||||
contact.add('url', meta.social.Blog, { type: 'Blog' })
|
||||
contact.set('nickname', 'kremalicious')
|
||||
contact.add('x-socialprofile', meta.social.Twitter, { type: 'twitter' })
|
||||
contact.add('x-socialprofile', meta.social.GitHub, { type: 'GitHub' })
|
||||
contact.set('photo', photo, { encoding: 'b', type: 'JPEG' })
|
||||
const vcard = contact.toString('3.0')
|
||||
this.downloadVcard(vcard, meta)
|
||||
}
|
||||
|
||||
downloadVcard(vcard, meta) {
|
||||
@ -48,9 +46,9 @@ class Footer extends Component {
|
||||
<footer className="footer">
|
||||
<Social meta={meta} minimal />
|
||||
<p className="footer__actions">
|
||||
{/* <a href="#" onClick={this.handleAddressbookClick}>
|
||||
<a href="#" onClick={this.handleAddressbookClick}>
|
||||
Add to addressbook
|
||||
</a> */}
|
||||
</a>
|
||||
<a href={meta.gpg}>PGP/GPG key</a>
|
||||
</p>
|
||||
<p>
|
||||
|
71
src/lib/vcf/parse-lines.js
Normal file
71
src/lib/vcf/parse-lines.js
Normal file
@ -0,0 +1,71 @@
|
||||
var camelCase = require('camel-case') // that's the only change
|
||||
var Property = require('./property')
|
||||
|
||||
function set(object, key, value) {
|
||||
if (Array.isArray(object[key])) {
|
||||
object[key].push(value)
|
||||
} else if (object[key] != null) {
|
||||
object[key] = [object[key], value]
|
||||
} else {
|
||||
object[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
function createParams(params, param) {
|
||||
var parts = param.split('=')
|
||||
var k = camelCase(parts[0])
|
||||
var value = parts[1]
|
||||
|
||||
if (value == null || value === '') {
|
||||
value = parts[0]
|
||||
k = 'type'
|
||||
}
|
||||
|
||||
if (k === 'type') {
|
||||
value
|
||||
.toLowerCase()
|
||||
.split(',')
|
||||
.forEach(function(value) {
|
||||
set(params, k, value)
|
||||
})
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
set(params, k, value)
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
function parseLines(lines) {
|
||||
var data = {}
|
||||
|
||||
// NOTE: Line format:
|
||||
// PROPERTY[;PARAMETER[=VALUE]]:Attribute[;Attribute]
|
||||
var line = null
|
||||
var pattern = /^([^;:]+)((?:;(?:[^;:]+))*)(?:\:(.+))?$/i // eslint-disable-line no-useless-escape
|
||||
var len = lines.length - 1
|
||||
|
||||
for (var i = 1; i < len; i++) {
|
||||
line = lines[i]
|
||||
|
||||
var match = pattern.exec(line)
|
||||
if (!match) continue
|
||||
|
||||
var name = match[1].split('.')
|
||||
var property = name.pop()
|
||||
var group = name.pop()
|
||||
var value = match[3]
|
||||
var params = match[2] ? match[2].replace(/^;|;$/g, '').split(';') : []
|
||||
|
||||
var propParams = params.reduce(createParams, group ? { group: group } : {})
|
||||
var propName = camelCase(property)
|
||||
var propVal = new Property(propName, value, propParams)
|
||||
|
||||
set(data, propName, propVal)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
module.exports = parseLines
|
145
src/lib/vcf/property.js
Normal file
145
src/lib/vcf/property.js
Normal file
@ -0,0 +1,145 @@
|
||||
/**
|
||||
* vCard Property
|
||||
* @constructor
|
||||
* @memberOf vCard
|
||||
* @param {String} field
|
||||
* @param {String} value
|
||||
* @param {Object} params
|
||||
* @return {Property}
|
||||
*/
|
||||
function Property(field, value, params) {
|
||||
if (!(this instanceof Property)) return new Property(value)
|
||||
|
||||
if (params != null) Object.assign(this, params)
|
||||
|
||||
this._field = field
|
||||
this._data = value
|
||||
|
||||
Object.defineProperty(this, '_field', { enumerable: false })
|
||||
Object.defineProperty(this, '_data', { enumerable: false })
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a vCard.Property from jCard data
|
||||
* @param {Array} data
|
||||
* @return {Property}
|
||||
*/
|
||||
Property.fromJSON = function(data) {
|
||||
var field = data[0]
|
||||
var params = data[1]
|
||||
|
||||
if (!/text/i.test(data[2])) params.value = data[2]
|
||||
|
||||
var value = Array.isArray(data[3]) ? data[3].join(';') : data[3]
|
||||
|
||||
return new Property(field, value, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a string into capitalized dash-case
|
||||
* @internal used by `Property#toString()`
|
||||
* @param {String} value
|
||||
* @return {String}
|
||||
* @ignore
|
||||
*/
|
||||
function capitalDashCase(value) {
|
||||
return value.replace(/([A-Z])/g, '-$1').toUpperCase()
|
||||
}
|
||||
|
||||
/**
|
||||
* Property prototype
|
||||
* @type {Object}
|
||||
*/
|
||||
Property.prototype = {
|
||||
constructor: Property,
|
||||
|
||||
/**
|
||||
* Check whether the property is of a given type
|
||||
* @param {String} type
|
||||
* @return {Boolean}
|
||||
*/
|
||||
is: function(type) {
|
||||
type = (type + '').toLowerCase()
|
||||
return Array.isArray(this.type)
|
||||
? this.type.indexOf(type)
|
||||
: this.type === type
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether the property is empty
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isEmpty: function() {
|
||||
return this._data == null && Object.keys(this).length === 0
|
||||
},
|
||||
|
||||
/**
|
||||
* Clone the property
|
||||
* @return {Property}
|
||||
*/
|
||||
clone: function() {
|
||||
return new Property(this._field, this._data, this)
|
||||
},
|
||||
|
||||
/**
|
||||
* Format the property as vcf with given version
|
||||
* @param {String} version
|
||||
* @return {String}
|
||||
*/
|
||||
toString: function(version) { // eslint-disable-line no-unused-vars
|
||||
|
||||
var propName =
|
||||
(this.group ? this.group + '.' : '') + capitalDashCase(this._field)
|
||||
var keys = Object.keys(this)
|
||||
var params = []
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (keys[i] === 'group') continue
|
||||
params.push(capitalDashCase(keys[i]) + '=' + this[keys[i]])
|
||||
}
|
||||
|
||||
return (
|
||||
propName +
|
||||
(params.length ? ';' + params.join(';') : params) +
|
||||
':' +
|
||||
(Array.isArray(this._data) ? this._data.join(';') : this._data)
|
||||
)
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the property's value
|
||||
* @return {String}
|
||||
*/
|
||||
valueOf: function() {
|
||||
return this._data
|
||||
},
|
||||
|
||||
/**
|
||||
* Format the property as jCard data
|
||||
* @return {Array}
|
||||
*/
|
||||
toJSON: function() {
|
||||
var params = Object.assign({}, this)
|
||||
|
||||
if (params.value === 'text') {
|
||||
params.value = void 0
|
||||
delete params.value
|
||||
}
|
||||
|
||||
var data = [this._field, params, this.value || 'text']
|
||||
|
||||
switch (this._field) {
|
||||
default:
|
||||
data.push(this._data)
|
||||
break
|
||||
case 'adr':
|
||||
case 'n':
|
||||
data.push(this._data.split(';'))
|
||||
}
|
||||
|
||||
return data
|
||||
},
|
||||
}
|
||||
|
||||
// Exports
|
||||
module.exports = Property
|
320
src/lib/vcf/vcard.js
Normal file
320
src/lib/vcf/vcard.js
Normal file
@ -0,0 +1,320 @@
|
||||
/**
|
||||
* vCard
|
||||
* @constructor
|
||||
* @return {vCard}
|
||||
*/
|
||||
function vCard() {
|
||||
if (!(this instanceof vCard)) return new vCard()
|
||||
|
||||
/** @type {String} Version number */
|
||||
this.version = vCard.versions[vCard.versions.length - 1]
|
||||
/** @type {Object} Card data */
|
||||
this.data = {}
|
||||
}
|
||||
|
||||
/**
|
||||
* vCard MIME type
|
||||
* @type {String}
|
||||
*/
|
||||
vCard.mimeType = 'text/vcard'
|
||||
|
||||
/**
|
||||
* vCard file extension
|
||||
* @type {String}
|
||||
*/
|
||||
vCard.extension = '.vcf'
|
||||
|
||||
/**
|
||||
* vCard versions
|
||||
* @type {Array}
|
||||
*/
|
||||
vCard.versions = ['2.1', '3.0', '4.0']
|
||||
|
||||
/**
|
||||
* Folds a long line according to the RFC 5322.
|
||||
* @see http://tools.ietf.org/html/rfc5322#section-2.1.1
|
||||
* @param {String} input
|
||||
* @param {Number} maxLength
|
||||
* @param {Boolean} hardWrap
|
||||
* @return {String}
|
||||
*/
|
||||
vCard.foldLine = require('foldline')
|
||||
|
||||
/**
|
||||
* Normalizes input (cast to string, line folding, whitespace)
|
||||
* @param {String} input
|
||||
* @return {String}
|
||||
*/
|
||||
vCard.normalize = function(input) {
|
||||
return (
|
||||
(input + '')
|
||||
// Trim whitespace
|
||||
.replace(/^[\s\r\n]+|[\s\r\n]+$/g, '')
|
||||
// Trim blank lines
|
||||
.replace(/(\r?\n)\s*(\r?\n)|$/g, '$1')
|
||||
// Unfold folded lines
|
||||
.replace(/\r?\n[\x20\x09]+/g, '') // eslint-disable-line no-control-regex
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a given version is supported
|
||||
* @param {String} version
|
||||
* @return {Boolean}
|
||||
*/
|
||||
vCard.isSupported = function(version) {
|
||||
return /^\d\.\d$/.test(version) && vCard.versions.indexOf(version) !== -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string or buffer into a vCard object
|
||||
* @param {String|Buffer} value
|
||||
* @return {Array<vCard>}
|
||||
*/
|
||||
vCard.parse = function(value) {
|
||||
var objects = (value + '').split(/(?=BEGIN\:VCARD)/gi) // eslint-disable-line no-useless-escape
|
||||
var cards = []
|
||||
|
||||
for (var i = 0; i < objects.length; i++) {
|
||||
cards.push(new vCard().parse(objects[i]))
|
||||
}
|
||||
|
||||
return cards
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an array of vcf formatted lines
|
||||
* @internal used by `vCard#parse()`
|
||||
* @type {Function}
|
||||
*/
|
||||
vCard.parseLines = require('./parse-lines')
|
||||
|
||||
/**
|
||||
* Constructs a vCard from jCard data
|
||||
* @param {Array} jcard
|
||||
* @return {vCard}
|
||||
*/
|
||||
vCard.fromJSON = function(jcard) {
|
||||
jcard = typeof jcard === 'string' ? JSON.parse(jcard) : jcard
|
||||
|
||||
if (jcard == null || !Array.isArray(jcard)) return new vCard()
|
||||
|
||||
if (!/vcard/i.test(jcard[0])) throw new Error('Object not in jCard format')
|
||||
|
||||
var card = new vCard()
|
||||
|
||||
jcard[1].forEach(function(prop) {
|
||||
card.addProperty(vCard.Property.fromJSON(prop))
|
||||
})
|
||||
|
||||
return card
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a card object according to the given version
|
||||
* @param {vCard} card
|
||||
* @param {String} version
|
||||
* @return {String}
|
||||
*/
|
||||
vCard.format = function(card, version) {
|
||||
version = version || card.version || vCard.versions[vCard.versions.length - 1]
|
||||
|
||||
if (!vCard.isSupported(version))
|
||||
throw new Error('Unsupported vCard version "' + version + '"')
|
||||
|
||||
var vcf = []
|
||||
|
||||
vcf.push('BEGIN:VCARD')
|
||||
vcf.push('VERSION:' + version)
|
||||
|
||||
var props = Object.keys(card.data)
|
||||
var prop = ''
|
||||
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
if (props[i] === 'version') continue
|
||||
prop = card.data[props[i]]
|
||||
if (Array.isArray(prop)) {
|
||||
for (var k = 0; k < prop.length; k++) {
|
||||
if (prop[k].isEmpty()) continue
|
||||
vcf.push(vCard.foldLine(prop[k].toString(version), 75))
|
||||
}
|
||||
} else if (!prop.isEmpty()) {
|
||||
vcf.push(vCard.foldLine(prop.toString(version), 75))
|
||||
}
|
||||
}
|
||||
|
||||
vcf.push('END:VCARD')
|
||||
|
||||
return vcf.join('\n')
|
||||
}
|
||||
|
||||
// vCard Property constructor
|
||||
vCard.Property = require('./property')
|
||||
|
||||
/**
|
||||
* vCard prototype
|
||||
* @type {Object}
|
||||
*/
|
||||
vCard.prototype = {
|
||||
constructor: vCard,
|
||||
|
||||
/**
|
||||
* Get a vCard property
|
||||
* @param {String} key
|
||||
* @return {Object|Array}
|
||||
*/
|
||||
get: function(key) {
|
||||
if (this.data[key] == null) {
|
||||
return this.data[key]
|
||||
}
|
||||
|
||||
if (Array.isArray(this.data[key])) {
|
||||
return this.data[key].map(function(prop) {
|
||||
return prop.clone()
|
||||
})
|
||||
} else {
|
||||
return this.data[key].clone()
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a vCard property
|
||||
* @param {String} key
|
||||
* @param {String} value
|
||||
* @param {Object} params
|
||||
*/
|
||||
set: function(key, value, params) {
|
||||
return this.setProperty(new vCard.Property(key, value, params))
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a vCard property
|
||||
* @param {String} key
|
||||
* @param {String} value
|
||||
* @param {Object} params
|
||||
*/
|
||||
add: function(key, value, params) {
|
||||
var prop = new vCard.Property(key, value, params)
|
||||
this.addProperty(prop)
|
||||
return this
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a vCard property from an already
|
||||
* constructed vCard.Property
|
||||
* @param {vCard.Property} prop
|
||||
*/
|
||||
setProperty: function(prop) {
|
||||
this.data[prop._field] = prop
|
||||
return this
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a vCard property from an already
|
||||
* constructed vCard.Property
|
||||
* @param {vCard.Property} prop
|
||||
*/
|
||||
addProperty: function(prop) {
|
||||
var key = prop._field
|
||||
|
||||
if (Array.isArray(this.data[key])) {
|
||||
this.data[key].push(prop)
|
||||
} else if (this.data[key] != null) {
|
||||
this.data[key] = [this.data[key], prop]
|
||||
} else {
|
||||
this.data[key] = prop
|
||||
}
|
||||
|
||||
return this
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse a vcf formatted vCard
|
||||
* @param {String} value
|
||||
* @return {vCard}
|
||||
*/
|
||||
parse: function(value) {
|
||||
// Normalize & split
|
||||
var lines = vCard.normalize(value).split(/\r?\n/g)
|
||||
|
||||
// Keep begin and end markers
|
||||
// for eventual error messages
|
||||
var begin = lines[0]
|
||||
var version = lines[1]
|
||||
var end = lines[lines.length - 1]
|
||||
|
||||
if (!/BEGIN:VCARD/i.test(begin))
|
||||
throw new SyntaxError(
|
||||
'Invalid vCard: Expected "BEGIN:VCARD" but found "' + begin + '"'
|
||||
)
|
||||
|
||||
if (!/END:VCARD/i.test(end))
|
||||
throw new SyntaxError(
|
||||
'Invalid vCard: Expected "END:VCARD" but found "' + end + '"'
|
||||
)
|
||||
|
||||
// TODO: For version 2.1, the VERSION can be anywhere between BEGIN & END
|
||||
if (!/VERSION:\d\.\d/i.test(version))
|
||||
throw new SyntaxError(
|
||||
'Invalid vCard: Expected "VERSION:\\d.\\d" but found "' + version + '"'
|
||||
)
|
||||
|
||||
this.version = version.substring(8, 11)
|
||||
|
||||
if (!vCard.isSupported(this.version))
|
||||
throw new Error('Unsupported version "' + this.version + '"')
|
||||
|
||||
this.data = vCard.parseLines(lines)
|
||||
|
||||
return this
|
||||
},
|
||||
|
||||
/**
|
||||
* Format the vCard as vcf with given version
|
||||
* @param {String} version
|
||||
* @param {String} charset
|
||||
* @return {String}
|
||||
*/
|
||||
toString: function(version, charset) { // eslint-disable-line no-unused-vars
|
||||
version = version || this.version
|
||||
return vCard.format(this, version)
|
||||
},
|
||||
|
||||
/**
|
||||
* Format the card as jCard
|
||||
* @param {String} version='4.0'
|
||||
* @return {Array} jCard
|
||||
*/
|
||||
toJCard: function(version) {
|
||||
version = version || '4.0'
|
||||
|
||||
var keys = Object.keys(this.data)
|
||||
var data = [['version', {}, 'text', version]]
|
||||
var prop = null
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (keys[i] === 'version') continue
|
||||
prop = this.data[keys[i]]
|
||||
if (Array.isArray(prop)) {
|
||||
for (var k = 0; k < prop.length; k++) {
|
||||
data.push(prop[k].toJSON())
|
||||
}
|
||||
} else {
|
||||
data.push(prop.toJSON())
|
||||
}
|
||||
}
|
||||
|
||||
return ['vcard', data]
|
||||
},
|
||||
|
||||
/**
|
||||
* Format the card as jCard
|
||||
* @return {Array} jCard
|
||||
*/
|
||||
toJSON: function() {
|
||||
return this.toJCard(this.version)
|
||||
},
|
||||
}
|
||||
|
||||
// Exports
|
||||
module.exports = vCard
|
@ -44,7 +44,8 @@ class NotFound extends Component {
|
||||
<h1>Shenanigans, page not found.</h1>
|
||||
<p>
|
||||
You might want to check the url, or{' '}
|
||||
<Link to={'/'}>go back to the homepage</Link>. Or just check out some fail gifs, entirely your choice.
|
||||
<Link to={'/'}>go back to the homepage</Link>. Or just check out some
|
||||
fail gifs, entirely your choice.
|
||||
</p>
|
||||
|
||||
<video className="gif" src={this.state.gif} autoPlay loop />
|
||||
|
Loading…
Reference in New Issue
Block a user