1
1
mirror of https://github.com/rsms/inter.git synced 2024-12-27 09:33:19 +03:00

website: big update with samples and vf stuff

This commit is contained in:
Rasmus Andersson 2018-10-07 18:32:03 -07:00
parent f6050df801
commit a0df8aa6d4
109 changed files with 232253 additions and 6999 deletions

View File

@ -1,8 +1,8 @@
[
{
"head": {
"checkSumAdjustment": 3496267821,
"created": 3563720514,
"checkSumAdjustment": 2438927683,
"created": 3621707122,
"flags": 27,
"fontDirectionHint": 2,
"fontRevision": 3.0,
@ -12,16 +12,16 @@
"macStyle": [],
"macStyle_raw": 0,
"magicNumber": 1594834165,
"modified": 3620507819,
"modified": 3621707136,
"tableVersion": 1.0,
"unitsPerEm": 2816,
"xMax": 3756,
"xMax": 4524,
"xMin": -2080,
"yMax": 3012,
"yMin": -1080
},
"hhea": {
"advanceWidthMax": 4004,
"advanceWidthMax": 4912,
"ascent": 2708,
"caretOffset": 0,
"caretSlopeRise": 1,
@ -31,18 +31,18 @@
"metricDataFormat": 0,
"minLeftSideBearing": -2080,
"minRightSideBearing": -1440,
"numberOfHMetrics": 2183,
"numberOfHMetrics": 2283,
"tableVersion": 65536,
"xMaxExtent": 3756
"xMaxExtent": 4524
},
"id": "Inter UI Regular:2018:b54a3a10",
"id": "Inter UI Regular:2018:32cdb6ede",
"name": "InterUI-Regular",
"names": {
"copyright": "Copyright 2018 The Inter UI project authors",
"designer": "Rasmus Andersson",
"designerURL": "https://rsms.me/",
"familyName": "Inter UI",
"fontId": "Inter UI Regular:2018:b54a3a10",
"fontId": "Inter UI Regular:2018:32cdb6ede",
"fullName": "Inter UI Regular",
"licenseDescription": "OFL 1.1 (SIL Open Font License, Version 1.1)",
"licenseURL": "http://scripts.sil.org/OFL",
@ -51,7 +51,7 @@
"subfamilyName": "Regular",
"trademark": "Inter UI is a trademark of rsms.",
"vendorURL": "https://rsms.me/",
"version": "3.0;b54a3a10"
"version": "3.0;32cdb6ede"
},
"os/2": {
"achVendID": "RSMS",
@ -95,7 +95,7 @@
"usWinAscent": 2708,
"usWinDescent": 660,
"version": 4,
"xAvgCharWidth": 1697,
"xAvgCharWidth": 1675,
"yStrikeoutPosition": 1024,
"yStrikeoutSize": 256,
"ySubscriptXOffset": 0,

View File

@ -0,0 +1,57 @@
{%
capture url_root
%}{% if site.safe == false %}/{% else %}/inter/{% endif
%}{%
endcapture %}{%
for file in site.static_files %}{%
assign _path = file.path | remove_first: "/inter" %}{%
if _path == "/res/ctxedit.js" %}{%
assign ctxedit_js_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{%
elsif _path == "/res/ctxedit.css" %}{%
assign ctxedit_css_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{%
endif %}{%
endfor
%}
<link rel="stylesheet" href="{{url_root}}res/ctxedit.css?v={{ ctxedit_css_v }}">
<div id="ctxedit-ui" class="styled-inputs-neg" contenteditable="false" tabindex="1">
<div class="wrapper">
<div class="control popup">
<select data-binding="style">
<option value="regular" default>Regular</option>
<option value="italic">Italic</option>
<option value="medium">Medium</option>
<option value="medium-italic">Medium Italic</option>
<option value="semi-bold">Semi Bold</option>
<option value="semi-bold-italic">Semi Bold Italic</option>
<option value="bold">Bold</option>
<option value="bold-italic">Bold Italic</option>
<option value="extra-bold">Extra Bold</option>
<option value="extra-bold-italic">Extra Bold Italic</option>
<option value="black">Black</option>
<option value="black-italic">Black Italic</option>
</select>
</div>
<div class="control range">
<img title="Size" class="icon" src="icons/font-size.svg">
<input type="range" min="8" max="150" step="1" data-binding="size">
</div>
<div class="control range">
<img title="Tracking/letter-spacing in EM" class="icon" src="icons/letter-spacing.svg">
<input type="range" min="-0.1" max="0.1" step="0.001" data-binding="tracking">
</div>
<div class="control range">
<img title="Line height" class="icon" src="icons/line-height.svg">
<input type="range" value="1.2" min="0.7" max="2" step="0.01" data-binding="lineHeight">
</div>
<!-- <div class="control color">
<input type="color" value="#111" data-binding="color">
</div> -->
<!-- <div class="control button features-button" title="Features..."></div> -->
<div class="control button reset-button" title="Reset"></div>
<div class="control button dismiss-button" title="Close editor"></div>
</div>
</div>
<script src="{{url_root}}res/ctxedit.js?v={{ ctxedit_js_v }}"></script>

View File

@ -59,6 +59,13 @@ endfor
<meta property="og:type" content="product">
<meta property="og:locale" content="en_US" />
</head>
<script>
(function(u){
if (u.indexOf('Safari/') != -1 && u.indexOf('Chrome/') == -1 && u.indexOf('Chromium/') == -1) {
document.documentElement.classList.add('safari')
}
})(navigator.userAgent);
</script>
<body>
<div id="hud-notification"><div class="msg">Hello</div></div>
<script src="{{url_root}}res/base.js?v={{ base_js_v }}"></script>

View File

@ -2,6 +2,11 @@
set -e
cd "$(dirname "$0")/.."
if [ "$1" == "-h" ]; then
echo "usage: $0 [<bindaddr>]" >&2
exit 1
fi
if [ ! -s lab/fonts ]; then
rm -f lab/fonts
ln -fs ../../build/fonts lab/fonts
@ -15,4 +20,9 @@ fi
# For live testing with fonts, you'll instead want to use docs/lab/serve.py
rm -rf _site
jekyll serve --limit_posts 20 --watch --host 127.0.0.1 --port 3002
BINDADDR=127.0.0.1
if [ "$1" != "" ]; then
BINDADDR=$1
fi
jekyll serve --limit_posts 20 --watch --host "$BINDADDR" --port 3002

View File

@ -89,8 +89,8 @@ endfor
<option value="italic">Italic</option>
<option value="medium" default>Medium</option>
<option value="medium-italic">Medium Italic</option>
<option value="semi-bold" default>Extra Bold</option>
<option value="semi-bold-italic">Extra Bold Italic</option>
<option value="semi-bold" default>Semi Bold</option>
<option value="semi-bold-italic">Semi Bold Italic</option>
<option value="bold" default>Bold</option>
<option value="bold-italic">Bold Italic</option>
<option value="extra-bold" default>Extra Bold</option>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

108
docs/index-var.css Normal file
View File

@ -0,0 +1,108 @@
.variable-sample {
--var-size: 128px;
--var-weight: 600;
--var-slant: 0;
--var-letterSpacing: -0.03em;
--var-lineHeight: 1.1;
text-align: center;
}
@supports (font-variation-settings: normal) {
.variable-sample {
font-family: 'Inter UI var', sans-serif;
}
}
.variable {
padding-bottom: 0;
}
.variable label {
user-select: none;
}
.variable .unsupported-message {
opacity: 0.3;
border: 2px solid #999;
border-radius:4px;
text-align: center;
padding: 1em 1em;
display: none;
margin: 1em auto;
width: 60%;
}
.variable .unsupported-message.active {
display: block;
}
.variable .unsupported-message p {
margin: 0.5em 0;
}
.variable .ctrl {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: stretch;
/*border: 1px solid #ddd; border-radius:4px;*/
/*border-top: 1px solid #ddd;*/
border-bottom: 1px solid #ddd;
color: #333;
padding:20px 20px 20px 20px;
}
.variable .unsupported-message.active + .ctrl {
border-top: none;
}
.variable .ctrl .ctrlrow {
flex: 1 0 auto;
display: flex;
justify-content: flex-start;
align-items: center;
padding:5px;
}
.variable .ctrl input {
margin: 0 8px 0 0;
}
.variable .ctrl input[type="range"] {
margin-left: 8px;
flex: 0 0 auto;
width: 150px;
}
.variable .ctrl label {
display: flex;
flex: 0 1 auto;
align-items: center;
margin-right: 20px;
/*background:lightpink;*/
}
.variable .ctrl label.disabled {
color: rgba(0,0,0,0.3);
}
.variable .ctrl label.tight {
flex: 0 1 auto;
}
.variable .ctrl label:last-child {
margin-right: 0;
}
.variable .ctrl label .label {
min-width: 65px;
}
.variable .ctrl label .label.var {
font-weight: 500;
}
.variable-sample-row {
padding-top:0;
}
.variable-sample-row.black .variable-sample {
color: white;
}
.variable-sample {
color: #030508;
padding-top: 40px;
max-width: 100%;
font-size: var(--var-size);
letter-spacing: var(--var-letterSpacing);
line-height: var(--var-lineHeight);
font-variation-settings: 'wght' var(--var-weight), 'slnt' var(--var-slant);
}

191
docs/index-var.js Normal file
View File

@ -0,0 +1,191 @@
(function(){
var root = document.querySelector('div.variable')
var sample = document.querySelector('.variable-sample')
var animateCheckbox = document.querySelector('[name="animate"]')
var ui = {
state: {
weight: 0,
slant: 0,
size: 0, // px
letterSpacing: 0, // em
lineHeight: 0,
},
variable: {
weight: true,
slant: true,
},
formatters: {
size(v) { return `${v}px` },
letterSpacing(v) { return `${v}em` },
},
inputs: {
// populated by init()
},
init() {
let s = getComputedStyle(sample)
// We test for variable-font support by, in CSS, conditionally using
// a different font family name when VF is supported. Then we test for
// what font family name is in effect. If it's the "var" one, we can be
// fairly certain that variable fonts are supported by the user agent.
let supportsVF = s.fontFamily.indexOf('Inter UI var') != -1
// supportsVF = false // XXX
// hook up input controls
for (let k in this.state) {
let value = parseFloat(s.getPropertyValue(`--var-${k}`))
this.state[k] = value
let input = root.querySelector(`[name="${k}"]`)
if (input) {
this.inputs[k] = input
input.value = value
if (!supportsVF && this.variable[k]) {
input.disabled = true
input.parentElement.classList.add('disabled')
} else if (input.type == 'range') {
this.bindRangeControl(input, v => {
this.state[k] = v
this.update()
})
}
}
}
if (!supportsVF) {
animateCheckbox.disabled = true
animateCheckbox.parentElement.classList.add('disabled')
let unsupportedMessage = root.querySelector(`.unsupported-message`)
if (unsupportedMessage) {
unsupportedMessage.classList.add('active')
}
}
},
bindRangeControl(rangeInput, handler) {
rangeInput.addEventListener('input',
rangeInput.valueAsNumber !== undefined ? ev => {
handler(rangeInput.valueAsNumber)
} : ev => {
handler(parseFloat(rangeInput.value))
}
)
},
setState(props) {
for (let k in props) {
if (k in this.state) {
this.state[k] = props[k]
}
}
this.update()
},
update() {
let s = sample.style
for (let k in this.state) {
let f = this.formatters[k]
s.setProperty(`--var-${k}`, f ? f(this.state[k]) : this.state[k])
}
},
}
// monotime() :float milliseconds
//
var monotime = (
window.performance !== undefined && window.performance.now ? function() {
return window.performance.now()
} : Date.now ? function() {
return Date.now()
} : function() {
return (new Date()).getTime()
}
)
var isAnimating = false
function startAnimation() {
if (isAnimating) {
return
}
ui.inputs.weight.disabled = true
ui.inputs.slant.disabled = true
isAnimating = true
let v = 0
let wmin = parseFloat(ui.inputs.weight.min)
, wmax = parseFloat(ui.inputs.weight.max)
, imin = parseFloat(ui.inputs.slant.min)
, imax = parseFloat(ui.inputs.slant.max)
, wspeed = 200 // lower is faster; time divisor
, ispeed = 800
, clamp = 0.001
, startTime = monotime()
function update() {
let r = 0, v = 0
r = (1 + Math.sin((monotime() - startTime) / wspeed)) * 0.5
v = (wmin * (1 - clamp)) + (((wmax * (1 + clamp)) - (wmin * (1 - clamp))) * r)
v = Math.max(wmin, Math.min(wmax, v))
ui.state.weight = v
ui.inputs.weight.value = v
r = (1 + Math.sin((monotime() - startTime) / ispeed)) * 0.5
v = (imin * (1 - clamp)) + (((imax * (1 + clamp)) - (imin * (1 - clamp))) * r)
v = Math.max(imin, Math.min(imax, v))
ui.state.slant = v
ui.inputs.slant.value = v
ui.update()
if (isAnimating) {
requestAnimationFrame(update)
}
}
update()
}
function stopAnimation() {
isAnimating = false
ui.inputs.weight.disabled = false
ui.inputs.slant.disabled = false
ui.inputs.weight.value = String(ui.state.weight)
ui.inputs.slant.value = String(ui.state.slant)
}
// UI control: animate
if (!window.requestAnimationFrame) {
animateCheckbox.disabled = true
animateCheckbox.title = "Not supported by browser"
} else {
animateCheckbox.addEventListener('change', ev => {
if (animateCheckbox.checked) {
startAnimation()
} else {
stopAnimation()
}
})
}
// UI control: invert colors ("Black/White")
document.querySelector('[name="invert"]').addEventListener('change', ev => {
if (ev.target.checked) {
sample.parentElement.classList.add('black')
sample.parentElement.classList.remove('white')
} else {
sample.parentElement.classList.remove('black')
sample.parentElement.classList.add('white')
}
})
ui.init()
})();

View File

@ -59,3 +59,180 @@
.dynmet-calc #dynmet-unit:active {
color: white;
}
tablex in, tablex to, tablex out {
display: table-cell;
width: 5%;
white-space: pre;
padding-bottom:0.5em;
}
/*tablex to {
width:0;
}*/
tablex to::after {
-moz-font-feature-settings: 'calt' 1, 'case' 1;
-ms-font-feature-settings: 'calt' 1, 'case' 1;
-o-font-feature-settings: 'calt' 1, 'case' 1;
-webkit-font-feature-settings: 'calt' 1, 'case' 1;
font-feature-settings: 'calt' 1, 'case' 1;
content: " → ";
color: rgba(0,0,0,0.2);
}
tablex in, tablex out {
color: rgba(0,0,0,0.8);
}
tablex r name {
color: rgba(0,0,0,0.4);
}
tablex in {
-moz-font-feature-settings: 'calt' 0;
-ms-font-feature-settings: 'calt' 0;
-o-font-feature-settings: 'calt' 0;
-webkit-font-feature-settings: 'calt' 0;
font-feature-settings: 'calt' 0;
}
tablex out {
-moz-font-feature-settings: 'calt' 1;
-ms-font-feature-settings: 'calt' 1;
-o-font-feature-settings: 'calt' 1;
-webkit-font-feature-settings: 'calt' 1;
font-feature-settings: 'calt' 1;
}
tablex em {
font-style: inherit;
background: #e4fdef;
color: rgba(0,0,0,1);
}
tablex out.zero {
-moz-font-feature-settings: 'calt' 1, 'zero' 1;
-ms-font-feature-settings: 'calt' 1, 'zero' 1;
-o-font-feature-settings: 'calt' 1, 'zero' 1;
-webkit-font-feature-settings: 'calt' 1, 'zero' 1;
font-feature-settings: 'calt' 1, 'zero' 1;
}
tablex out.tnum {
-moz-font-feature-settings: 'calt' 1, 'tnum' 1;
-ms-font-feature-settings: 'calt' 1, 'tnum' 1;
-o-font-feature-settings: 'calt' 1, 'tnum' 1;
-webkit-font-feature-settings: 'calt' 1, 'tnum' 1;
font-feature-settings: 'calt' 1, 'tnum' 1;
}
tablex out.case {
-moz-font-feature-settings: 'calt' 1, 'case' 1;
-ms-font-feature-settings: 'calt' 1, 'case' 1;
-o-font-feature-settings: 'calt' 1, 'case' 1;
-webkit-font-feature-settings: 'calt' 1, 'case' 1;
font-feature-settings: 'calt' 1, 'case' 1;
}
tablex out.frac {
-moz-font-feature-settings: 'calt' 1, 'frac' 1;
-ms-font-feature-settings: 'calt' 1, 'frac' 1;
-o-font-feature-settings: 'calt' 1, 'frac' 1;
-webkit-font-feature-settings: 'calt' 1, 'frac' 1;
font-feature-settings: 'calt' 1, 'frac' 1;
}
tablex out.numr {
-moz-font-feature-settings: 'calt' 1, 'numr' 1;
-ms-font-feature-settings: 'calt' 1, 'numr' 1;
-o-font-feature-settings: 'calt' 1, 'numr' 1;
-webkit-font-feature-settings: 'calt' 1, 'numr' 1;
font-feature-settings: 'calt' 1, 'numr' 1;
}
tablex out.dnom {
-moz-font-feature-settings: 'calt' 1, 'dnom' 1;
-ms-font-feature-settings: 'calt' 1, 'dnom' 1;
-o-font-feature-settings: 'calt' 1, 'dnom' 1;
-webkit-font-feature-settings: 'calt' 1, 'dnom' 1;
font-feature-settings: 'calt' 1, 'dnom' 1;
}
tablex out.sups {
-moz-font-feature-settings: 'calt' 1, 'sups' 1;
-ms-font-feature-settings: 'calt' 1, 'sups' 1;
-o-font-feature-settings: 'calt' 1, 'sups' 1;
-webkit-font-feature-settings: 'calt' 1, 'sups' 1;
font-feature-settings: 'calt' 1, 'sups' 1;
}
tablex out.subs {
-moz-font-feature-settings: 'calt' 1, 'subs' 1;
-ms-font-feature-settings: 'calt' 1, 'subs' 1;
-o-font-feature-settings: 'calt' 1, 'subs' 1;
-webkit-font-feature-settings: 'calt' 1, 'subs' 1;
font-feature-settings: 'calt' 1, 'subs' 1;
}
tablex out.ss01 {
-moz-font-feature-settings: 'calt' 1, 'ss01' 1;
-ms-font-feature-settings: 'calt' 1, 'ss01' 1;
-o-font-feature-settings: 'calt' 1, 'ss01' 1;
-webkit-font-feature-settings: 'calt' 1, 'ss01' 1;
font-feature-settings: 'calt' 1, 'ss01' 1;
}
tablex out.ss02 {
-moz-font-feature-settings: 'calt' 1, 'ss02' 1;
-ms-font-feature-settings: 'calt' 1, 'ss02' 1;
-o-font-feature-settings: 'calt' 1, 'ss02' 1;
-webkit-font-feature-settings: 'calt' 1, 'ss02' 1;
font-feature-settings: 'calt' 1, 'ss02' 1;
}
tablex out.cpsp {
-moz-font-feature-settings: 'calt' 1, 'cpsp' 1;
-ms-font-feature-settings: 'calt' 1, 'cpsp' 1;
-o-font-feature-settings: 'calt' 1, 'cpsp' 1;
-webkit-font-feature-settings: 'calt' 1, 'cpsp' 1;
font-feature-settings: 'calt' 1, 'cpsp' 1;
}
tablex out.dlig {
-moz-font-feature-settings: 'calt' 1, 'dlig' 1;
-ms-font-feature-settings: 'calt' 1, 'dlig' 1;
-o-font-feature-settings: 'calt' 1, 'dlig' 1;
-webkit-font-feature-settings: 'calt' 1, 'dlig' 1;
font-feature-settings: 'calt' 1, 'dlig' 1;
}
tablex out.cv01 {
-moz-font-feature-settings: 'calt' 1, 'cv01' 1;
-ms-font-feature-settings: 'calt' 1, 'cv01' 1;
-o-font-feature-settings: 'calt' 1, 'cv01' 1;
-webkit-font-feature-settings: 'calt' 1, 'cv01' 1;
font-feature-settings: 'calt' 1, 'cv01' 1;
}
tablex out.cv02 {
-moz-font-feature-settings: 'calt' 1, 'cv02' 1;
-ms-font-feature-settings: 'calt' 1, 'cv02' 1;
-o-font-feature-settings: 'calt' 1, 'cv02' 1;
-webkit-font-feature-settings: 'calt' 1, 'cv02' 1;
font-feature-settings: 'calt' 1, 'cv02' 1;
}
tablex out.cv03 {
-moz-font-feature-settings: 'calt' 1, 'cv03' 1;
-ms-font-feature-settings: 'calt' 1, 'cv03' 1;
-o-font-feature-settings: 'calt' 1, 'cv03' 1;
-webkit-font-feature-settings: 'calt' 1, 'cv03' 1;
font-feature-settings: 'calt' 1, 'cv03' 1;
}
tablex out.cv04 {
-moz-font-feature-settings: 'calt' 1, 'cv04' 1;
-ms-font-feature-settings: 'calt' 1, 'cv04' 1;
-o-font-feature-settings: 'calt' 1, 'cv04' 1;
-webkit-font-feature-settings: 'calt' 1, 'cv04' 1;
font-feature-settings: 'calt' 1, 'cv04' 1;
}
tablex out.cv05 {
-moz-font-feature-settings: 'calt' 1, 'cv05' 1;
-ms-font-feature-settings: 'calt' 1, 'cv05' 1;
-o-font-feature-settings: 'calt' 1, 'cv05' 1;
-webkit-font-feature-settings: 'calt' 1, 'cv05' 1;
font-feature-settings: 'calt' 1, 'cv05' 1;
}
tablex out.cv06 {
-moz-font-feature-settings: 'calt' 1, 'cv06' 1;
-ms-font-feature-settings: 'calt' 1, 'cv06' 1;
-o-font-feature-settings: 'calt' 1, 'cv06' 1;
-webkit-font-feature-settings: 'calt' 1, 'cv06' 1;
font-feature-settings: 'calt' 1, 'cv06' 1;
}
boxes.features box h3 + p {
margin-top:0.5em;
}

View File

@ -12,11 +12,16 @@ for file in site.static_files %}{%
assign _path = file.path | remove_first: "/inter" %}{%
if _path == "/index.css" %}{%
assign index_css_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{%
elsif _path == "/index-var.css" %}{%
assign index_var_css_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{%
elsif _path == "/index-var.js" %}{%
assign index_var_js_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{%
endif %}{%
endfor
%}
<link rel="stylesheet" href="index.css?v={{ index_css_v }}">
<link rel="stylesheet" href="index-var.css?v={{ index_var_css_v }}">
<input type="text" id="hidden-text-input">
<div class="row"><div>
@ -88,57 +93,213 @@ endfor
</div></div>
<div class="row"><div>
<h2><a id="weights" href="#weights">Weights & Styles</a></h2>
<p>
There are currently four <a id="weights" href="#weights">weights</a>
There are six weights, each with italic counterparts,
making a total of 12 styles.
</p>
<img src="res/weights-and-styles.svg" style="opacity:0.76;width:100%;display:block;margin:2em 0 3em 0">
<img src="res/weights-and-styles.svg" style="opacity:0.88;width:100%;display:block;margin:3em 0 3em 0">
</div></div>
<div class="row white variable"><div>
<h2><a id="variable" href="#variable">Variable</a></h2>
<p>
Inter UI is offered as both traditional constant font files
(one per style, e.g. Bold Italic, Medium, etc.) as well as a
<a href="https://en.wikipedia.org/wiki/Variable_fonts">Variable Font</a>
file which contains all styles in a much smaller file size.
Additionally, a variable font is ...variable! You can mix and match weight
and italic angle as you please, forming theoretically infinite variations.
</p>
<div class="unsupported-message">
<p>Variable Fonts not supported by this web browser</p>
</div>
<div class="ctrl">
<div class="ctrlrow">
<label title="Weight in the range of 400 to 900">
<span class="label var">Weight:</span>
<input type="range" value="400" min="400" max="900" name="weight">
</label>
<label title="Slant angle in the range of 0° to 10°">
<span class="label var">Slant:</span>
<input type="range" value="0" min="0" max="10" step="0.01" name="slant">
</label>
<label class="tight">
<input type="checkbox" name="animate"> Animate weight &amp; slant
</label>
<label class="tight">
<input type="checkbox" name="invert"> Negative
</label>
</div>
<div class="ctrlrow">
<label title="Font size">
<span class="label">Size:</span>
<input type="range" value="96" min="11" max="400" name="size">
</label>
<label title="Space between letters">
<span class="label">Tracking:</span>
<input type="range" value="0" min="-0.1" max="0.1" step="0.001" name="letterSpacing">
</label>
<label>
<span class="label">Line height:</span>
<input type="range" value="1.2" min="0.7" max="2" step="0.01" name="lineHeight">
</label>
</div>
</div>
</div></div>
<div class="row white variable-sample-row">
<div class="variable-sample" contenteditable>
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890
?!()[]{}&*^%$#@~
</div>
</div>
<script src="index-var.js?v={{ index_var_js_v }}"></script>
<div class="row white"><div>
<p>
Variable fonts is a new technology and support is somewhat in flux at
the time of writing this (fall 2018.)
<a href="var-test.html">This test</a> can be used to discover
what a web browser is capable of.
</p>
</div></div>
<div class="row"><div>
<h2><a id="features" href="#features">Features</a></h2>
<boxes>
<p>
Inter UI comes with many OpenType features that can be used to
tailor functionality and aesthetics to your specific needs.
Some of these features can be combined to form a great number of
alternative variations.
</p>
<boxes class="features">
<box>
<h3>Contextual alternates (<q title='OpenType feature ID'>calt</q>)</h3>
<h3>Contextual alternates <q title='OpenType feature ID'>calt</q></h3>
<p>
This feature is enabled by default and causes certain characters to
adjust themselves or be replaced depending on the surrounding context.
</p>
<tablex><t>
<h><in>Disabled</in><to></to><out>Enabled</out></h>
<r><in>12<em>:</em>34, FE<em></em>X</in><to></to><out>12:34, FE—X</out></r>
<r><in>4<em>.</em>2</in><to></to><out>4.2</out></r>
<r><in><em>(</em>SEMI<em>)</em>PERMANENT</in><to></to><out>(SEMI)PERMANENT</out></r>
<r><in>SFO <em>-></em> STO</in><to></to><out>SFO -> STO</out></r>
<r><in>IIA <em>—></em> OGG</in><to></to><out>IIA —> OGG</out></r>
<r><in>ARN <em><--></em> OGG</in><to></to><out>ARN <--> OGG</out></r>
<r><in>M<em>@</em>N m@n</in><to></to><out>M@N m@n</out></r>
<r><in>Smile <em>:-)</em></in><to></to><out>Smile :-)</out></r>
</t></tablex>
<p>
There are many more contextual alternates.
</p>
</box>
<box>
<h3>Tabular numbers (<q title='OpenType feature ID'>tnum</q>)</h3>
<h3>Tabular numbers <q title='OpenType feature ID'>tnum</q></h3>
<p>
Fixed-width numbers are useful for tabular data, where comparing
columns across rows is desired.
</p>
<tablex><t>
<h><in>Disabled</in><to></to><out>Enabled</out></h>
<r><in><em>1</em>23456<em>7</em>890</in><to></to><out class="tnum">1234567890</out></r>
<r><in>1234567890</in><to></to><out class="tnum">1234567890</out></r>
<r><in>1131711<em>&nbsp;</em></in><to></to><out class="tnum">1131711<em>&nbsp;</em></out></r>
<r><in>0040900<em>&nbsp;</em></in><to></to><out class="tnum">0040900<em>&nbsp;</em></out></r>
<r><in>11:31,711<em>&nbsp;</em></in><to></to><out class="tnum">11:31,711<em>&nbsp;</em></out></r>
<r><in>00:40.900<em>&nbsp;</em></in><to></to><out class="tnum">00:40.900<em>&nbsp;</em></out></r>
<r><in>0.45, 0.91, +0.08<em>&nbsp;</em></in><to></to><out class="tnum">0.45, 0.91, +0.08<em>&nbsp;</em></out></r>
<r><in>1.00, 9.44, 0.13<em>&nbsp;</em></in><to></to><out class="tnum">1.00, 9.44, 0.13<em>&nbsp;</em></out></r>
<r><in>0.00, 1.13, +7.12<em>&nbsp;</em></in><to></to><out class="tnum">0.00, 1.13, +7.12<em>&nbsp;</em></out></r>
</t></tablex>
</box>
<box>
<h3>Slashed zero (<q title='OpenType feature ID'>zero</q>)</h3>
<h3>Numerators <q title='OpenType feature ID'>numr</q></h3>
<tablex><t>
<h><in>Disabled</in><to></to><out>Enabled</out></h>
<r><in><em>0</em>123</in><to></to><out class="zero">0123</out></r>
<r><in>Hello <em>0123</em></in><to></to><out class="numr">Hello 0123</out></r>
</t></tablex>
</box>
<box>
<h3>Fractions (<q title='OpenType feature ID'>frac</q>)</h3>
<h3>Denominators <q title='OpenType feature ID'>dnom</q></h3>
<tablex><t>
<h><in>Disabled</in><to></to><out>Enabled</out></h>
<r><in>Hello <em>0123</em></in><to></to><out class="dnom">Hello 0123</out></r>
</t></tablex>
</box>
<box>
<h3>Superscript <q title='OpenType feature ID'>sups</q></h3>
<tablex><t>
<h><in>Disabled</in><to></to><out>Enabled</out></h>
<r><in>H<em>ello 0123</em></in><to></to><out class="sups">Hello 0123</out></r>
<r><in><em>abcdefghijklm</em></in><to></to><out class="sups">abcdefghijklm</out></r>
<r><in><em>nopqrstuvwxyz</em></in><to></to><out class="sups">nopqrstuvwxyz</out></r>
</t></tablex>
</box>
<box>
<h3>Subscript <q title='OpenType feature ID'>subs</q></h3>
<tablex><t>
<h><in>Disabled</in><to></to><out>Enabled</out></h>
<r><in>H<em>ello 0123</em></in><to></to><out class="subs">Hello 0123</out></r>
<r><in><em>abcdefghijklm</em></in><to></to><out class="subs">abcdefghijklm</out></r>
<r><in><em>nopqrstuvwxyz</em></in><to></to><out class="subs">nopqrstuvwxyz</out></r>
</t></tablex>
</box>
<box>
<h3>Fractions <q title='OpenType feature ID'>frac</q></h3>
<p>
This feature is contextually sensitive and will convert "words" of
numbers separated by forward slash into proper fractions.
This feature is dynamic and allows for any fractions.
Note that the digits used for fractions are custom-made for their
small size, and are even made separately from the slightly larger
Superscript and Subscript numbers.
</p>
<tablex><t>
<h><in>Disabled</in><to></to><out>Enabled</out></h>
<r>
<in><em>1/3</em> <em>22/9</em> <em>3/4/5</em></in>
<to></to><out class="frac">1/3 22/9 3/4/5</out>
<in><em>1/3</em> <em>3/4</em> <em>1/5</em> <em>1337/5910</em></in>
<to></to><out class="frac">1/3 3/4 1/5 1337/5910</out>
</r>
</t></tablex>
</box>
<box>
<h3>Stylistic set 1: Alternate digits (<q title='OpenType feature ID'>ss01</q>)</h3>
<h3>Case alternates <q title='OpenType feature ID'>case</q></h3>
<p>
Switches out some glyphs to work better with capital letters and numbers.
</p>
<tablex><t>
<h><in>Disabled</in><to></to><out>Enabled</out></h>
<r>
<in><em>(</em>Hello<em>)</em> <em>[</em>World<em>]</em> <em>{</em>9000<em>}</em></in>
<to></to><out class="case">(Hello) [World] {9000}</out>
</r>
<r><in>SCHOOL <em>@</em> RUN</in><to></to><out class="case">SCHOOL @ RUN</out></r>
<r><in>3 <em>+</em> 9 <em>=</em> 12 <em>*</em> 1</in><to></to><out class="case">3 + 9 = 12 * 1</out></r>
<r><in><em>*</em> <em>+</em> <em>÷</em> <em>±</em> <em>×</em> <em>=</em> <em></em> <em></em></in><to></to><out class="case">* + ÷ ± × = ≠ •</out></r>
<r><in><em></em> <em></em> <em></em> <em></em> <em></em> <em>-</em> <em></em> <em></em> <em>:</em></in><to></to><out class="case">→ ← ⟶ ⟵ - — :</out></r>
</t></tablex>
</box>
<box>
<h3>Stylistic set 1: Alternate digits <q title='OpenType feature ID'>ss01</q></h3>
<p>
An alternate style of digits.
Note that individual digit styles can be cherry-picked using the cvXX
features.
</p>
<tablex><t>
<h><in>Disabled</in><to></to><out>Enabled</out></h>
<r>
@ -153,27 +314,74 @@ endfor
</box>
<box>
<h3>Case alternates (<q title='OpenType feature ID'>case</q>)</h3>
<h3>Stylistic set 2: Disambiguation <q title='OpenType feature ID'>ss02</q></h3>
<p>
Alternate glyph set that decreases ambiguity.
</p>
<tablex><t>
<h><in>Disabled</in><to></to><out>Enabled</out></h>
<r>
<in><em>(</em>Hello<em>)</em> <em>[</em>World<em>]</em> <em>{</em>9000<em>}</em></in>
<to></to><out class="case">(Hello) [World] {9000}</out>
</r>
<r><in>SCHOOL <em>@</em> RUN</in><to></to><out class="case">SCHOOL @ RUN</out></r>
<r><in>3 <em>+</em> 9 <em>=</em> 12 <em>*</em> 1</in><to></to><out class="case">3 + 9 = 12 * 1</out></r>
<r><in><em>*</em> <em>+</em> <em>÷</em> <em>±</em> <em>×</em> <em>=</em> <em></em> <em></em></in><to></to><out class="case">* + ÷ ± × = ≠ •</out></r>
<r><in><em></em> <em></em> <em></em> <em></em> <em></em> <em>-</em> <em></em> <em></em> <em>:</em></in><to></to><out class="case">→ ← ⟶ ⟵ - — :</out></r>
<r><in>WP<em>0</em>AC2A9XJS1<em>0</em>12O9</in><to></to><out class="ss02">WP0AC2A9XJS1012O9</out></r>
<r><in>I<em>ll</em>ega<em>l</em></in><to></to><out class="ss02">Illegal</out></r>
</t></tablex>
</box>
<box>
<h3>Discretionary ligatures <q title='OpenType feature ID'>dlig</q></h3>
<tablex><t>
<h><in>Disabled</in><to></to><out>Enabled</out></h>
<r><in><em>¡¿</em>What<em>?!</em></in><to></to><out class="dlig">¡¿What?!</out></r>
<r><in><em>¿¡</em>What<em>!?</em></in><to></to><out class="dlig">¿¡What!?</out></r>
</t></tablex>
</box>
<box>
<h3>Slashed zero <q title='OpenType feature ID'>zero</q></h3>
<tablex><t>
<h><in>Disabled</in><to></to><out>Enabled</out></h>
<r><in><em>0</em>123</in><to></to><out class="zero">0123</out></r>
</t></tablex>
</box>
<box>
<h3>Character variants <q title='OpenType feature ID'>cvXX</q></h3>
<p>
Allows cherry-picking alternate characters.
</p>
<tablex><t>
<h><name>Feature&nbsp;&nbsp;</name><in>Disabled</in><to></to><out>Enabled</out></h>
<r><name>cv01</name><in>1</in><to></to><out class="cv01">1</out></r>
<r><name>cv02</name><in>4</in><to></to><out class="cv02">4</out></r>
<r><name>cv03</name><in>6</in><to></to><out class="cv03">6</out></r>
<r><name>cv04</name><in>9</in><to></to><out class="cv04">9</out></r>
<r><name>cv05</name><in>l ł ƚ ɫ ɬ ŀ ĺ ļ ľ ḷ ḹ ḻ ḽ</in><to></to><out class="cv05">l ł ƚ ɫ ɬ ŀ ĺ ļ ľ ḷ ḹ ḻ ḽ</out></r>
<r><name>cv06</name><in>r ɽ ɍ ɼ ŕ ŗ ř ȑ ȓ ṙ ṛ ṝ ṟ</in><to></to><out class="cv06">r ɽ ɍ ɼ ŕ ŗ ř ȑ ȓ ṙ ṛ ṝ ṟ</out></r>
</t></tablex>
</box>
<box>
<h3>Capital Spacing <q title='OpenType feature ID'>cpsp</q></h3>
<p>
Slightly increases letter spacing for increased legibility of
capital letters. Note: It's usually better to set letter-spacing
(aka tracking) manually instead of using this feature. It's here
mainly for completeness.
</p>
<tablex><t>
<h><in>Disabled</in><to></to><out>Enabled</out></h>
<r><in>FOREVER IMMATERIAL</in><to></to><out class="cpsp">FOREVER IMMATERIAL</out></r>
<r><in>TORSCHLUẞPANIK</in><to></to><out class="cpsp">TORSCHLUẞPANIK</out></r>
</t></tablex>
</box>
</boxes>
<p>
Also includes some
Localized Forms (<q title='OpenType feature ID'>locl</q>),
Numerators (<q title='OpenType feature ID'>numr</q>) and
Denominators (<q title='OpenType feature ID'>dnom</q>).
Additional features, not highlighted above:
<q title='OpenType feature ID'>locl</q>,
<q title='OpenType feature ID'>aalt</q>,
<q title='OpenType feature ID'>ccmp</q>,
<q title='OpenType feature ID'>ordn</q> and
<q title='OpenType feature ID'>salt</q>,
</p>
<p>&nbsp;</p>
@ -213,8 +421,8 @@ endfor
<h2><a id="status" href="#status">Current status &amp; usability</a></h2>
<p>
Inter UI works great for English-language text, and pretty well for other
Latin and Cyrillic languages. There's still a lot of work to be done, and
Inter UI works great for Latin text and pretty well for
Cyrillic. There's still some work to be done on Cyrillic and
<a href="https://github.com/rsms/inter/blob/master/CONTRIBUTING.md">contributions are warmly welcomed</a>. The playground contains <a href="lab/?sample=Body%20text%201&size=16">a lot of samples</a>, including some common <a href="lab/?sample=Kerning%20body%20multi-lang&size=16">non English-language words in the playground.</a>
</p>

View File

@ -116,6 +116,11 @@ html {
}
}
BUGS:
- Safari 12.0 will default to italic instead of regular when font-weight
is provided in a @font-face declaration.
Workaround: Use "Inter UI var safari-fix" for Safari, or explicitly set
`font-variation-settings:"slnt" DEGREE`.
*/
@font-face {
font-family: 'Inter UI var';
@ -124,3 +129,9 @@ html {
src: url("font-files/Inter-UI.var.woff2?v=3.0") format("woff2-variations"),
url("font-files/Inter-UI.var.woff2?v=3.0") format("woff2");
}
@font-face {
font-family: 'Inter UI var safari-fix';
font-style: oblique 0deg 10deg;
src: url("font-files/Inter-UI.var.woff2?v=3.0") format("woff2-variations"),
url("font-files/Inter-UI.var.woff2?v=3.0") format("woff2");
}

File diff suppressed because it is too large Load Diff

View File

@ -71,7 +71,7 @@ label {
</label>
</div>
<div class="sample" contenteditable>
Inter UI 3.0 is variable and flexible<br>
Inter UI 3.0<br>
Variable weight axis<br>
Variable slant/oblique axis<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>

View File

@ -2,7 +2,7 @@
html { }
body {
background-color: #f4f4f4;
color: #414141;
color: #111;
font: 15px/22px 'Inter UI', system-ui, sans-serif;
font-size: 15px;
@ -25,6 +25,30 @@ body {
font-feature-settings:"kern" 1, "liga" 1;
}
/* Font style classifiers used by samples and dynmetrics */
/* Note: font-variation-settings is needed for Safari. */
.font-style-regular { font-variation-settings: "wght" 400, "slnt" 0 !important; font-weight:400 !important; font-style:normal !important; }
.font-style-italic { font-variation-settings: "wght" 400, "slnt" 100 !important; font-weight:400 !important; font-style:oblique !important; }
.font-style-medium { font-variation-settings: "wght" 500, "slnt" 0 !important; font-weight:500 !important; font-style:normal !important; }
.font-style-medium-italic { font-variation-settings: "wght" 500, "slnt" 100 !important; font-weight:500 !important; font-style:oblique !important; }
.font-style-semi-bold { font-variation-settings: "wght" 600, "slnt" 0 !important; font-weight:600 !important; font-style:normal !important; }
.font-style-semi-bold-italic { font-variation-settings: "wght" 600, "slnt" 100 !important; font-weight:600 !important; font-style:oblique !important; }
.font-style-bold { font-variation-settings: "wght" 700, "slnt" 0 !important; font-weight:700 !important; font-style:normal !important; }
.font-style-bold-italic { font-variation-settings: "wght" 700, "slnt" 100 !important; font-weight:700 !important; font-style:oblique !important; }
.font-style-extra-bold { font-variation-settings: "wght" 800, "slnt" 0 !important; font-weight:800 !important; font-style:normal !important; }
.font-style-extra-bold-italic { font-variation-settings: "wght" 800, "slnt" 100 !important; font-weight:800 !important; font-style:oblique !important; }
.font-style-black { font-variation-settings: "wght" 900, "slnt" 0 !important; font-weight:900 !important; font-style:normal !important; }
.font-style-black-italic { font-variation-settings: "wght" 900, "slnt" 100 !important; font-weight:900 !important; font-style:oblique !important; }
@supports (font-variation-settings: normal) {
body {
font-family: 'Inter UI var', system-ui, sans-serif;
}
html.safari body {
font-family: 'Inter UI var safari-fix', system-ui, sans-serif;
}
}
:target:before {
content:"";
display: block;
@ -108,8 +132,7 @@ num { /* number */
}
em, i, .italic {
font-style: italic;
/*font-variation-settings: 'slnt' 10;*/
font-style: oblique;
}
small {
@ -133,8 +156,9 @@ h1 {
font-weight: 700;
}
h2 {
font-size: 24px;
letter-spacing: -0.02em;
font-size: 30px;
font-weight: 600;
letter-spacing: -0.015em;
line-height: 30px;
margin-bottom: 25px;
margin-top: 10px;
@ -172,7 +196,12 @@ h2.banner {
}
h3 {
font-size: inherit;
font-size: 20px;
font-weight: 600;
}
h3 q {
font-weight: 400;
padding-left: 0.5em;
}
h1 > a, h2 > a, h3 > a {
@ -182,20 +211,6 @@ h1 > a, h2 > a, h3 > a {
background: none;
}
/* font style classifiers used by samples and dynmetrics */
.font-style-regular { font-variation-settings: "wght" 400, "ital" 0 !important; font-weight:400 !important; font-style:normal !important; }
.font-style-italic { font-variation-settings: "wght" 400, "ital" 100 !important; font-weight:400 !important; font-style:italic !important; }
.font-style-medium { font-variation-settings: "wght" 500, "ital" 0 !important; font-weight:500 !important; font-style:normal !important; }
.font-style-medium-italic { font-variation-settings: "wght" 500, "ital" 100 !important; font-weight:500 !important; font-style:italic !important; }
.font-style-semi-bold { font-variation-settings: "wght" 600, "ital" 0 !important; font-weight:800 !important; font-style:normal !important; }
.font-style-semi-bold-italic { font-variation-settings: "wght" 600, "ital" 100 !important; font-weight:800 !important; font-style:italic !important; }
.font-style-bold { font-variation-settings: "wght" 700, "ital" 0 !important; font-weight:700 !important; font-style:normal !important; }
.font-style-bold-italic { font-variation-settings: "wght" 700, "ital" 100 !important; font-weight:700 !important; font-style:italic !important; }
.font-style-extra-bold { font-variation-settings: "wght" 800, "ital" 0 !important; font-weight:800 !important; font-style:normal !important; }
.font-style-extra-bold-italic { font-variation-settings: "wght" 800, "ital" 100 !important; font-weight:800 !important; font-style:italic !important; }
.font-style-black { font-variation-settings: "wght" 900, "ital" 0 !important; font-weight:900 !important; font-style:normal !important; }
.font-style-black-italic { font-variation-settings: "wght" 900, "ital" 100 !important; font-weight:900 !important; font-style:italic !important; }
.row {
padding: 50px;
display: flex;
@ -279,19 +294,26 @@ h1 > a, h2 > a, h3 > a {
background: white;
}
.row.dark {
.row.dark,
.row.black {
background: #2b2b2b;
color: #99999b;
}
.row.dark a {
.row.black {
background: #010101;
}
.row.dark a,
.row.black a {
text-decoration-color: rgba(255, 255, 255, 0.2);
color: #aaa;
}
.row.dark a:hover {
.row.dark a:hover,
.row.black a:hover {
color: rgb(95, 170, 255);
text-decoration: underline rgb(95, 170, 255);
}
.row.dark h2, .row.dark h2 > a {
.row.dark h2, .row.dark h2 > a,
.row.black h2, .row.black h2 > a {
color: #ccc;
background: none;
}
@ -379,81 +401,6 @@ tablex {
text-decoration: none;
display: table-row;
}
tablex in, tablex to, tablex out {
display: table-cell;
width: 5%;
white-space: pre;
padding-bottom:0.5em;
}
/*tablex to {
width:0;
}*/
tablex to::after {
-moz-font-feature-settings: 'calt' 1, 'case' 1;
-ms-font-feature-settings: 'calt' 1, 'case' 1;
-o-font-feature-settings: 'calt' 1, 'case' 1;
-webkit-font-feature-settings: 'calt' 1, 'case' 1;
font-feature-settings: 'calt' 1, 'case' 1;
content: " → ";
color: rgba(0,0,0,0.2);
}
tablex in, tablex out {
color: rgba(0,0,0,0.8);
}
tablex in {
-moz-font-feature-settings: 'calt' 0;
-ms-font-feature-settings: 'calt' 0;
-o-font-feature-settings: 'calt' 0;
-webkit-font-feature-settings: 'calt' 0;
font-feature-settings: 'calt' 0;
}
tablex out {
-moz-font-feature-settings: 'calt' 1;
-ms-font-feature-settings: 'calt' 1;
-o-font-feature-settings: 'calt' 1;
-webkit-font-feature-settings: 'calt' 1;
font-feature-settings: 'calt' 1;
}
tablex out.zero {
-moz-font-feature-settings: 'calt' 1, 'zero' 1;
-ms-font-feature-settings: 'calt' 1, 'zero' 1;
-o-font-feature-settings: 'calt' 1, 'zero' 1;
-webkit-font-feature-settings: 'calt' 1, 'zero' 1;
font-feature-settings: 'calt' 1, 'zero' 1;
}
tablex out.tnum {
-moz-font-feature-settings: 'calt' 1, 'tnum' 1;
-ms-font-feature-settings: 'calt' 1, 'tnum' 1;
-o-font-feature-settings: 'calt' 1, 'tnum' 1;
-webkit-font-feature-settings: 'calt' 1, 'tnum' 1;
font-feature-settings: 'calt' 1, 'tnum' 1;
}
tablex out.case {
-moz-font-feature-settings: 'calt' 1, 'case' 1;
-ms-font-feature-settings: 'calt' 1, 'case' 1;
-o-font-feature-settings: 'calt' 1, 'case' 1;
-webkit-font-feature-settings: 'calt' 1, 'case' 1;
font-feature-settings: 'calt' 1, 'case' 1;
}
tablex out.frac {
-moz-font-feature-settings: 'calt' 1, 'frac' 1;
-ms-font-feature-settings: 'calt' 1, 'frac' 1;
-o-font-feature-settings: 'calt' 1, 'frac' 1;
-webkit-font-feature-settings: 'calt' 1, 'frac' 1;
font-feature-settings: 'calt' 1, 'frac' 1;
}
tablex out.ss01 {
-moz-font-feature-settings: 'calt' 1, 'ss01' 1;
-ms-font-feature-settings: 'calt' 1, 'ss01' 1;
-o-font-feature-settings: 'calt' 1, 'ss01' 1;
-webkit-font-feature-settings: 'calt' 1, 'ss01' 1;
font-feature-settings: 'calt' 1, 'ss01' 1;
}
tablex em {
font-style: inherit;
background: #FBE9A3;
color: rgba(0,0,0,1);
}
boxes {

View File

@ -86,6 +86,13 @@ function InterUIDynamicTracking(fontSize) {
return a + b * Math.pow(Math.E, c * fontSize)
}
// InterUIDynamicLineHeight produces the line height for the given font size
//
function InterUIDynamicLineHeight(fontSize) {
var l = 1.4
return Math.round(fontSize * l)
}
// Mac or not? Maybe even a buggy Safari?
var isMac = false

View File

@ -2,6 +2,14 @@
function passThrough(v) { return v }
function valueGetter(el) {
return (
'valueAsNumber' in el ? () => el.valueAsNumber :
(el.type == 'number' || el.type == 'range') ? () => parseFloat(el.value) :
() => el.value
)
}
function Binding(name){
this.name = name
this.value = undefined
@ -15,8 +23,9 @@ function Binding(name){
Binding.prototype.addInput = function(el) {
var binding = this
var _onInput = function(ev) {
binding.setValue(el.value, el)
var getValue = valueGetter(el)
var _onInput = ev => {
binding.setValue(getValue(), el)
}
var input = {
el: el,
@ -24,13 +33,18 @@ Binding.prototype.addInput = function(el) {
}
this.inputs.push(input)
if (this.value === undefined) {
this.value = el.value
this.value = getValue()
} else {
input.el.value = this.formatter(this.value)
}
el.addEventListener('input', _onInput, {passive:true})
if (el.tagName == 'SELECT' || el.type == 'checkbox') {
el.addEventListener('change', _onInput, {passive:true})
} else {
el.addEventListener('input', _onInput, {passive:true})
}
}
Binding.prototype.addOutput = function(el) {
this.outputs.push(el)
if (this.value !== undefined) {
@ -71,12 +85,13 @@ Binding.prototype.setValue = function(nextval, origin) {
})
}
// ------------------------------------------------------------------------
function Bindings() {
this.bindings = {}
}
Bindings.prototype.getBinding = function(name, input) {
Bindings.prototype.getBinding = function(name) {
var binding = this.bindings[name]
if (!binding) {
binding = new Binding(name)
@ -188,3 +203,40 @@ Bindings.prototype.configure = function(name, value, parser, listener) {
binding.parser = parser
}
}
Bindings.prototype.allBindings = (
typeof Object.values == 'function' ? function() {
return Object.values(this.bindings)
} : function() {
let v = []
for (let name in this.bindings) {
v.push(this.bindings[name])
}
return v
}
)
Bindings.prototype.getValues = function() {
let values = {}
for (let name in this.bindings) {
values[name] = this.bindings[name].value
}
return values
}
Bindings.prototype.setValues = function(values) {
Object.keys(values).forEach(name => {
let b = this.bindings[name]
if (!b) {
if (console.warn) {
console.warn('Bindings.setValues: ignoring unknown "' + name + '"')
}
return
}
// console.log(`bindings setValue ${name} => ${values[name]}`)
b.setValue(values[name])
})
}

1
docs/res/close.svg Executable file
View File

@ -0,0 +1 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 8.707l4.646 4.647.708-.708L8.707 8l4.647-4.646-.708-.708L8 7.293 3.354 2.646l-.708.708L7.293 8l-4.647 4.646.708.708L8 8.707z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 232 B

319
docs/res/ctxedit.css Normal file
View File

@ -0,0 +1,319 @@
:root {
--strip-height: 40px;
}
#ctxedit-ui {
box-sizing: border-box;
overflow: hidden;
display: flex;
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 0 0;
height: var(--strip-height);
background: #111;
color: #ccc;
font-size: 12px;
/*border-top-left-radius: 4px;
border-bottom-left-radius: 4px;*/
padding: 0 50px;
display: flex;
justify-content: center;
opacity:0;
transition: 90ms all cubic-bezier(0.25, 0.47, 0.44, 0.93);
transform: translate(0, var(--strip-height));
}
#ctxedit-ui.visible {
opacity:1;
transform: translate(0, 0);
}
#ctxedit-ui .wrapper {
display: flex;
flex-direction: row;
align-items: stretch;
justify-content: center;
width: 100%;
max-width: 888px; /* same as base.css .row > * */
flex: 1 0 100%;
}
#ctxedit-ui .control {
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
min-height: 30px;
margin: 0 16px;
}
#ctxedit-ui .control:first-child {
margin-left:0;
}
#ctxedit-ui .control.range {
flex: 1 1 auto;
max-width: 200px;
}
#ctxedit-ui .control > * {
flex: 1 1 auto;
margin:0;
box-sizing: border-box;
}
#ctxedit-ui .control > :last-child {
margin-right: 0;
}
#ctxedit-ui .control > select {
min-width: 8em;
flex: 0 1 auto;
align-items: center;
justify-content: center;
}
#ctxedit-ui .control > input,
#ctxedit-ui .control > select {
width: 0;
outline: none;
color: inherit;
}
#ctxedit-ui .control.popup {
margin-right: 0px;
}
#ctxedit-ui .control > select {
font: inherit;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
border: none;
background-color: #111;
margin: 0;
padding: 0;
height: var(--strip-height);
background-image: url(popup.svg);
background-repeat: no-repeat;
width: 120px;
color: white;
opacity: 0.6;
background-position: left center;
padding-left: 20px;
line-height: var(--strip-height);
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
#ctxedit-ui .control > select::-ms-expand {
display: none;
}
#ctxedit-ui .control > select:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 #fff;
background-color: #111;
font: inherit;
font-size: inherit;
}
#ctxedit-ui .control > select:hover {
opacity: 1;
}
#ctxedit-ui .control > input[type="number"],
#ctxedit-ui .control > input[type="text"] {
background: none;
border: none;
padding: 4px 0;
font-size: inherit;
/*border-radius: 2px;*/
}
#ctxedit-ui .control > input[type="number"] {
max-width: 48px;
text-align: left;
-moz-appearance: textfield;
-moz-font-feature-settings: 'tnum' 1;
-ms-font-feature-settings: 'tnum' 1;
-o-font-feature-settings: 'tnum' 1;
-webkit-font-feature-settings: 'tnum' 1;
font-feature-settings: 'tnum' 1;
}
#ctxedit-ui .control > input[type=number]::-webkit-inner-spin-button,
#ctxedit-ui .control > input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
#ctxedit-ui .control > input[type="range"] {
/*max-width: 80%;*/
flex: 1 1 auto;
display: block;
}
#ctxedit-ui .control > input[type="color"] {
width:20px;
height:20px;
border: none;
background: transparent;
}
#ctxedit-ui .control > img.icon,
#ctxedit-ui .control > label {
user-select: none;
font-family: georgia, serif;
font-style: italic;
color: white;
width: 16px;
height: 16px;
flex: 0 0 auto;
margin-right: 16px;
opacity: 0.6;
}
#ctxedit-ui .button {
width: var(--strip-height);
height: var(--strip-height);
background-repeat: no-repeat;
background-position: center;
opacity: 0.6;
margin:0;
}
#ctxedit-ui .button:hover {
opacity: 1;
background-color: #292929;
}
#ctxedit-ui .button:active {
background-color: #444;
}
#ctxedit-ui .button.features-button { background-image: url(settings.svg); }
#ctxedit-ui .button.reset-button { background-image: url(reset.svg); }
#ctxedit-ui .button.dismiss-button { background-image: url(dismiss.svg); }
.font-preload {
position: fixed;
display: block;
opacity: 0;
pointer-events: none;
}
.slider-value-tip {
pointer-events: none;
opacity: 0;
position: fixed;
text-align: center;
width: 100px;
/*background: hotpink;*/
left: 500px;
display: flex;
flex-direction: column;
align-items: center;
z-index: 9;
transition: opacity 120ms ease-out;
filter: drop-shadow(0px 2px 6px rgba(0,0,0,0.2));
--fgcolor: #fff;
--bgcolor: #444;
}
.slider-value-tip .value {
padding: 4px 10px;
border-radius: 2px;
font-size: 11px;
letter-spacing: 0.013em;
color: var(--fgcolor);
background: var(--bgcolor);
-moz-font-feature-settings: 'tnum' 1;
-ms-font-feature-settings: 'tnum' 1;
-o-font-feature-settings: 'tnum' 1;
-webkit-font-feature-settings: 'tnum' 1;
font-feature-settings: 'tnum' 1;
z-index: 1;
}
.slider-value-tip .callout {
background: var(--bgcolor);
width:10px;
height:10px;
transform: translate(0, -6px) rotate(45deg);
z-index: 0;
}
.slider-value-tip.visible {
opacity: 1;
}
.styled-inputs-neg {
--track-thickness: 2px;
--track-color: rgba(255, 255, 255, 0.3);
--thumb-outline-thickness: 2px;
--thumb-outline-color: #111; /* match control strip */
--thumb-diameter: 10px;
--thumb-color: white;
--active-color: rgb(95, 170, 255);
}
.styled-inputs-neg input[type=range] {
-webkit-appearance: none;
margin: 0;
width: 100%;
height: var(--strip-height);
background: transparent;
}
.styled-inputs-neg input[type=range]:focus {
outline: none;
}
.styled-inputs-neg input[type=range]::-webkit-slider-runnable-track {
width: 100%;
margin: 0;
animate: 0.2s;
background: var(--track-color);
height: var(--track-thickness);
}
.styled-inputs-neg input[type=range]:focus::-webkit-slider-runnable-track {
background: var(--active-color);
}
.styled-inputs-neg input[type=range]::-moz-range-track {
width: 100%;
margin: 0;
animate: 0.2s;
background: var(--track-color);
height: var(--track-thickness);
}
.styled-inputs-neg input[type=range]:focus::-moz-range-track {
background: var(--active-color);
}
.styled-inputs-neg input[type=range]::-webkit-slider-thumb {
--thumb-diameter2: calc(var(--thumb-diameter) + var(--thumb-outline-thickness) * 2);
width: var(--thumb-diameter2);
height: var(--thumb-diameter2);
border: var(--thumb-outline-thickness) solid var(--thumb-outline-color);
border-radius: 100%;
background: var(--thumb-color);
-webkit-appearance: none;
margin-top: calc(((var(--thumb-diameter2) / 2) - (var(--track-thickness) / 2)) * -1);
}
.styled-inputs-neg input[type=range]::-moz-range-thumb {
width: var(--thumb-diameter);
height: var(--thumb-diameter);
border: var(--thumb-outline-thickness) solid var(--thumb-outline-color);
border-radius: 100%;
background: var(--thumb-color);
margin-top: calc(((var(--thumb-diameter) / 2) - (var(--track-thickness) / 2)) * -1);
}
/* MS Edge -- note that we can't use CSS variables here */
.styled-inputs-neg input[type=range]::-ms-track {
background: transparent;
border-color: transparent;
border-width: 0 0;
color: transparent; /* markings */
height: 2px;
animate: 0.2s;
margin: 0;
}
.styled-inputs-neg input[type=range]::-ms-fill-lower,
.styled-inputs-neg input[type=range]::-ms-fill-upper {
background: white;
opacity: 0.3;
}
.styled-inputs-neg input[type=range]::-ms-thumb {
width: 9px;
height: 9px;
/*border: 2px solid rgba(0,0,0,0.8);*/
box-shadow: 0px 0px 0px 2px #111;
border-radius: 100%;
background: white;
}
/* Note: :focus selectors are buggy in Edge, so we skip that */

