├── next.config.js ├── .gitignore ├── screen.png ├── now.json ├── components ├── FontSelector │ ├── Section.js │ ├── Container.js │ ├── Label.js │ ├── Select.js │ ├── InputNumber.js │ ├── SelectField.js │ └── index.js ├── FontImporter.js └── FontDemo.js ├── README.md ├── bin └── update-fonts.js ├── data └── fonts.js ├── pages └── index.js ├── reducers └── FontReducer.js └── package.json /next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | target: 'serverless' 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .next 2 | node_modules 3 | data/familyMetadataList.json 4 | package-lock.json -------------------------------------------------------------------------------- /screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/border-radius/play-with-fonts/master/screen.png -------------------------------------------------------------------------------- /now.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "builds": [{ 4 | "src": "next.config.js", 5 | "use": "@now/next" 6 | }] 7 | } -------------------------------------------------------------------------------- /components/FontSelector/Section.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | const Section = styled.div` 4 | padding: 7px; 5 | ` 6 | 7 | export default Section 8 | -------------------------------------------------------------------------------- /components/FontSelector/Container.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | const Container = styled.div` 4 | padding: 15px 15px 5px; 5 | display: flex; 6 | ` 7 | 8 | export default Container 9 | -------------------------------------------------------------------------------- /components/FontSelector/Label.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | const Label = styled.div` 4 | padding-left: 14px; 5 | font: 12px/1.4 Arial, sans-serif; 6 | color: #666; 7 | ` 8 | 9 | export default Label 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Play with fonts 2 | 3 | ![Screenshot](screen.png) 4 | 5 | #### How to play 6 | 7 | ```bash 8 | git clone https://github.com/border-radius/play-with-fonts 9 | cd play-with-fonts 10 | npm install 11 | npm run dev 12 | ``` 13 | 14 | And open your browser at [localhost:3000](http://localhost:3000). -------------------------------------------------------------------------------- /components/FontSelector/Select.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | const Select = styled.select` 4 | padding: 4px 10px; 5 | min-width: 70px; 6 | border: 1px solid #ccc; 7 | background: #fff; 8 | font: 14px/1.4 Arial, sans-serif; 9 | color: #000; 10 | ` 11 | 12 | export default Select 13 | -------------------------------------------------------------------------------- /components/FontSelector/InputNumber.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | const InputNumber = styled.input` 4 | padding: 4px 0 4px 15px; 5 | width: 70px; 6 | border: 1px solid #ccc; 7 | background: #fff; 8 | font: 14px/1.4 Arial, sans-serif; 9 | color: #000; 10 | ` 11 | 12 | export default InputNumber 13 | -------------------------------------------------------------------------------- /components/FontImporter.js: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | 3 | const FontImporter = ({ context }) => { 4 | const { subset, family, font } = useContext(context) 5 | 6 | const familyUri = family.replace(/\s+/g, '+') 7 | const importUrl = `https://fonts.googleapis.com/css?family=${familyUri}:${font}&subset=${subset}` 8 | 9 | return 10 | } 11 | 12 | export default FontImporter 13 | -------------------------------------------------------------------------------- /bin/update-fonts.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import axios from 'axios' 3 | import { promises as fs } from 'fs' 4 | 5 | const FONTS_URL = 'https://fonts.google.com/metadata/fonts' 6 | const FONTS_PATH = path.join(__dirname, '../data/familyMetadataList.json') 7 | 8 | async function updateFonts() { 9 | const { data } = await axios({ url: FONTS_URL, responseType: 'text' }) 10 | return fs.writeFile(FONTS_PATH, data.slice(5), { encoding: 'utf8' }) 11 | } 12 | 13 | ;(async () => await updateFonts())() 14 | -------------------------------------------------------------------------------- /components/FontSelector/SelectField.js: -------------------------------------------------------------------------------- 1 | import Section from './Section' 2 | import Label from './Label' 3 | import Select from './Select' 4 | 5 | const SelectField = ({ title, list, value, onChange }) => ( 6 |
7 | 8 | 15 |
16 | ) 17 | 18 | export default SelectField 19 | -------------------------------------------------------------------------------- /data/fonts.js: -------------------------------------------------------------------------------- 1 | import { familyMetadataList } from './familyMetadataList.json' 2 | 3 | const subsetsList = [] 4 | const subsetFamilies = {} 5 | const familyFonts = {} 6 | 7 | familyMetadataList.forEach(({ family, subsets, fonts }) => { 8 | subsets.forEach(subset => { 9 | if (!subsetFamilies[subset]) { 10 | subsetFamilies[subset] = [family] 11 | subsetsList.push(subset) 12 | } else { 13 | subsetFamilies[subset].push(family) 14 | } 15 | }) 16 | 17 | familyFonts[family] = Object.keys(fonts) 18 | }) 19 | 20 | subsetsList.sort() 21 | 22 | export const getSubsetList = () => subsetsList 23 | export const getFamilyList = subset => subsetFamilies[subset] || [] 24 | export const getFontList = family => familyFonts[family] || [] 25 | -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | import { createContext, useMemo } from 'react' 2 | 3 | import FontDemo from '../components/FontDemo' 4 | import FontSelector from '../components/FontSelector' 5 | import FontImporter from '../components/FontImporter' 6 | import FontReducer from '../reducers/FontReducer' 7 | 8 | const FontContext = createContext({}) 9 | 10 | const App = () => { 11 | const [state, setState] = FontReducer() 12 | 13 | const contextValue = useMemo(() => ({ ...state, setState }), [ 14 | state.subset, 15 | state.family, 16 | state.font, 17 | state.size, 18 | state.width, 19 | ]) 20 | 21 | return ( 22 | 23 | 24 | 25 | 26 | 27 | ) 28 | } 29 | 30 | export default App 31 | -------------------------------------------------------------------------------- /components/FontDemo.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | import { useContext, useState } from 'react' 3 | 4 | const defaultText = `Lorem ipsum, dolor sit amet consectetur adipisicing elit. 5 | Architecto quo labore nulla. 6 | Corporis possimus asperiores sit voluptates debitis voluptas, pariatur accusamus. 7 | Cupiditate ipsum tempora, natus earum ex hic nesciunt soluta!`.replace( 8 | /\n/g, 9 | ' ' 10 | ) 11 | 12 | const TextArea = ({ value, onChange, className }) => ( 13 |