├── .gitignore
├── .prettierignore
├── LICENSE.md
├── README.md
├── keymaps
└── font-viewer.cson
├── lib
├── font-viewer-view.js
├── font-viewer.js
└── main.js
├── package-lock.json
├── package.json
├── prettier.config.js
├── screenshot.webp
├── spec.zip
└── styles
└── font-viewer.less
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | npm-debug.log
3 | node_modules
4 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | package.json
3 | package-lock.json
4 | pnpm-lock.yaml
5 | changelog.md
6 | coverage
7 | build
8 | dist
9 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 Eric Freese
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Font Viewer
2 |
3 | Preview font files in an editor in Atom. Support zooming via `CTRL+` `CTRL-`, and `CTRL0` (`⌘` on MacOS)
4 |
5 | Shows a preview of all mapped characters. Currently supports `.otf`, `.ttf`, and `.woff`
6 |
7 | 
8 |
9 | Based on [image-view](https://github.com/atom/image-view). Uses the [freetype2](https://www.npmjs.org/package/freetype2) module for font file parsing.
10 |
11 | https://atom.io/packages/font-viewer
12 |
--------------------------------------------------------------------------------
/keymaps/font-viewer.cson:
--------------------------------------------------------------------------------
1 | '.platform-darwin .font-viewer':
2 | 'cmd-+': 'font-viewer:zoom-in'
3 | 'cmd-=': 'font-viewer:zoom-in'
4 | 'cmd--': 'font-viewer:zoom-out'
5 | 'cmd-_': 'font-viewer:zoom-out'
6 | 'cmd-0': 'font-viewer:reset-zoom'
7 |
8 | '.platform-win32 .font-viewer':
9 | 'ctrl-+': 'font-viewer:zoom-in'
10 | 'ctrl-=': 'font-viewer:zoom-in'
11 | 'ctrl--': 'font-viewer:zoom-out'
12 | 'ctrl-_': 'font-viewer:zoom-out'
13 | 'ctrl-0': 'font-viewer:reset-zoom'
14 |
--------------------------------------------------------------------------------
/lib/font-viewer-view.js:
--------------------------------------------------------------------------------
1 | "use babel"
2 | import { each } from "underscore-plus"
3 | import { ScrollView } from "atom-space-pen-views-plus"
4 | import { Emitter, CompositeDisposable } from "atom"
5 |
6 | // View that renders a {FontViewer}.
7 | export default class FontViewerView extends ScrollView {
8 | static content() {
9 | this.div({ class: "font-viewer", tabindex: -1 }, () => {
10 | this.style({ outlet: "style" })
11 | this.div({ class: "font-container", outlet: "container" })
12 | })
13 | }
14 |
15 | initialize(fontViewer) {
16 | this.fontViewer = fontViewer
17 | super.initialize(...arguments)
18 | this.emitter = new Emitter()
19 | }
20 |
21 | attached() {
22 | this.disposables = new CompositeDisposable()
23 |
24 | this.disposables.add(
25 | atom.commands.add(this.element, {
26 | "font-viewer:zoom-in": () => this.zoomIn(),
27 | "font-viewer:zoom-out": () => this.zoomOut(),
28 | "font-viewer:reset-zoom": () => this.resetZoom(),
29 | })
30 | )
31 |
32 | const { container } = this
33 | this.fontViewer.getAvailableCharacters((availableCharacters) =>
34 | each(availableCharacters, (c) => {
35 | const cString = c.toString(16)
36 | container.append(`
`)
37 | })
38 | )
39 |
40 | // load font in the view
41 | const fontViewerURI = this.fontViewer.getUri()
42 | this.style.append(`
43 | @font-face {
44 | font-family: "${fontViewerURI}";
45 | src: url("${fontViewerURI}");
46 | }`)
47 | this.container.css({ "font-family": `"${fontViewerURI}"` })
48 | }
49 |
50 | detached() {
51 | this.disposables.dispose()
52 | }
53 |
54 | // Zooms the font preview out by 10%.
55 | zoomOut() {
56 | this.adjustSize(0.9)
57 | }
58 |
59 | // Zooms the font preview in by 10%.
60 | zoomIn() {
61 | this.adjustSize(1.1)
62 | }
63 |
64 | // Zooms the font preview to its normal size.
65 | resetZoom() {
66 | if (!this.isVisible()) {
67 | return
68 | }
69 |
70 | this.container.css({ "font-size": "" })
71 | }
72 |
73 | // Adjust the size of the font preview by the given multiplying factor.
74 | //
75 | // factor - A {Number} to multiply against the current size.
76 | adjustSize(factor) {
77 | if (!this.isVisible()) {
78 | return
79 | }
80 |
81 | this.container.css({ "font-size": `${parseInt(this.container.css("font-size"), 10) * factor}px` })
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/lib/font-viewer.js:
--------------------------------------------------------------------------------
1 | "use babel"
2 | /*
3 | * decaffeinate suggestions:
4 | * DS102: Remove unnecessary code created because of implicit returns
5 | * DS206: Consider reworking classes to avoid initClass
6 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
7 | */
8 |
9 | import path from "path"
10 | import fs from "fs-plus"
11 | import { File, CompositeDisposable } from "atom"
12 | import { NewMemoryFace } from "freetype2"
13 | import fileUrl from "file-url"
14 |
15 | // Editor model for a font file
16 | export default class FontViewer {
17 | static initClass() {
18 | atom.deserializers.add(this)
19 | }
20 |
21 | static deserialize({ filePath }) {
22 | if (fs.isFileSync(filePath)) {
23 | return new FontViewer(filePath)
24 | } else {
25 | console.warn(`Could not deserialize font viewer for path '${filePath}' because that file no longer exists`)
26 | }
27 | }
28 |
29 | constructor(filePath) {
30 | this.file = new File(filePath)
31 | this.subscriptions = new CompositeDisposable()
32 | }
33 |
34 | serialize() {
35 | return { filePath: this.getPath(), deserializer: this.constructor.name }
36 | }
37 |
38 | getViewClass() {
39 | return require("./font-viewer-view")
40 | }
41 |
42 | destroy() {
43 | this.subscriptions.dispose()
44 | }
45 |
46 | // Retrieves the filename of the open file.
47 | //
48 | // This is `'untitled'` if the file is new and not saved to the disk.
49 | //
50 | // Returns a {String}.
51 | getTitle() {
52 | const filePath = this.getPath()
53 | if (filePath) {
54 | return path.basename(filePath)
55 | } else {
56 | return "untitled"
57 | }
58 | }
59 |
60 | // Retrieves the URI of the font file.
61 | //
62 | // Returns a {String}.
63 | getUri() {
64 | return fileUrl(this.getPath())
65 | }
66 |
67 | // Retrieves the absolute path to the font file.
68 | //
69 | // Returns a {String} path.
70 | getPath() {
71 | return this.file.getPath()
72 | }
73 |
74 | getAvailableCharacters(callback) {
75 | return fs.readFile(this.getPath(), function (err, buffer) {
76 | const chars = []
77 | const face = NewMemoryFace(buffer, 0)
78 |
79 | let char = face.getFirstChar()
80 | while (char && char.glyphIndex !== 0) {
81 | chars.push(char.charCode)
82 | char = face.getNextChar(char.charCode)
83 | }
84 |
85 | return callback(chars)
86 | })
87 | }
88 |
89 | // Compares two {FontViewer}s to determine equality.
90 | //
91 | // Equality is based on the condition that the two URIs are the same.
92 | //
93 | // Returns a {Boolean}.
94 | isEqual(other) {
95 | return other instanceof FontViewer && this.getUri() === other.getUri()
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/lib/main.js:
--------------------------------------------------------------------------------
1 | "use babel"
2 | import path from "path"
3 | import { include } from "underscore-plus"
4 | import FontViewer from "./font-viewer"
5 |
6 | let openerDisposable
7 |
8 | export function activate() {
9 | FontViewer.initClass()
10 |
11 | // Files with these extensions will be opened as fonts
12 | const fontExtensions = [".otf", ".ttf", ".woff"]
13 | openerDisposable = atom.workspace.addOpener((uriToOpen) => {
14 | const uriExtension = path.extname(uriToOpen).toLowerCase()
15 | if (include(fontExtensions, uriExtension)) {
16 | return new FontViewer(uriToOpen)
17 | }
18 | })
19 | }
20 |
21 | export function deactivate() {
22 | openerDisposable.dispose()
23 | }
24 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "font-viewer",
3 | "version": "1.0.5",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "async": {
8 | "version": "1.5.2",
9 | "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
10 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
11 | },
12 | "at-least-node": {
13 | "version": "1.0.0",
14 | "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
15 | "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
16 | },
17 | "atom-space-pen-views-plus": {
18 | "version": "3.0.4",
19 | "resolved": "https://registry.npmjs.org/atom-space-pen-views-plus/-/atom-space-pen-views-plus-3.0.4.tgz",
20 | "integrity": "sha512-PfCBrD6RUN359P8Do3D3m2d1Ws2DyR7Jl1Ym97R2Gr9liM+5CYU5AvopJNL9m8pZqOBpu5ePcHjSrC/V1cL8oA==",
21 | "requires": {
22 | "fs-extra": "^9.0.1",
23 | "fuzzaldrin": "^2.1.0",
24 | "space-pen-plus": "^6.0.3"
25 | }
26 | },
27 | "balanced-match": {
28 | "version": "1.0.0",
29 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
30 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
31 | },
32 | "bindings": {
33 | "version": "1.5.0",
34 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
35 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
36 | "requires": {
37 | "file-uri-to-path": "1.0.0"
38 | }
39 | },
40 | "brace-expansion": {
41 | "version": "1.1.11",
42 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
43 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
44 | "requires": {
45 | "balanced-match": "^1.0.0",
46 | "concat-map": "0.0.1"
47 | }
48 | },
49 | "concat-map": {
50 | "version": "0.0.1",
51 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
52 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
53 | },
54 | "file-uri-to-path": {
55 | "version": "1.0.0",
56 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
57 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
58 | },
59 | "file-url": {
60 | "version": "3.0.0",
61 | "resolved": "https://registry.npmjs.org/file-url/-/file-url-3.0.0.tgz",
62 | "integrity": "sha512-g872QGsHexznxkIAdK8UiZRe7SkE6kvylShU4Nsj8NvfvZag7S0QuQ4IgvPDkk75HxgjIVDwycFTDAgIiO4nDA=="
63 | },
64 | "freetype2": {
65 | "version": "1.0.6",
66 | "resolved": "https://registry.npmjs.org/freetype2/-/freetype2-1.0.6.tgz",
67 | "integrity": "sha512-jfVNUD9fecnST+bNIIfdtsAwy9aQwMGYgkHJVaxDg/P0mgiZCJauASiBAdRUQFDeh9flbG8W/ogyCe51VYCchA==",
68 | "requires": {
69 | "bindings": "^1.5.0",
70 | "node-addon-api": "^3.0.2",
71 | "node-gyp-build": "^4.2.3"
72 | }
73 | },
74 | "fs-extra": {
75 | "version": "9.0.1",
76 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
77 | "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
78 | "requires": {
79 | "at-least-node": "^1.0.0",
80 | "graceful-fs": "^4.2.0",
81 | "jsonfile": "^6.0.1",
82 | "universalify": "^1.0.0"
83 | }
84 | },
85 | "fs-plus": {
86 | "version": "3.1.1",
87 | "resolved": "https://registry.npmjs.org/fs-plus/-/fs-plus-3.1.1.tgz",
88 | "integrity": "sha512-Se2PJdOWXqos1qVTkvqqjb0CSnfBnwwD+pq+z4ksT+e97mEShod/hrNg0TRCCsXPbJzcIq+NuzQhigunMWMJUA==",
89 | "requires": {
90 | "async": "^1.5.2",
91 | "mkdirp": "^0.5.1",
92 | "rimraf": "^2.5.2",
93 | "underscore-plus": "1.x"
94 | }
95 | },
96 | "fs.realpath": {
97 | "version": "1.0.0",
98 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
99 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
100 | },
101 | "fuzzaldrin": {
102 | "version": "2.1.0",
103 | "resolved": "https://registry.npmjs.org/fuzzaldrin/-/fuzzaldrin-2.1.0.tgz",
104 | "integrity": "sha1-kCBMPi/appQbso0WZF1BgGOpDps="
105 | },
106 | "glob": {
107 | "version": "7.1.6",
108 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
109 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
110 | "requires": {
111 | "fs.realpath": "^1.0.0",
112 | "inflight": "^1.0.4",
113 | "inherits": "2",
114 | "minimatch": "^3.0.4",
115 | "once": "^1.3.0",
116 | "path-is-absolute": "^1.0.0"
117 | }
118 | },
119 | "graceful-fs": {
120 | "version": "4.2.4",
121 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
122 | "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
123 | },
124 | "inflight": {
125 | "version": "1.0.6",
126 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
127 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
128 | "requires": {
129 | "once": "^1.3.0",
130 | "wrappy": "1"
131 | }
132 | },
133 | "inherits": {
134 | "version": "2.0.4",
135 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
136 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
137 | },
138 | "jquery": {
139 | "version": "3.5.1",
140 | "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz",
141 | "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg=="
142 | },
143 | "jsonfile": {
144 | "version": "6.0.1",
145 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz",
146 | "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==",
147 | "requires": {
148 | "graceful-fs": "^4.1.6",
149 | "universalify": "^1.0.0"
150 | }
151 | },
152 | "minimatch": {
153 | "version": "3.0.4",
154 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
155 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
156 | "requires": {
157 | "brace-expansion": "^1.1.7"
158 | }
159 | },
160 | "minimist": {
161 | "version": "1.2.5",
162 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
163 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
164 | },
165 | "mkdirp": {
166 | "version": "0.5.5",
167 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
168 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
169 | "requires": {
170 | "minimist": "^1.2.5"
171 | }
172 | },
173 | "node-addon-api": {
174 | "version": "3.0.2",
175 | "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.2.tgz",
176 | "integrity": "sha512-+D4s2HCnxPd5PjjI0STKwncjXTUKKqm74MDMz9OPXavjsGmjkvwgLtA5yoxJUdmpj52+2u+RrXgPipahKczMKg=="
177 | },
178 | "node-gyp-build": {
179 | "version": "4.2.3",
180 | "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz",
181 | "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg=="
182 | },
183 | "once": {
184 | "version": "1.4.0",
185 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
186 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
187 | "requires": {
188 | "wrappy": "1"
189 | }
190 | },
191 | "path-is-absolute": {
192 | "version": "1.0.1",
193 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
194 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
195 | },
196 | "prettier": {
197 | "version": "2.2.1",
198 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz",
199 | "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
200 | "dev": true
201 | },
202 | "rimraf": {
203 | "version": "2.7.1",
204 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
205 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
206 | "requires": {
207 | "glob": "^7.1.3"
208 | }
209 | },
210 | "space-pen-plus": {
211 | "version": "6.0.3",
212 | "resolved": "https://registry.npmjs.org/space-pen-plus/-/space-pen-plus-6.0.3.tgz",
213 | "integrity": "sha512-iqPZAQYP3xPDGxT6MxIwm4GQks91p2H4QeUUcjjzPyr2FEmpaqVLX6cDwjzf8HWMQ0r9fa3hSB9CzMODXVBe6g==",
214 | "requires": {
215 | "jquery": "^3.5.1"
216 | }
217 | },
218 | "underscore": {
219 | "version": "1.10.2",
220 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz",
221 | "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg=="
222 | },
223 | "underscore-plus": {
224 | "version": "1.8.1",
225 | "resolved": "https://registry.npmjs.org/@aminya/underscore-plus/-/underscore-plus-1.8.1.tgz",
226 | "integrity": "sha512-MiGCwfNr6iYou5jaEICXGuQJBACyHt/RiCVjib136cjNmvrirXe4WIf7Px4YW4d2RPYxEHKiXV617CL26aa4tA==",
227 | "requires": {
228 | "underscore": "^1.10.2"
229 | }
230 | },
231 | "universalify": {
232 | "version": "1.0.0",
233 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
234 | "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug=="
235 | },
236 | "wrappy": {
237 | "version": "1.0.2",
238 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
239 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
240 | }
241 | }
242 | }
243 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "font-viewer",
3 | "main": "./lib/main",
4 | "version": "1.0.5",
5 | "description": "Preview font files in an editor in Atom.",
6 | "repository": "https://github.com/ericfreese/font-viewer",
7 | "license": "MIT",
8 | "engines": {
9 | "atom": "*"
10 | },
11 | "scripts": {
12 | "format": "prettier --write ."
13 | },
14 | "dependencies": {
15 | "atom-space-pen-views-plus": "^3.0.4",
16 | "file-url": "^3.0.0",
17 | "freetype2": "1.0.6",
18 | "fs-plus": "~3.1.1",
19 | "underscore-plus": "^1.7"
20 | },
21 | "activationHooks": [
22 | "core:loaded-shell-environment"
23 | ],
24 | "devDependencies": {
25 | "prettier": "^2.2.1"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | // Add to .prettierignore to ignore files and folders
2 |
3 | // This configuration all the formats including typescript, javascript, json, yaml, markdown
4 | module.exports = {
5 | tabWidth: 2,
6 | printWidth: 120,
7 | semi: false,
8 | singleQuote: false,
9 | overrides: [
10 | {
11 | files: "{*.json}",
12 | options: {
13 | parser: "json",
14 | trailingComma: "es5",
15 | },
16 | },
17 | {
18 | files: "{*.md}",
19 | options: {
20 | parser: "markdown",
21 | proseWrap: "preserve",
22 | },
23 | },
24 | ],
25 | }
26 |
--------------------------------------------------------------------------------
/screenshot.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ericfreese/font-viewer/f8f6042ef757221839cebb7aa571f81a5c620148/screenshot.webp
--------------------------------------------------------------------------------
/spec.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ericfreese/font-viewer/f8f6042ef757221839cebb7aa571f81a5c620148/spec.zip
--------------------------------------------------------------------------------
/styles/font-viewer.less:
--------------------------------------------------------------------------------
1 | @import "ui-variables";
2 |
3 | // css containment to improve performance
4 | @contain_all: layout size paint style;
5 | @contain_but_size: layout paint style;
6 |
7 | .font-viewer {
8 | contain: @contain_all;
9 | .font-container {
10 | contain: @contain_all;
11 | padding: 0.2em;
12 | height: 100%;
13 | overflow: auto;
14 | font-size: 4em;
15 | color: @text-color-highlight;
16 |
17 | .font-glyph {
18 | contain: @contain_but_size;
19 | position: relative;
20 | display: inline-block;
21 | vertical-align: middle;
22 | border: 1px solid transparent;
23 | margin: 0.1em;
24 | min-width: 1.5em;
25 | text-align: center;
26 | white-space: pre;
27 |
28 | .font-glyph-id {
29 | contain: @contain_but_size;
30 | display: none;
31 | position: absolute;
32 | right: 0;
33 | bottom: 0;
34 | background: @text-color-highlight;
35 | color: @base-background-color;
36 | font-size: 0.2em;
37 | padding: 0 0.2em 0 0.2em;
38 | font-family: @font-family;
39 | }
40 |
41 | &:hover {
42 | border-color: @text-color-highlight;
43 |
44 | .font-glyph-id {
45 | contain: @contain_but_size;
46 | display: block;
47 | }
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------