Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions src/fonts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Font information for solid-ui / Mashlib.
*
* The UI references the following font families in its inline styles:
*
* - **Raleway** and **Roboto**: used for primary and secondary buttons
* (`font-family: Raleway, Roboto, sans-serif`). These are web fonts that
* are _not_ bundled with the library; they must be loaded separately by the
* host application (e.g. via `loadFonts()`).
*
* - **Arial**: used for header menu links and buttons. Arial is a system font
* on Windows and macOS; on other platforms the browser will fall back to the
* next `sans-serif` font.
*
* - **monospace** and **sans-serif**: generic CSS font families used for the
* notepad / pad widget and heading elements respectively.
*
* Use `loadFonts()` to inject the Raleway and Roboto web fonts into the
* document so that they are available on all platforms.
*/

import styleConstants from './styleConstants'

/** Names of the web fonts that solid-ui references in its styles. */
export const fontNames = {
/** Primary font for buttons. */
button: 'Raleway',
/** Fallback font for buttons when Raleway is unavailable. */
buttonFallback: 'Roboto'
}

/**
* Full CSS font-family stacks as used in the inline styles.
* These match the values in `styleConstants`.
*/
export const fontFamilies = {
/** Font stack for primary and secondary buttons. */
button: styleConstants.fontFamilyButton,
/** Font stack for header menus and navigation links. */
header: styleConstants.fontFamilyHeader
}