566
docs/res/ctxedit.js Normal file
View File

@ -0,0 +1,566 @@
var CtxEdit = (function(){
function getLocalObject(key) {
let s = sessionStorage.getItem(key)
if (s) {
try {
return JSON.parse(s)
} catch (e) {
console.error(
`failed to parse sessionStorage value "${s}" for key ${key}`,
err.stack || String(err)
)
}
}
return null
}
function setLocalObject(key, value) {
let json = JSON.stringify(value)
sessionStorage.setItem(key, json)
}
function rmLocalObject(key) {
sessionStorage.removeItem(key)
}
class FloatProp {
constructor(cssProp, unitSuffix) {
this.cssProp = cssProp
this.unitSuffix = unitSuffix
}
valueInStyle(s) {
let v = s[this.cssProp]
return v !== undefined ? parseFloat(v) : v
}
applyStyle(el, value) {
el.style[this.cssProp] = value + this.unitSuffix
}
}
class FontStyleProp {
valueInStyle(s) {
let italic = s['font-style'] == 'italic' || s['font-style'].indexOf('oblique') != -1
let weight = parseFloat(s['font-weight'])
if (isNaN(weight)) {
weight = s['font-weight']
if (weight == 'normal') { return italic ? 'italic' : 'regular' }
if (weight == 'medium') { return italic ? 'medium-italic' : 'medium' }
if (weight == 'semi-bold') { return italic ? 'semi-bold-italic' : 'semi-bold' }
if (weight == 'bold') { return italic ? 'bold-italic' : 'bold' }
if (weight == 'extra-bold') { return italic ? 'extra-bold-italic' : 'extra-bold' }
} else {
if (weight <= 450) { return italic ? 'italic' : 'regular' }
if (weight <= 550) { return italic ? 'medium-italic' : 'medium' }
if (weight <= 650) { return italic ? 'semi-bold-italic' : 'semi-bold' }
if (weight <= 750) { return italic ? 'bold-italic' : 'bold' }
if (weight <= 850) { return italic ? 'extra-bold-italic' : 'extra-bold' }
}
return italic ? 'black-italic' : 'black'
}
applyStyle(el, value) {
let cl = el.classList
for (let k of Array.from(cl.values())) {
if (k.indexOf('font-style-') == 0) {
cl.remove(k)
}
}
cl.add('font-style-' + value)
}
}
class LineHeightProp {
valueInStyle(s) {
let v = s['line-height']
if (v === undefined) {
return 1.0
}
if (v.lastIndexOf('px') == v.length - 2) {
// compute
return parseFloat(
(parseFloat(v) / parseFloat(s['font-size'])).toFixed(3)
)
}
v = parseFloat(v)
return isNaN(v) ? 1.0 : v
}
applyStyle(el, value) {
el.style['line-height'] = String(value)
}
}
class TrackingProp {
valueInStyle(s) {
let v = s['letter-spacing']
if (v === undefined) {
return 0
}
if (v.lastIndexOf('px') == v.length - 2) {
// compute
return parseFloat(
(parseFloat(v) / parseFloat(s['font-size'])).toFixed(3)
)
}
v = parseFloat(v)
return isNaN(v) ? 0 : v
}
applyStyle(el, value) {
el.style['letter-spacing'] = value.toFixed(3) + 'em'
}
}
const Props = {
size: new FloatProp('font-size', 'px'),
tracking: new TrackingProp(),
lineHeight: new LineHeightProp(),
style: new FontStyleProp(),
}
function valuesFromStyle(s) {
let values = {}
for (let name in Props) {
let p = Props[name]
values[name] = p.valueInStyle(s)
}
return values
}
class Editable {
constructor(el, key) {
this.el = el
this.key = key
this.defaultValues = valuesFromStyle(getComputedStyle(this.el))
// console.log('default values:', this.defaultValues)
this.values = Object.assign({}, this.defaultValues)
this.explicitTracking = false
this.explicitTrackingKey = this.key + ":etracking"
this.loadValues()
this.updateSizeDependantProps()
}
resetValues() {
this.values = Object.assign({}, this.defaultValues)
let style = this.el.style
for (let name in this.values) {
Props[name].applyStyle(this.el, this.values[name])
}
rmLocalObject(this.key)
rmLocalObject(this.explicitTrackingKey)
this.explicitTracking = false
this.updateSizeDependantProps()
}
setExplicitTracking(explicitTracking) {
if (this.explicitTracking !== explicitTracking) {
this.explicitTracking = explicitTracking
if (!this.explicitTracking) {
this.updateSizeDependantProps()
}
}
}
setValue(name, value) {
this.values[name] = value
Props[name].applyStyle(this.el, value)
if (name == 'size') {
this.updateSizeDependantProps()
}
}
updateSizeDependantProps() {
let size = this.values.size
// dynamic tracking
if (!this.explicitTracking) {
this.setValue('tracking', InterUIDynamicTracking(size))
}
// left indent
let leftMargin = 0
// TODO: Find a formula for this: F(size) -> leftMargin
// TODO: Consider making this part of dynamic metrics.
if (size >= 162) { leftMargin = -10; }
else if (size >= 146) { leftMargin = -9; }
else if (size >= 130) { leftMargin = -8; }
else if (size >= 114) { leftMargin = -7; }
else if (size >= 98) { leftMargin = -6; }
else if (size >= 79) { leftMargin = -5; }
else if (size >= 64) { leftMargin = -4; }
else if (size >= 48) { leftMargin = -3; }
else if (size >= 32) { leftMargin = -2; }
else if (size >= 16) { leftMargin = -1; }
if (leftMargin == 0) {
this.el.style.marginLeft = null
} else {
this.el.style.marginLeft = leftMargin + 'px'
}
}
loadValues() {
let values = getLocalObject(this.key)
if (values && typeof values == 'object') {
for (let name in values) {
if (name in this.values) {
let value = values[name]
this.values[name] = value
Props[name].applyStyle(this.el, value)
} else if (console.warn) {
console.warn(`Editable.loadValues ignoring unknown "${name}"`)
}
}
// console.log(`loaded values for ${this}:`, values)
}
let etr = getLocalObject(this.explicitTrackingKey)
this.explicitTracking = false
if (etr) {
this.explicitTracking = true
}
}
isDefaultValues() {
for (let k in this.values) {
if (this.values[k] !== this.defaultValues[k]) {
return false
}
}
return true
}
saveValues() {
if (this.isDefaultValues()) {
rmLocalObject(this.key)
rmLocalObject(this.explicitTrackingKey)
} else {
setLocalObject(this.key, this.values)
setLocalObject(this.explicitTrackingKey, this.explicitTracking ? "1" : "0")
}
// console.log(`saved values for ${this}`)
}
toString() {
return `Editable(${this.key})`
}
}
var supportsFocusTrick = (u =>
u.indexOf('Firefox/') == -1
)(navigator.userAgent)
class CtxEdit {
constructor() {
this.bindings = new Bindings()
this.keyPrefix = 'ctxedit:' + document.location.pathname + ':'
this.editables = new Map()
this.ui = $('#ctxedit-ui')
this.currEditable = null
this._saveValuesTimer = null
this.isChangingBindings = true
this.bindings = new Bindings()
this.initBindings()
this.initUI()
this.addAllEditables()
this.isChangingBindings = false
this.preloadFonts()
if (supportsFocusTrick) {
this.ui.addEventListener('focus', ev => {
if (this.currEditable) {
ev.preventDefault()
ev.stopImmediatePropagation()
this.currEditable.el.focus() // breaks Firefox
}
}, {capture:true, passive:false})
}
}
initUI() {
$('.reset-button', this.ui).addEventListener('click', ev => this.reset())
$('.dismiss-button', this.ui).addEventListener('click', ev => this.stopEditing())
this.initRangeSliders()
}
initRangeSliders() {
this._sliderTimers = new Map()
$$('input[type="range"]', this.ui).forEach(input => {
var binding = this.bindings.getBinding(input.dataset.binding)
// create and hook up value tip
let valtip = document.createElement('div')
let valtipval = document.createElement('div')
let valtipcallout = document.createElement('div')
valtip.className = 'slider-value-tip'
valtipval.className = 'value'
valtipcallout.className = 'callout'
valtipval.innerText = '0'
valtip.appendChild(valtipval)
valtip.appendChild(valtipcallout)
binding.addOutput(valtipval)
document.body.appendChild(valtip)
let inputBounds = {}
let min = parseFloat(input.getAttribute('min'))
let max = parseFloat(input.getAttribute('max'))
if (isNaN(min)) {
min = 0
}
if (isNaN(max)) {
max = 1
}
const sliderThumbWidth = 12
const valtipYOffset = 14
let updateValTipXPos = () => {
let r = (binding.value - min) / (max - min)
let sliderWidth = inputBounds.width - sliderThumbWidth
let x = ((inputBounds.x + (sliderThumbWidth / 2)) + (sliderWidth * r)) - (valtip.clientWidth / 2)
valtip.style.left = x + 'px'
}
binding.addListener(updateValTipXPos)
let shownCounter = 0
let showValTip = () => {
if (++shownCounter == 1) {
valtip.classList.add('visible')
inputBounds = input.getBoundingClientRect()
valtip.style.top = (inputBounds.y - valtip.clientHeight + valtipYOffset) + 'px'
updateValTipXPos()
}
}
let hideValTip = () => {
if (--shownCounter == 0) {
valtip.classList.remove('visible')
}
}
input.addEventListener('pointerdown', showValTip)
input.addEventListener('pointerup', hideValTip)
let timer = null
input.addEventListener('input', ev => {
if (timer === null) {
showValTip()
} else {
clearTimeout(timer)
}
timer = setTimeout(() => {
timer = null
hideValTip()
}, 400)
})
})
}
initBindings() {
let b = this.bindings
// let updateTracking = fontSize => {
// if (!this.currEditable.explicitTracking) {
// var tracking = InterUIDynamicTracking(fontSize)
// this.isChangingBindings = true
// b.setValue('tracking', tracking)
// this.isChangingBindings = false
// }
// }
b.configure('tracking', 0, 'float', tracking => {
if (!this.isChangingBindings && !this.currEditable.explicitTracking) {
// console.log('enabled explicit tracking')
this.currEditable.setExplicitTracking(true)
this.setNeedsSaveValues()
}
})
b.setFormatter('tracking', v => v.toFixed(3))
b.configure('size', 0, 'float', size => {
let ed = this.currEditable
if (ed) {
setTimeout(() => {
// HERE BE DRAGONS! Feedback loop from Editable
if (!ed.explicitTracking) {
this.isChangingBindings = true
b.setValue('tracking', ed.values.tracking)
this.isChangingBindings = false
}
}, 10)
}
})
b.configure('lineHeight', 1, 'float')
b.bindAllInputs($$('.control input', this.ui))
b.bindAllInputs($$('.control select', this.ui))
$('.control input[data-binding="tracking"]').addEventListener("dblclick", ev => {
let ed = this.currEditable
setTimeout(() => {
ed.setExplicitTracking(false)
this.setNeedsSaveValues()
this.isChangingBindings = true
b.setValue('tracking', ed.values.tracking)
this.isChangingBindings = false
}, 50)
})
for (let binding of b.allBindings()) {
binding.addListener(() => this.bindingChanged(binding))
}
}
preloadFonts() {
// Note: This has no effect on systems supporting variable fonts.
[
"regular",
"italic",
"medium",
"medium-italic",
"semi-bold",
"semi-bold-italic",
"bold",
"bold-italic",
"extra-bold",
"extra-bold-italic",
"black",
"black-italic",
].forEach(style => {
let e = document.createElement('div')
e.className = 'font-preload font-style-' + style
e.innerText = 'a'
document.body.appendChild(e)
})
}
bindingChanged(binding) {
if (this.isChangingBindings) {
// Note: this.isChangingBindings is true when binding values are
// changed internally, in which case we do nothing here.
return
}
if (this.currEditable) {
this.currEditable.setValue(binding.name, binding.value)
}
this.setNeedsSaveValues()
}
reset() {
for (let ed of this.editables.values()) {
ed.resetValues()
}
this.updateBindingValues()
}
updateBindingValues() {
if (this.currEditable) {
this.isChangingBindings = true
this.bindings.setValues(this.currEditable.values)
this.isChangingBindings = false
}
}
saveValues() {
if (this._saveValuesTimer !== null) {
clearTimeout(this._saveValuesTimer)
this._saveValuesTimer = null
}
if (this.currEditable) {
this.currEditable.saveValues()
}
}
setNeedsSaveValues() {
if (this._saveValuesTimer !== null) {
clearTimeout(this._saveValuesTimer)
}
this._saveValuesTimer = setTimeout(() => this.saveValues(), 300)
}
setCurrEditable(ed) {
if (this._saveValuesTimer !== null &&
this.currEditable &&
!this.isChangingBindings)
{
this.saveValues()
}
this.currEditable = ed
this.updateBindingValues()
if (this.currEditable) {
this.showUI()
} else {
this.hideUI()
}
}
onEditableReceivedFocus(ed) {
// console.log(`onEditableReceivedFocus ${ed}`)
clearTimeout(this._deselectTimer)
this.setCurrEditable(ed)
}
onEditableLostFocus(ed) {
// console.log(`onEditableLostFocus ${ed}`)
// this.setCurrEditable(null)
if (supportsFocusTrick) {
this._deselectTimer = setTimeout(() => this.setCurrEditable(null), 10)
}
}
showUI() {
this.ui.classList.add('visible')
}
hideUI() {
this.ui.classList.remove('visible')
}
stopEditing() {
if (this.currEditable) {
this.currEditable.el.blur()
this.setCurrEditable(null)
}
}
addAllEditables() {
for (let el of $$('[data-ctxedit]')) {
this.addEditable(el)
}
}
addEditable(el) {
let key = this.keyPrefix + el.dataset.ctxedit
let existing = this.editables.get(key)
if (existing) {
throw new Error(`duplicate editable ${key}`)
}
let ed = new Editable(el, key)
this.editables.set(key, ed)
this.initEditable(ed)
// this.showUI() // XXX
}
initEditable(ed) {
// filter paste
ed.el.addEventListener('paste', ev => {
ev.preventDefault()
let text = ev.clipboardData.getData("text/plain")
document.execCommand("insertHTML", false, text)
}, {capture:true,passive:false})
ed.el.addEventListener('focus', ev => this.onEditableReceivedFocus(ed))
ed.el.addEventListener('blur', ev => this.onEditableLostFocus(ed))
}
}
return CtxEdit
})();

