Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New: Add font and CSS/Less support for theme picker (fixes #4) #2

Closed
wants to merge 11 commits into from
76 changes: 73 additions & 3 deletions lib/CourseThemeModule.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,14 @@ class CourseThemeModule extends AbstractApiModule {
* @param {AdaptFrameworkBuild} fwBuild Reference to the current build
*/
async writeCustomLess (fwBuild) {
const { customStyle, [this.attributeKey]: variables } = fwBuild.courseData.course.data
const fontImportString = await this.processFileVariables(fwBuild)
this.processCustomStyling(fwBuild)

const { customStyle, [this.attributeKey]: variables, themeCustomStyle } = fwBuild.courseData.course.data
return Promise.all([
this.writeFile(fwBuild, '1-variables.less', this.getVariablesString(variables)),
this.writeFile(fwBuild, '2-customStyles.less', customStyle)
this.writeFile(fwBuild, '1-variables.less', fontImportString + this.getVariablesString(variables)),
this.writeFile(fwBuild, '2-customStyles.less', customStyle),
this.writeFile(fwBuild, '3-themeCustomStyles.less', themeCustomStyle)
])
}

Expand Down Expand Up @@ -123,6 +127,72 @@ class CourseThemeModule extends AbstractApiModule {
}
}
}

/**
* Copies uploaded font files into the build
* @param {object} data The data to process
*/
async processFileVariables (fwBuild) {
const assets = await this.app.waitForModule('assets')
const themeDir = `${fwBuild.dir}/src/theme/${fwBuild.courseData.config.data._theme}`
const fontData = fwBuild.courseData.course.data.themeVariables._font

if (!fontData) {
return ''
}
let fontImportCSS = ''
// font files
if (fontData._items) {
await Promise.all(fontData._items.map(async f => {
if (!f['font-family']) return
// copy each uploaded font file
for (const font in f._files) {
const [data] = await assets.find({ _id: f._files[font] })
const asset = assets.createFsWrapper(data)
try {
const relativeFontPath = `fonts/${f._files[font]}.${asset.data.subtype}`
await fs.writeFile(`${themeDir}/${relativeFontPath}`, await asset.read())
// construct font import styling
const fontStyle = font.includes('Italic') ? 'italic' : 'normal'
const fontWeight = font.includes('light') ? 'light' : font.includes('bold') ? 'bold' : 'normal'
fontImportCSS += `@font-face ${JSON.stringify({
'font-family': `${f['font-family']};`,
src: `url('./${relativeFontPath}') format('${asset.data.subtype}');`,
'font-weight': `${fontWeight};\n\tfont-style: ${fontStyle};`
}, null, 2)}`
} catch (e) {
this.log('error', `failed to write ${f._files[font]}, ${e.message}`)
}
}
}))
delete fontData._items
}
// instruction style checkbox
const _instruction = fontData._fontAssignments._instruction
if (_instruction['instruction-font-style']) {
_instruction['instruction-font-style'] = _instruction._isInstructionItalic ? 'italic' : 'normal'
delete _instruction._isInstructionItalic
}
// external fonts
if (fontData._externalFonts) {
fontData._externalFonts.forEach(f => {
if (f) fontImportCSS += `@import url('${f}');\n`
})
delete fontData._externalFonts
}

return fontImportCSS
}

processCustomStyling (fwBuild) {
const customStyling = fwBuild.courseData.course.data.themeVariables.themeCustomStyle

if (!customStyling) return

fwBuild.courseData.course.data.themeCustomStyle = customStyling

delete fwBuild.courseData.course.data.themeVariables.themeCustomStyle
}
}

export default CourseThemeModule