/**
* Injects a `<link>` element into the document `<head>` to load Raleway and
* Roboto from the provided base URL (defaults to Google Fonts).
*
* Call this once during application initialisation so that the web fonts
* referenced in solid-ui styles are actually available to the browser.
*
* @param fontsUrl - The URL of the CSS file that declares `@font-face` rules
* for Raleway and Roboto. Defaults to a Google Fonts stylesheet. Pass a
* self-hosted URL to avoid sending requests to third-party servers.
*/
export function loadFonts (
fontsUrl = 'https://fonts.googleapis.com/css2?family=Raleway:wght@400;700&family=Roboto:wght@400;700&display=swap'
): void {
if (typeof document === 'undefined') return

// Avoid adding duplicate <link> elements.
const existing = document.querySelector(`link[data-solid-ui-fonts]`)
if (existing) return

const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = fontsUrl
link.setAttribute('data-solid-ui-fonts', 'true')
document.head.appendChild(link)
}
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import * as pad from './pad'
import * as participation from './participation'
// @ts-ignore
import * as preferences from './preferences'
import * as fonts from './fonts'
// @ts-ignore
import { style } from './style'
// @ts-ignore
Expand All @@ -80,6 +81,7 @@ if (typeof window !== 'undefined') {
create,
createTypes,
dom,
fonts,
icons,
language,
log,
Expand Down Expand Up @@ -109,6 +111,7 @@ export {
create,
createTypes,
dom,
fonts,
icons,
language,
log,
Expand Down
24 changes: 12 additions & 12 deletions src/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@ export const style = { // styleModule
temporaryStatusEnd: 'background: transparent; transition: background 5s linear;',

// header
headerUserMenuLink: 'background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none;',
headerUserMenuLinkHover: 'background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none; background-image: linear-gradient(to right, #7C4DFF 0%, #18A9E6 50%, #01C9EA 100%);',
headerUserMenuLink: `background: none; border: 0; color: black; cursor: pointer; display: block; font-family: ${styleConstants.fontFamilyHeader}; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none;`,
headerUserMenuLinkHover: `background: none; border: 0; color: black; cursor: pointer; display: block; font-family: ${styleConstants.fontFamilyHeader}; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none; background-image: linear-gradient(to right, #7C4DFF 0%, #18A9E6 50%, #01C9EA 100%);`,
headerUserMenuTrigger: 'background: none; border: 0; cursor: pointer; width: 60px; height: 60px;',
headerUserMenuTriggerImg: 'border-radius: 50%; height: 56px; width: 28px !important;',
headerUserMenuButton: 'background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial; font-size: 1em; text-align: left; padding: 1em; width: 100%;',
headerUserMenuButtonHover: 'background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial; font-size: 1em; text-align: left; padding: 1em; width: 100%; background-image: linear-gradient(to right, #7C4DFF 0%, #18A9E6 50%, #01C9EA 100%);',
headerUserMenuButton: `background: none; border: 0; color: black; cursor: pointer; display: block; font-family: ${styleConstants.fontFamilyHeader}; font-size: 1em; text-align: left; padding: 1em; width: 100%;`,
headerUserMenuButtonHover: `background: none; border: 0; color: black; cursor: pointer; display: block; font-family: ${styleConstants.fontFamilyHeader}; font-size: 1em; text-align: left; padding: 1em; width: 100%; background-image: linear-gradient(to right, #7C4DFF 0%, #18A9E6 50%, #01C9EA 100%);`,
headerUserMenuList: 'list-style: none; margin: 0; padding: 0;',
headerUserMenuListDisplay: 'list-style: none; margin: 0; padding: 0; display:true;',
headerUserMenuNavigationMenu: 'background: white; border: solid 1px #000000; border-right: 0; position: absolute; right: 0; top: 60px; width: 200px; z-index: 1; display: true;',
Expand All @@ -114,14 +114,14 @@ export const style = { // styleModule
footer: 'border-top: solid 1px $divider-color; font-size: 0.9em; padding: 0.5em 1.5em;',

// buttons
primaryButton: 'background-color: #7c4dff; color: #ffffff; font-family: Raleway, Roboto, sans-serif; border-radius: 0.25em; border-color: #7c4dff; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none;',
primaryButtonHover: 'background-color: #9f7dff; color: #ffffff; font-family: Raleway, Roboto, sans-serif;border-radius: 0.25em; border-color: #7c4dff; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none; transition: 0.25s all ease-in-out;',
primaryButtonNoBorder: 'background-color: #ffffff; color: #7c4dff; font-family: Raleway, Roboto, sans-serif;border-radius: 0.25em; border-color: #7c4dff; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none;',
primaryButtonNoBorderHover: 'background-color: #7c4dff; color: #ffffff; font-family: Raleway, Roboto, sans-serif; border-radius: 0.25em; border-color: #7c4dff; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none; transition: 0.25s all ease-in-out;',
secondaryButton: 'background-color: #01c9ea; color: #ffffff; font-family: Raleway, Roboto, sans-serif;border-radius: 0.25em; border-color: #01c9ea; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none;',
secondaryButtonHover: 'background-color: #37cde6; color: #ffffff; font-family: Raleway, Roboto, sans-serif;border-radius: 0.25em; border-color: #7c4dff; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none; transition: 0.25s all ease-in-out;',
secondaryButtonNoBorder: 'background-color: #ffffff; color: #01c9ea; font-family: Raleway, Roboto, sans-serif; border-radius: 0.25em; border-color: #01c9ea; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none;',
secondaryButtonNoBorderHover: 'background-color: #01c9ea; color: #ffffff; font-family: Raleway, Roboto, sans-serif; border-radius: 0.25em; border-color: #01c9ea; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none; transition: 0.25s all ease-in-out;',
primaryButton: `background-color: #7c4dff; color: #ffffff; font-family: ${styleConstants.fontFamilyButton}; border-radius: 0.25em; border-color: #7c4dff; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none;`,
primaryButtonHover: `background-color: #9f7dff; color: #ffffff; font-family: ${styleConstants.fontFamilyButton}; border-radius: 0.25em; border-color: #7c4dff; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none; transition: 0.25s all ease-in-out;`,
primaryButtonNoBorder: `background-color: #ffffff; color: #7c4dff; font-family: ${styleConstants.fontFamilyButton}; border-radius: 0.25em; border-color: #7c4dff; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none;`,
primaryButtonNoBorderHover: `background-color: #7c4dff; color: #ffffff; font-family: ${styleConstants.fontFamilyButton}; border-radius: 0.25em; border-color: #7c4dff; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none; transition: 0.25s all ease-in-out;`,
secondaryButton: `background-color: #01c9ea; color: #ffffff; font-family: ${styleConstants.fontFamilyButton}; border-radius: 0.25em; border-color: #01c9ea; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none;`,
secondaryButtonHover: `background-color: #37cde6; color: #ffffff; font-family: ${styleConstants.fontFamilyButton}; border-radius: 0.25em; border-color: #7c4dff; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none; transition: 0.25s all ease-in-out;`,
secondaryButtonNoBorder: `background-color: #ffffff; color: #01c9ea; font-family: ${styleConstants.fontFamilyButton}; border-radius: 0.25em; border-color: #01c9ea; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none;`,
secondaryButtonNoBorderHover: `background-color: #01c9ea; color: #ffffff; font-family: ${styleConstants.fontFamilyButton}; border-radius: 0.25em; border-color: #01c9ea; border: 1px solid; cursor: pointer; font-size: .8em; text-decoration: none; padding: 0.5em 4em; transition: 0.25s all ease-in-out; outline: none; transition: 0.25s all ease-in-out;`,

// media
controlStyle: `border-radius: 0.5em; margin: 0.8em; width:${styleConstants.mediaModuleCanvasWidth}; height:${styleConstants.mediaModuleCanvasHeight};`,
Expand Down
4 changes: 4 additions & 0 deletions src/styleConstants.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
export default {
highlightColor: '#7C4DFF', // Solid lavender https://design.inrupt.com/atomic-core/?cat=Core

// Font families referenced throughout the UI
fontFamilyButton: 'Raleway, Roboto, sans-serif', // Used for primary and secondary buttons
fontFamilyHeader: 'Arial, sans-serif', // Used for header menus and navigation

formBorderColor: '#888888', // Mid-grey
formHeadingColor: '#888888', // originally was brown; now grey
lowProfileLinkColor: '#3B5998', // Grey-blue, e.g., for field labels linking to ontology
Expand Down
62 changes: 62 additions & 0 deletions test/unit/fonts.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { fontNames, fontFamilies, loadFonts } from '../../src/fonts'

describe('fontNames', () => {
it('exposes the primary button font name', () => {
expect(fontNames.button).toEqual('Raleway')
})

it('exposes the button fallback font name', () => {
expect(fontNames.buttonFallback).toEqual('Roboto')
})
})

describe('fontFamilies', () => {
it('includes the button font family string', () => {
expect(typeof fontFamilies.button).toEqual('string')
expect(fontFamilies.button).toContain('Raleway')
expect(fontFamilies.button).toContain('Roboto')
expect(fontFamilies.button).toContain('sans-serif')
})

it('includes the header font family string', () => {
expect(typeof fontFamilies.header).toEqual('string')
expect(fontFamilies.header).toContain('Arial')
expect(fontFamilies.header).toContain('sans-serif')
})
})

describe('loadFonts', () => {
beforeEach(() => {
// Clear any <link> elements added by previous tests
document.querySelectorAll('link[data-solid-ui-fonts]').forEach(el => el.remove())
})

it('appends a <link> element to document.head', () => {
loadFonts()
const link = document.querySelector('link[data-solid-ui-fonts]')
expect(link).not.toBeNull()
expect(link!.getAttribute('rel')).toEqual('stylesheet')
})

it('uses the default Google Fonts URL when no argument is supplied', () => {
loadFonts()
const link = document.querySelector('link[data-solid-ui-fonts]') as HTMLLinkElement
expect(link.href).toContain('fonts.googleapis.com')
expect(link.href).toContain('Raleway')
expect(link.href).toContain('Roboto')
})

it('accepts a custom font URL', () => {
const customUrl = 'https://example.com/fonts.css'
loadFonts(customUrl)
const link = document.querySelector('link[data-solid-ui-fonts]') as HTMLLinkElement
expect(link.href).toEqual(customUrl)
})

it('does not add duplicate <link> elements when called multiple times', () => {
loadFonts()
loadFonts()
const links = document.querySelectorAll('link[data-solid-ui-fonts]')
expect(links.length).toEqual(1)
})
})
14 changes: 7 additions & 7 deletions test/unit/header/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ exports[`createBanner check customized logo... 1`] = `
>
<a
href="https://reflectechblog.wordpress.com/"
style="background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none;"
style="background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial, sans-serif; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none;"
/>
</li>
</ul>
Expand All @@ -119,7 +119,7 @@ exports[`createBanner check customized logo... 1`] = `
>
<a
href="https://reflectechblog.wordpress.com/"
style="background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none;"
style="background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial, sans-serif; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none;"
/>
</li>
</ul>
Expand Down Expand Up @@ -235,7 +235,7 @@ exports[`createBanner creates a link 1`] = `
>
<a
href="https://reflectechblog.wordpress.com/"
style="background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none;"
style="background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial, sans-serif; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none;"
/>
</li>
</ul>
Expand All @@ -257,7 +257,7 @@ exports[`createBanner creates a link 1`] = `
>
<a
href="https://reflectechblog.wordpress.com/"
style="background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none;"
style="background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial, sans-serif; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none;"
/>
</li>
</ul>
Expand Down Expand Up @@ -407,7 +407,7 @@ exports[`createUserMenu creates a menu.... 1`] = `
>
<a
href="https://reflectechblog.wordpress.com/"
style="background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none;"
style="background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial, sans-serif; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none;"
/>
</li>
</ul>
Expand All @@ -417,7 +417,7 @@ exports[`createUserMenu creates a menu.... 1`] = `

exports[`createUserMenuButton creates a button 1`] = `
<button
style="background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial; font-size: 1em; text-align: left; padding: 1em; width: 100%;"
style="background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial, sans-serif; font-size: 1em; text-align: left; padding: 1em; width: 100%;"
/>
`;

Expand All @@ -432,7 +432,7 @@ exports[`createUserMenuItem creates a link 1`] = `
exports[`createUserMenuLink creates a link 1`] = `
<a
href="http://www.test.com"
style="background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none;"
style="background: none; border: 0; color: black; cursor: pointer; display: block; font-family: Arial, sans-serif; font-size: 1em; text-align: left; padding: 1em; width: 100%; text-decoration: none;"
/>
`;

Expand Down
1 change: 1 addition & 0 deletions test/unit/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe('Index', () => {
'create',
'createTypes',
'dom',
'fonts',
'icons',
'infiniteMessageArea',
'initFooter',
Expand Down