From cfcb0f03e3d033856fe3a968480cc4bd3d4f00a9 Mon Sep 17 00:00:00 2001 From: Julien Barret Date: Fri, 10 Aug 2018 18:07:40 +0200 Subject: [PATCH] #692 [WIP] Host domains and variants --- app/scripts/actions/export.actions.jsx | 72 +++++- .../library-fontinuse-create.components.jsx | 13 + .../library-hosting-create.components.jsx | 227 +++++++++++++++++- .../library/library-hosting.components.jsx | 1 + .../library/library-main.components.jsx | 19 +- app/styles/components/library.scss | 6 +- 6 files changed, 327 insertions(+), 11 deletions(-) diff --git a/app/scripts/actions/export.actions.jsx b/app/scripts/actions/export.actions.jsx index 205addce6..18ce75997 100644 --- a/app/scripts/actions/export.actions.jsx +++ b/app/scripts/actions/export.actions.jsx @@ -158,9 +158,7 @@ export default { ); if (hosting) { - const patch = prototypoStore - .set('hostingBuffer', buffer) - .commit(); + const patch = prototypoStore.set('hostingBuffer', buffer).commit(); localServer.dispatchUpdate('/prototypoStore', patch); } @@ -390,6 +388,74 @@ export default { localClient.dispatchAction('/end-export-otf'); }); }, + '/host-from-library': async ({ + familyNames, + variantNames, + valueArray, + metadataArray, + templateArray, + glyphsArray, + }) => { + const promiseArray = []; + const fontMediatorInstance = FontMediator.instance(); + + variantNames.forEach((variantName, index) => { + console.log(`exporting ${variantName} number ${index}`); + promiseArray.push( + new Promise((resolve, reject) => { + const subset = Object.keys(glyphsArray[index]).filter( + key => glyphsArray[index][key][0].unicode !== undefined, + ); + const family = familyNames[index].replace(/\s/g, '-'); + const style = variantName + ? variantName.replace(/\s/g, '-') + : 'regular'; + const name = { + family, + style: `${style.toLowerCase()}`, + }; + + console.log('getting font file'); + fontMediatorInstance + .getFontFile( + name, + templateArray[index], + {...valueArray[index]}, + subset, + undefined, + undefined, + undefined, + undefined, + metadataArray[index].weight, + metadataArray[index].width, + metadataArray[index].italic, + ) + .then((buffer) => { + console.log(`${variantName} Buffer recieved!`); + resolve(buffer); + }) + .catch((e) => { + console.log(e); + reject(e); + }); + }), + ); + }); + + Promise.all(promiseArray) + .then((blobBuffers) => { + const patch = prototypoStore + .set('hostingBuffers', blobBuffers) + .commit(); + + localServer.dispatchUpdate('/prototypoStore', patch); + }) + .catch((e) => { + console.log('An error occured'); + console.log(e); + localClient.dispatchAction('/end-export-otf'); + }); + }, '/end-export-otf': () => { console.log('Export finished'); localClient.dispatchAction('/store-value-font', {exportPlease: false}); diff --git a/app/scripts/components/library/library-fontinuse-create.components.jsx b/app/scripts/components/library/library-fontinuse-create.components.jsx index 54b4b69f7..1398be30a 100644 --- a/app/scripts/components/library/library-fontinuse-create.components.jsx +++ b/app/scripts/components/library/library-fontinuse-create.components.jsx @@ -496,6 +496,19 @@ const libraryUserQuery = gql` } template } + hostedDomains { + id + domain + hostedVariants { + id + createdAt + origin { + id + } + url + version + } + } } } `; diff --git a/app/scripts/components/library/library-hosting-create.components.jsx b/app/scripts/components/library/library-hosting-create.components.jsx index edf7afa7c..57bd7d45a 100644 --- a/app/scripts/components/library/library-hosting-create.components.jsx +++ b/app/scripts/components/library/library-hosting-create.components.jsx @@ -1,10 +1,13 @@ import React from 'react'; import {Link} from 'react-router'; +import Lifespan from 'lifespan'; +import {graphql, gql, compose} from 'react-apollo'; import {LibrarySidebarRight} from './library-sidebars.components'; +import {tmpUpload} from '../../services/graphcool.services'; import LocalClient from '../../stores/local-client.stores'; import FontUpdater from '../font-updater.components'; -export default class LibraryHostingCreate extends React.Component { +class LibraryHostingCreate extends React.Component { constructor(props) { super(props); this.state = { @@ -22,17 +25,57 @@ export default class LibraryHostingCreate extends React.Component { this, ); this.addSuggestion = this.addSuggestion.bind(this); - this.addWebsite = this.addWebsite.bind(this); + this.hostFonts = this.hostFonts.bind(this); } async componentWillMount() { this.client = LocalClient.instance(); + this.lifespan = new Lifespan(); + const prototypoStore = await this.client.fetch('/prototypoStore'); + this.client.getStore('/prototypoStore', this.lifespan).onUpdate((head) => { + this.setState({ + buffers: head.toJS().d.hostingBuffers, + }); + }); this.setState({ templateInfos: await prototypoStore.head.toJS().templateList, templatesData: await prototypoStore.head.toJS().templatesData, }); } + async componentDidUpdate(prevState) { + if ( + prevState.buffers !== this.state.buffers + && this.state.status === 'generating' + ) { + this.setState({status: 'uploading'}); + + const urls = await Promise.all( + this.state.buffers.map(async (buffer, index) => + tmpUpload( + new Blob([new Uint8Array(buffer)]), + `${this.state.addedFonts[index]} ${ + this.state.addedFonts[index].variant.name + }`, + ), + ), + ); + + const hostedFonts = await Promise.all( + urls.map(({url}, index) => + this.props.hostFont(this.state.addedFonts[index].variant.id, url), + ), + ); + + this.props + .createHostedDomain( + this.state.domain, + hostedFonts.map(({data}) => data.hostFont.id), + ) + .then(() => this.props.router.push('/library/hosting')); + this.setState({status: 'hosting'}); + } + } addSuggestion(suggestion, variant) { if ( !this.state.addedFonts.find( @@ -44,6 +87,7 @@ export default class LibraryHostingCreate extends React.Component { let templateData; let preset; let family; + let glyphs; this.setState({ errors: { @@ -57,6 +101,7 @@ export default class LibraryHostingCreate extends React.Component { templateData = this.state.templatesData.find( e => e.name === suggestion.templateName, ); + glyphs = templateData.glyphs; values = templateData.initValues; template = templateData.templateName; break; @@ -68,6 +113,10 @@ export default class LibraryHostingCreate extends React.Component { template = this.state.templateInfos.find( t => preset.template === t.templateName, ).templateName; + templateData = this.state.templatesData.find( + e => e.name === preset.template, + ); + glyphs = templateData.glyphs; break; case 'Family': family @@ -76,6 +125,7 @@ export default class LibraryHostingCreate extends React.Component { templateData = this.state.templatesData.find( e => e.name === family.template, ); + glyphs = templateData.glyphs; values = { ...templateData.initValues, ...(typeof variant.values === 'object' @@ -98,6 +148,7 @@ export default class LibraryHostingCreate extends React.Component { variant, template, values, + glyphs, }, ]), }); @@ -208,7 +259,7 @@ export default class LibraryHostingCreate extends React.Component { }); } - addWebsite() { + hostFonts() { const domain = this.state.domain .replace('http://', '') .replace('https://', '') @@ -245,6 +296,41 @@ export default class LibraryHostingCreate extends React.Component { hostedFonts: false, }, }); + const familyNames = []; + const variantNames = []; + const valueArray = []; + const metadataArray = []; + const templateArray = []; + const glyphsArray = []; + + this.state.addedFonts.forEach((addedFont) => { + familyNames.push(addedFont.name); + variantNames.push(addedFont.variant.name); + valueArray.push(addedFont.values); + metadataArray.push({ + weight: addedFont.variant.weight, + width: addedFont.variant.width, + italic: !!addedFont.variant.italic, + }); + templateArray.push(addedFont.template); + glyphsArray.push(addedFont.glyphs); + }); + try { + this.setState({status: 'generating'}); + + // generate the font + this.client.dispatchAction('/host-from-library', { + familyNames, + variantNames, + valueArray, + metadataArray, + templateArray, + glyphsArray, + }); + } + catch (err) { + console.log(err.message); + } } render() { @@ -372,7 +458,7 @@ export default class LibraryHostingCreate extends React.Component {
{ - this.addWebsite(); + this.hostFonts(); }} > Add website @@ -390,3 +476,136 @@ export default class LibraryHostingCreate extends React.Component { ); } } + +const hostVariantMutation = gql` + mutation hostVariant($id: ID!, $tmpFileUrl: String!) { + hostFont(variantId: $id, tmpFileUrl: $tmpFileUrl) { + id + url + version + createdAt + } + } +`; + +const createHostedDomainMutation = gql` + mutation createHostedDomain( + $domain: String! + $creatorId: ID! + $hostedVariantsIds: [ID!]! + ) { + createHostedDomain( + domain: $domain + creatorId: $creatorId + hostedVariantsIds: $hostedVariantsIds + ) { + id + domain + hostedVariants { + id + url + createdAt + origin { + id + } + version + } + } + } +`; + +const libraryUserQuery = gql` + query getLibraryUserInfos { + user { + id + firstName + lastName + fontInUses { + id + client + clientUrl + designer + designerUrl + images + fontUsed { + id + name + family { + id + } + type + template + preset { + id + } + } + } + favourites { + id + name + updatedAt + type + preset { + id + } + family { + id + variants { + id + } + } + template + } + hostedDomains { + id + domain + hostedVariants { + id + createdAt + origin { + id + } + url + version + } + } + } + } +`; + +export default compose( + graphql(hostVariantMutation, { + props: ({mutate}) => ({ + hostFont: (id, tmpFileUrl) => + mutate({ + variables: { + id, + tmpFileUrl, + }, + }), + }), + }), + graphql(createHostedDomainMutation, { + props: ({mutate, ownProps}) => ({ + createHostedDomain: (domain, hostedVariantsIds) => + mutate({ + variables: { + domain, + hostedVariantsIds, + creatorId: ownProps.user.id, + }, + }), + }), + options: { + update: (store, {data: {createHostedDomain}}) => { + const data = store.readQuery({query: libraryUserQuery}); + + data.user.hostedDomains.push(createHostedDomain); + store.writeQuery({ + query: libraryUserQuery, + data, + }); + }, + }, + }), +)(LibraryHostingCreate); diff --git a/app/scripts/components/library/library-hosting.components.jsx b/app/scripts/components/library/library-hosting.components.jsx index f655780f6..fcee96586 100644 --- a/app/scripts/components/library/library-hosting.components.jsx +++ b/app/scripts/components/library/library-hosting.components.jsx @@ -11,6 +11,7 @@ export default class LibraryHosting extends React.Component { } render() { + console.log(this.props.hostedDomains); return (
diff --git a/app/scripts/components/library/library-main.components.jsx b/app/scripts/components/library/library-main.components.jsx index 11c69519a..c1dee8326 100644 --- a/app/scripts/components/library/library-main.components.jsx +++ b/app/scripts/components/library/library-main.components.jsx @@ -217,6 +217,7 @@ class LibraryMain extends React.Component { updateTags: this.props.updateTags, favourites: this.props.favourites, addFavourite: this.props.addFavourite, + hostedDomains: this.props.hostedDomains, deleteFavourite: this.props.deleteFavourite, user: { firstName: this.props.firstName, @@ -344,9 +345,9 @@ const libraryUserQuery = gql` } favourites { id - type - updatedAt name + updatedAt + type preset { id } @@ -358,6 +359,19 @@ const libraryUserQuery = gql` } template } + hostedDomains { + id + domain + hostedVariants { + id + createdAt + origin { + id + } + url + version + } + } } } `; @@ -494,6 +508,7 @@ export default compose( userId: data.user.id, favourites: data.user.favourites, fontInUses: data.user.fontInUses, + hostedDomains: data.user.hostedDomains, } ); }, diff --git a/app/styles/components/library.scss b/app/styles/components/library.scss index ec1b46530..0c4d00f63 100644 --- a/app/styles/components/library.scss +++ b/app/styles/components/library.scss @@ -324,7 +324,8 @@ } input, select { - width: 50%; + width: 100%; + max-width: 950px; background: transparent; box-shadow: none; outline: none; @@ -365,7 +366,8 @@ max-height: 200px; overflow-x: hidden; overflow-y: auto; - width: 50%; + width: 100%; + max-width: 950px; .suggestion { padding-top: 5px; padding-bottom: 5px;