1
docs/res/dismiss.svg Executable file
View File

@ -0,0 +1 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 9l-.354.354.354.353.354-.353L8 9zm.354.354l5-5-.708-.708-5 5 .708.708zm0-.708l-5-5-.708.708 5 5 .708-.708z" fill="#fff"/><path stroke="#fff" d="M2 12.5h12"/></svg>

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

After

Width:  |  Height:  |  Size: 266 KiB

1
docs/res/popup.svg Executable file
View File

@ -0,0 +1 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M8 3.293l3.354 3.353-.708.708L8 4.707 5.354 7.354l-.708-.708L8 3.293zm0 8L5.354 8.646l-.708.708L8 12.707l3.354-3.353-.708-.708L8 11.293z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 64 KiB

1
docs/res/reset.svg Executable file
View File

@ -0,0 +1 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9.993.893L6.95 2.817l1.272.187A6 6 0 1 1 2 9h1a5 5 0 1 0 5.928-4.914l-.005.032-.79-.116A5.078 5.078 0 0 0 8 4v-.018L6.684 3.79l2.214 2.908-.796.606-3.287-4.319L9.459.047l.534.846z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 285 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 497 KiB

After

Width:  |  Height:  |  Size: 398 KiB

1
docs/res/settings.svg Executable file
View File

