Skip to content

Commit 9e3d6a3

Browse files
authored
Merge pull request #34 from basiclines/develop
Add Display Network implementation
2 parents 867bdf3 + 125c93c commit 9e3d6a3

6 files changed

Lines changed: 171 additions & 6 deletions

File tree

src/App.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@
4646
--color-separator: rgba(0, 0, 0, 0.12);
4747
}
4848

49-
body { text-align: left; }
50-
root-ui { transition: opacity 0.05s linear; display: block; }
49+
body { text-align: left; overflow: hidden; }
50+
root-ui { transition: opacity 0.05s linear; display: block; position: relative; height: 539px; }
5151
root-ui[notready] { opacity: 0; pointer-events: none; }
5252

5353
.c-icon {

src/App.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,23 @@ import Element from 'src/ui/Element'
99
import 'src/ui/components/toolbar/ToolbarComponent'
1010
import 'src/ui/views/form/FormView'
1111
import 'src/ui/views/preferences/PreferencesView'
12+
import 'src/ui/components/display/DisplayComponent'
1213

1314

1415
class ui extends Element {
1516

1617
beforeMount() {
1718
window.addEventListener('message', e => {
1819
let msg = event.data.pluginMessage
19-
if (msg.type == 'init') {
20+
if (msg.type == 'init-hidden' || msg.type == 'init') {
2021
this.data.preferences = msg.preferences
2122
Tracking.setup(WP_AMPLITUDE_KEY, msg.UUID)
2223
Tracking.track('openPlugin', { cmd: msg.cmd })
2324
}
25+
26+
if (msg.type == 'init') {
27+
this.insertDisplay(msg.AD_LAST_SHOWN_DATE)
28+
}
2429
})
2530

2631
Router.setup({
@@ -33,6 +38,13 @@ class ui extends Element {
3338
Router.on('change:url', url => this.showActiveView(url))
3439
}
3540

41+
insertDisplay(lastShownDate) {
42+
let elem = document.createElement('c-display')
43+
elem.setAttribute('lastshowndate', lastShownDate)
44+
elem.setAttribute('hidden', '')
45+
document.body.insertBefore(elem, document.body.querySelector('root-ui'))
46+
}
47+
3648
showActiveView(url) {
3749
let view = url.replace('#', '')
3850
this.findAll('[data-view]').forEach(view => view.setAttribute('hidden', ''))

src/Core.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,13 @@ function cmdTidy(xSpacing, ySpacing, wrapInstances) {
148148
Promise.all([
149149
figma.clientStorage.getAsync('UUID'),
150150
figma.clientStorage.getAsync('preferences'),
151+
figma.clientStorage.getAsync('AD_LAST_SHOWN_DATE'),
151152
figma.clientStorage.getAsync('spacing') // legacy
152153
]).then(values => {
153154
let UUID = values[0]
154155
let preferences = values[1]
155-
let spacing = values[2]
156+
let AD_LAST_SHOWN_DATE = values[2] || 572083200 // initial date, if no date was saved previously
157+
let spacing = values[3]
156158

157159
let SPACING = { x: 100, y: 200 }
158160
let START_NAME = '000'
@@ -180,7 +182,12 @@ Promise.all([
180182
preferences = PREFERENCES
181183
}
182184

183-
figma.ui.postMessage({ type: 'init', UUID: UUID, cmd: cmd, preferences: preferences })
185+
figma.ui.postMessage({
186+
type: 'init-hidden',
187+
UUID: UUID,
188+
cmd: cmd,
189+
preferences: preferences
190+
})
184191

185192
// Command triggered by user
186193
if (cmd == 'rename') {
@@ -212,7 +219,13 @@ Promise.all([
212219
if (cmd == 'options') {
213220
// OPEN UI
214221
figma.showUI(__html__, { width: 320, height: 540 })
215-
figma.ui.postMessage({ type: 'init', UUID: UUID, cmd: cmd, preferences: preferences })
222+
figma.ui.postMessage({
223+
type: 'init',
224+
UUID: UUID,
225+
cmd: cmd,
226+
preferences: preferences,
227+
AD_LAST_SHOWN_DATE: AD_LAST_SHOWN_DATE
228+
})
216229
figma.ui.postMessage({ type: 'selection', selection: figma.currentPage.selection })
217230

218231
figma.on('selectionchange', () => {
@@ -235,6 +248,10 @@ Promise.all([
235248
preferences = msg.preferences
236249
figma.clientStorage.setAsync('preferences', preferences)
237250
figma.notify('Preferences saved')
251+
} else
252+
if (msg.type === 'displayImpression') {
253+
figma.ui.resize(320, 540+124)
254+
figma.clientStorage.setAsync('AD_LAST_SHOWN_DATE', Date.now())
238255
}
239256
}
240257
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
c-display[hidden] { display: block!important; height: 0; padding: 0 16px; opacity: 0.4; border: none; pointer-events: none; }
2+
3+
c-display { display: block; padding: 8px 16px 16px; background: var(--color-decorator-soft); border-bottom: solid 1px var(--color-decorator-regular); transition: all 0.25s ease-out; }
4+
c-display picture { position: relative; width: 48px; height: 48px; border-radius: 8px; margin-right: 16px; float: left; overflow: hidden; }
5+
c-display picture img { width: 100%; }
6+
c-display picture:after { content: ""; position: absolute; left: 0; top: 0; right: 0; bottom: 0; border: solid 1px var(--color-decorator-regular); border-radius: 8px; }
7+
8+
c-display section { overflow: hidden; }
9+
c-display em { display: block; font: var(--type-small-normal); color: var(--color-text-tertiary); margin: 0 0 8px; }
10+
c-display h1 { font: var(--type-large-bold); line-height: 16px; color: var(--color-text-primary); margin-bottom: 4px; }
11+
c-display p { font: var(--type-medium-normal); color: var(--color-text-secondary); margin-bottom: 8px; }
12+
c-display a { font: var(--type-medium-medium); color: var(--color-interactive-positive); }
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import './DisplayComponent.css'
2+
import Element from 'src/ui/Element'
3+
import DisplayNetwork from 'src/utils/DisplayNetwork'
4+
import Tracking from 'src/utils/Tracking'
5+
6+
const PLUGIN_NAME = 'super_tidy'
7+
8+
class DisplayComponent extends Element {
9+
10+
beforeMount() {
11+
// avoid display without proper data
12+
if (this.attrs.lastshowndate == 'undefined') return
13+
14+
DisplayNetwork.getAvailableAd(this.attrs.lastshowndate)
15+
.then(ad => {
16+
// if we have an available ad, then render and display it
17+
if (!!ad) {
18+
ad.link = ad.link + '?utm_source=figma&utm_medium=partner&utm_campaign='+PLUGIN_NAME
19+
this.data.ad = ad
20+
this.showDisplay()
21+
}
22+
})
23+
}
24+
25+
showDisplay() {
26+
this.removeAttribute('hidden')
27+
Tracking.track('displayImpression', { campaign: this.data.ad.tracking })
28+
parent.postMessage({ pluginMessage: { type: 'displayImpression' } }, '*')
29+
}
30+
31+
bind() {
32+
this.addEventListener('click', e => {
33+
if (e.target.getAttribute('data-trigger') == 'cta') {
34+
Tracking.track('displayClick', { campaign: this.data.ad.tracking })
35+
}
36+
})
37+
}
38+
39+
render() {
40+
if (!this.data.ad) return
41+
42+
let ad = this.data.ad
43+
return `
44+
<em>Sponsored</em>
45+
<picture><img src="${ad.icon}" /></picture>
46+
<section>
47+
<h1>${ad.headline}</h1>
48+
<p>${ad.description}</p>
49+
<a data-trigger="cta" href="${ad.link}" target="_blank">${this.data.ad.cta}</a>
50+
</section>
51+
`
52+
}
53+
}
54+
55+
customElements.define('c-display', DisplayComponent)

src/utils/DisplayNetwork.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
let singleton = null
2+
const DAILY_INTERVAL = 86400000
3+
const WEEKLY_INTERVAL = DAILY_INTERVAL*7
4+
const MONTHLY_INTERVAL = WEEKLY_INTERVAL*4
5+
6+
class DisplayNetwork {
7+
8+
constructor() {
9+
this.root = 'https://figma-plugins-display-network.netlify.app/api.json'
10+
this.timeStampNow = Date.now()
11+
12+
if (!singleton) singleton = this
13+
return singleton
14+
}
15+
16+
getAds() {
17+
return fetch(this.root, { method: 'GET' })
18+
}
19+
20+
getAvailableAd(lastShownDate) {
21+
return new Promise((resolve, reject) => {
22+
this.getAds().then(response => {
23+
response.json().then(ads => {
24+
25+
let availableAds = ads.reduce((prev, current) => {
26+
if (this.checkImpressionAvailability(parseInt(lastShownDate), current)) {
27+
prev.push(current)
28+
}
29+
return prev
30+
}, [])
31+
32+
resolve(availableAds[this.getRandomInt(0, availableAds.length)])
33+
})
34+
}).catch(error => console.log('Error getAvailableAd', error))
35+
})
36+
}
37+
38+
getRandomInt(min, max) {
39+
min = Math.ceil(min);
40+
max = Math.floor(max);
41+
return Math.floor(Math.random() * (max - min) + min); //The maximum is exclusive and the minimum is inclusive
42+
}
43+
44+
getAdInterval(ad) {
45+
if (WP_ENV == 'development') return 1000
46+
47+
let interval = 0
48+
switch (ad.impression_interval) {
49+
case 'daily': interval = DAILY_INTERVAL
50+
break;
51+
case 'weekly': interval = WEEKLY_INTERVAL
52+
break;
53+
case 'monthly': interval = MONTHLY_INTERVAL
54+
break;
55+
}
56+
57+
return interval
58+
}
59+
60+
checkImpressionAvailability(lastShownDate, ad) {
61+
let adInterval = this.getAdInterval(ad)
62+
let availableTimeWindow = (!lastShownDate || lastShownDate + adInterval < this.timeStampNow)
63+
64+
return availableTimeWindow
65+
}
66+
67+
}
68+
69+
export default new DisplayNetwork()

0 commit comments

Comments
 (0)