@ -0,0 +1 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M14 4H6V3h8v1zM4 4H2V3h2v1zm10 3H6V6h8v1zM4 7H2V6h2v1zm10 3H6V9h8v1zM4 10H2V9h2v1zm10 3H6v-1h8v1zM4 13H2v-1h2v1z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 257 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 171 KiB

View File

@ -1 +1 @@
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>font-size</title><desc>Created using Figma</desc><use xlink:href="#a" transform="translate(1.191 6.91)"/><use xlink:href="#b" transform="translate(7.307 3.273)"/><defs><path id="a" d="M1.054 5.09l.37-1.083h1.95l.37 1.084h1.051L2.918 0H1.877L0 5.09h1.054zm1.315-3.852h.06l.67 1.964h-1.4l.671-1.964z"/><path id="b" d="M1.108 8.727l.822-2.335h3.64l.822 2.335H7.5L4.295 0h-1.09L0 8.727h1.108zm2.59-7.346h.103l1.436 4.074H2.263L3.699 1.38z"/></defs></svg>
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2.245 12l.37-1.084h1.95L4.935 12h1.052L4.11 6.91H3.068L1.191 12h1.054zM3.56 8.147h.06l.671 1.964H2.89l.671-1.964zM8.415 12l.822-2.335h3.64L13.698 12h1.108l-3.205-8.727h-1.09L7.306 12h1.108zm2.59-7.347h.103l1.436 4.074H9.57l1.436-4.074z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 583 B

After

Width:  |  Height:  |  Size: 341 B

View File

@ -1 +1 @@
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>letter-spacing</title><desc>Created using Figma</desc><use xlink:href="#a" transform="translate(4.307 3.273)"/><use xlink:href="#b" transform="rotate(90 -.5 1.5)"/><use xlink:href="#b" transform="rotate(90 7 9)"/><defs><path id="a" d="M1.108 8.727l.822-2.335h3.64l.822 2.335H7.5L4.295 0h-1.09L0 8.727h1.108zm2.59-7.346h.103l1.436 4.074H2.263L3.699 1.38z"/><path id="b" fill-rule="evenodd" d="M12 1H0V0h12v1z"/></defs></svg>
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.415 12l.822-2.335h3.64L10.698 12h1.108L8.602 3.273h-1.09L4.306 12h1.108zm2.59-7.347h.103l1.436 4.074H6.57l1.436-4.074z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M0 14V2h1v12H0zm15 0V2h1v12h-1z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 556 B

After

Width:  |  Height:  |  Size: 321 B

View File

@ -0,0 +1 @@
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.297 12l.762-2.14h3.32L10.14 12h1.015L8.22 4h-1l-2.94 8h1.016zm1.066-3l1.324-3.734h.063L9.074 9h-2.71z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M15 2H1V1h14v1zm0 13H1v-1h14v1z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 304 B

View File

@ -1 +1 @@
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>style</title><desc>Created using Figma</desc><use xlink:href="#a" transform="rotate(90 -1 2)"/><use xlink:href="#b" transform="rotate(90 1 4)"/><use xlink:href="#c" transform="rotate(90 3.5 6.5)"/><use xlink:href="#d" transform="rotate(90 6.5 9.5)"/><defs><path id="a" fill-rule="evenodd" d="M10 1H0V0h10v1z"/><path id="b" fill-rule="evenodd" d="M10 2H0V0h10v2z"/><path id="c" fill-rule="evenodd" d="M10 3H0V0h10v3z"/><path id="d" fill-rule="evenodd" d="M10 4H0V0h10v4z"/></defs></svg>
<svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M0 13V3h1v10H0zm3 0V3h2v10H3zm4 0V3h3v10H7zm5 0V3h4v10h-4z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 618 B

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 KiB

After

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Some files were not shown because too many files have changed in this diff Show More