feat: use variable fonts with subsetting #2817
10
index.html
10
index.html
|
@ -9,13 +9,9 @@
|
|||
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<link rel="apple-touch-icon" href="/images/icons/apple-touch-icon-180x180.png"/>
|
||||
<link rel="preload" crossorigin="anonymous" href="/fonts/open-sans-v15-latin-700italic.woff2" as="font">
|
||||
<link rel="preload" crossorigin="anonymous" href="/fonts/open-sans-v15-latin-italic.woff2" as="font">
|
||||
<link rel="preload" crossorigin="anonymous" href="/fonts/quicksand-v7-latin-500.woff2" as="font">
|
||||
<link rel="preload" crossorigin="anonymous" href="/fonts/quicksand-v7-latin-700.woff2" as="font">
|
||||
<link rel="preload" crossorigin="anonymous" href="/fonts/open-sans-v15-latin-regular.woff2" as="font">
|
||||
<link rel="preload" crossorigin="anonymous" href="/fonts/open-sans-v15-latin-700.woff2" as="font">
|
||||
<link rel="preload" crossorigin="anonymous" href="/fonts/quicksand-v7-latin-regular.woff2" as="font">
|
||||
<link rel="preload" crossorigin="anonymous" href="/src/assets/fonts/OpenSans[wght].woff2" as="font">
|
||||
<link rel="preload" crossorigin="anonymous" href="/src/assets/fonts/OpenSans-Italic[wght].woff2" as="font">
|
||||
<link rel="preload" crossorigin="anonymous" href="/src/assets/fonts/Quicksand[wght].woff2" as="font">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -15,7 +15,10 @@
|
|||
"test:unit-watch": "vitest watch",
|
||||
"test:frontend": "cypress run",
|
||||
"typecheck": "vue-tsc --noEmit && vue-tsc --noEmit -p tsconfig.vitest.json --composite false",
|
||||
"browserslist:update": "npx browserslist@latest --update-db"
|
||||
"browserslist:update": "npx browserslist@latest --update-db",
|
||||
"fonts:update": "pnpm run fonts:download && pnpm run fonts:subset",
|
||||
"fonts:download": "./scripts/fonts-download.sh",
|
||||
"fonts:subset": "./scripts/fonts-subset.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "6.2.1",
|
||||
|
|
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.
|
@ -0,0 +1,56 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
#
|
||||
# This script downloads our original font files from their source repos
|
||||
# and puts them in our originalMedia folder.
|
||||
#
|
||||
|
||||
err_report() {
|
||||
echo "Error on line $(caller)" >&2
|
||||
}
|
||||
|
||||
trap err_report ERR
|
||||
|
||||
ORIGINAL_FONTS_DIR="./originalMedia/fonts"
|
||||
|
||||
# update these if there is a new version
|
||||
FONT_URLS=(
|
||||
"https://github.com/googlefonts/opensans/blob/27d060e1aad6886daeda67629ee28189f795f534/fonts/variable/OpenSans%5Bwdth%2Cwght%5D.ttf?raw=true"
|
||||
"https://github.com/googlefonts/opensans/blob/27d060e1aad6886daeda67629ee28189f795f534/fonts/variable/OpenSans-Italic%5Bwdth%2Cwght%5D.ttf?raw=true"
|
||||
"https://github.com/andrew-paglinawan/QuicksandFamily/blob/db6de44878582966f45a0debaef10d57108d93a7/fonts/Quicksand%5Bwght%5D.ttf?raw=true"
|
||||
)
|
||||
|
||||
|
||||
echo ""
|
||||
echo "###################################################"
|
||||
echo "# Download font files"
|
||||
echo "###################################################"
|
||||
echo ""
|
||||
|
||||
mkdir -p $ORIGINAL_FONTS_DIR
|
||||
|
||||
for URL in ${FONT_URLS[@]}; do
|
||||
wget -L $URL \
|
||||
--directory-prefix=$ORIGINAL_FONTS_DIR \
|
||||
--quiet \
|
||||
--timestamping \
|
||||
--show-progress
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "###################################################"
|
||||
echo "# Remove '?raw=true' filename suffix"
|
||||
echo "###################################################"
|
||||
echo ""
|
||||
|
||||
# Iterate over all files in directory with filetype ending in "?raw=true"
|
||||
for file in $ORIGINAL_FONTS_DIR/*?raw=true; do
|
||||
# Remove "?raw=true" from file name and store in variable
|
||||
new_name=$(echo $file | sed 's/?raw=true//')
|
||||
|
||||
# Overwrite existing file with new name
|
||||
mv -v $file $new_name
|
||||
done
|
||||
|
||||
echo "Renaming files complete"
|
|
@ -0,0 +1,161 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
#
|
||||
# This script subsets our variable fonts,
|
||||
# converts them to woff2 files and puts them in the
|
||||
# fonts folder.
|
||||
#
|
||||
# We do have to update the font paths in the @font-face
|
||||
# definitions manually since we use a checksum to make
|
||||
#
|
||||
# We use fonttools to create a partial instance of the
|
||||
# variable font where we keep only our needed features.
|
||||
# See more at:
|
||||
# https://fonttools.readthedocs.io/en/latest/varLib/instancer.html
|
||||
#
|
||||
# fonttools requires python > 3.7. For up-to-date
|
||||
# instructions see https://github.com/fonttools/fonttools#installation
|
||||
#
|
||||
# Lot's of info was gathered from:
|
||||
# https://markoskon.com/creating-font-subsets/
|
||||
# https://barrd.dev/article/create-a-variable-font-subset-for-smaller-file-size/
|
||||
#
|
||||
|
||||
ORIGINAL_FONTS="./originalMedia/fonts"
|
||||
TEMP_FOLDER="./.subset-fonts-temp"
|
||||
FONT_FOLDER="./src/assets/fonts"
|
||||
|
||||
err_report() {
|
||||
echo "Error on line $(caller)" >&2
|
||||
}
|
||||
|
||||
trap err_report ERR
|
||||
|
||||
mkdir -p $TEMP_FOLDER
|
||||
|
||||
# the latin subset that google uses on GoogleFonts
|
||||
# this is the same as the latin subset range that google uses on GoogleFonts
|
||||
# see for examle the unicode-range definition here:
|
||||
# https://fonts.googleapis.com/css2?family=Open+Sans
|
||||
UNICODE_LATIN_SUBSET="U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,\
|
||||
U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,\
|
||||
U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD"
|
||||
|
||||
get_filename_without_type() {
|
||||
filename=$1
|
||||
dirname=$(dirname $filename)
|
||||
# Extract the file type using parameter expansion
|
||||
filetype=${filename##*.}
|
||||
basename=$(basename $filename .$filetype)
|
||||
echo $basename
|
||||
}
|
||||
|
||||
# This function takes a font file and creates a subset of it using a specified set of unicode characters.
|
||||
instance_and_subset () {
|
||||
# Define default arguments for the subsetter.
|
||||
DEFAULT_SUBSETTER_ARGS="--layout-features=* --unicodes=${UNICODE_LATIN_SUBSET}"
|
||||
|
||||
# Assign function arguments to variables with more descriptive names.
|
||||
INPUT_FONT_FILE=$1
|
||||
INSTANCER_ARGS=$2
|
||||
OUTPUT_FONT_BASENAME=$3
|
||||
OUTPUT_FOLDER=$FONT_FOLDER
|
||||
|
||||
# If the output font basename is not provided, use the input font file's basename as the output font basename.
|
||||
if [ -z "$OUTPUT_FONT_BASENAME" ]; then
|
||||
INPUT_FONT_BASENAME=$(get_filename_without_type $INPUT_FONT_FILE)
|
||||
OUTPUT_FONT_BASENAME=$INPUT_FONT_BASENAME
|
||||
fi
|
||||
|
||||
# Use the default subsetter arguments if no custom arguments are provided.
|
||||
SUBSETTER_ARGS="${4:-$DEFAULT_SUBSETTER_ARGS}"
|
||||
|
||||
CHECKSUM=$(
|
||||
# Concatenate the contents of the input font file, the instancer arguments, and the subsetter arguments
|
||||
printf "%s%s" "$(cat $INPUT_FONT_FILE)" "$INSTANCER_ARGS" "$SUBSETTER_ARGS" |
|
||||
# Calculate the Blake2b checksum of the concatenated string
|
||||
b2sum |
|
||||
# Extract the checksum from the output of b2sum (it's the first field)
|
||||
awk '{print $1}'
|
||||
)
|
||||
|
||||
# Limit the checksum to 8 characters.
|
||||
CHECKSUM=$(echo "${CHECKSUM:0:8}")
|
||||
|
||||
# Construct the output font's filename
|
||||
OUTPUT_FONT_BASENAME="${OUTPUT_FONT_BASENAME}_${CHECKSUM}"
|
||||
OUTPUT_FONT_FILE="${OUTPUT_FOLDER}/${OUTPUT_FONT_BASENAME}.woff2"
|
||||
|
||||
# Check if the output font file already exists
|
||||
if test -f $OUTPUT_FONT_FILE; then
|
||||
echo "${OUTPUT_FONT_FILE} exists"
|
||||
return 0
|
||||
fi
|
||||
|
||||
FONT_INSTANCE="${TEMP_FOLDER}/${OUTPUT_FONT_BASENAME}.ttf"
|
||||
|
||||
if [ -n "$INSTANCER_ARGS" ]; then
|
||||
# If the INSTANCER_ARGS variable is set, use fonttools to create a font instance
|
||||
fonttools varLib.instancer --output $FONT_INSTANCE $INPUT_FONT_FILE $INSTANCER_ARGS
|
||||
else
|
||||
# Otherwise, just copy the input font file to the font instance file
|
||||
cp $INPUT_FONT_FILE $FONT_INSTANCE
|
||||
fi
|
||||
|
||||
# Use pyftsubset to create a subset of the font instance and save it to the output font file
|
||||
pyftsubset $FONT_INSTANCE --output-file=$OUTPUT_FONT_FILE --flavor=woff2 $SUBSETTER_ARGS
|
||||
|
||||
echo "${OUTPUT_FONT_BASENAME} subsetted."
|
||||
}
|
||||
|
||||
echo ""
|
||||
echo "###################################################"
|
||||
echo "# Install required libs"
|
||||
echo "###################################################"
|
||||
echo ""
|
||||
|
||||
pip install fonttools brotli
|
||||
|
||||
echo ""
|
||||
echo "###################################################"
|
||||
echo "# Create a partial instance of the variable font"
|
||||
echo "# where we keep only our needed features and then"
|
||||
echo "# subset fonts with latin unicode range and export"
|
||||
echo "# as woff2 file"
|
||||
echo "###################################################"
|
||||
echo ""
|
||||
|
||||
mkdir -p $TEMP_FOLDER
|
||||
|
||||
echo "\nOpen Sans"
|
||||
# we drop the wdth axis for all
|
||||
|
||||
instance_and_subset "${ORIGINAL_FONTS}/OpenSans[wdth,wght].ttf" "wdth=drop wght=400:700" "OpenSans[wght]"
|
||||
|
||||
# we restrict the wght range
|
||||
instance_and_subset "${ORIGINAL_FONTS}/OpenSans[wdth,wght].ttf" "wdth=drop wght=400" "OpenSans-Regular"
|
||||
instance_and_subset "${ORIGINAL_FONTS}/OpenSans[wdth,wght].ttf" "wdth=drop wght=700" "OpenSans-Bold"
|
||||
|
||||
echo "\nOpen Sans Italic"
|
||||
# we drop the wdth axis for all
|
||||
|
||||
instance_and_subset "${ORIGINAL_FONTS}/OpenSans-Italic[wdth,wght].ttf" "wdth=drop wght=400:700" "OpenSans-Italic[wght]"
|
||||
|
||||
# we restrict the wght range
|
||||
instance_and_subset "${ORIGINAL_FONTS}/OpenSans-Italic[wdth,wght].ttf" "wdth=drop wght=400" "OpenSans-RegularItalic"
|
||||
instance_and_subset "${ORIGINAL_FONTS}/OpenSans-Italic[wdth,wght].ttf" "wdth=drop wght=700" "OpenSans-BoldItalic"
|
||||
|
||||
echo "\nQuicksand"
|
||||
|
||||
instance_and_subset "${ORIGINAL_FONTS}/Quicksand[wght].ttf" "wght=400:700"
|
||||
|
||||
# we restrict the wght range
|
||||
instance_and_subset "${ORIGINAL_FONTS}/Quicksand[wght].ttf" "wght=400" "Quicksand-Regular"
|
||||
instance_and_subset "${ORIGINAL_FONTS}/Quicksand[wght].ttf" "wght=600" "Quicksand-SemiBold"
|
||||
instance_and_subset "${ORIGINAL_FONTS}/Quicksand[wght].ttf" "wght=700" "Quicksand-Bold"
|
||||
|
||||
echo "\nSubsetting files complete"
|
||||
|
||||
# remove temp folder
|
||||
rm -r $TEMP_FOLDER
|
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.
|
@ -435,7 +435,7 @@ $vikunja-nav-selected-width: 0.4rem;
|
|||
|
||||
.menu-list {
|
||||
li {
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
font-family: $vikunja-font;
|
||||
}
|
||||
|
||||
|
@ -460,7 +460,7 @@ $vikunja-nav-selected-width: 0.4rem;
|
|||
font-weight: bold;
|
||||
font-family: $vikunja-font;
|
||||
color: $vikunja-nav-color;
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
min-height: 2.5rem;
|
||||
padding-top: 0;
|
||||
padding-left: $navbar-padding;
|
||||
|
@ -479,6 +479,8 @@ $vikunja-nav-selected-width: 0.4rem;
|
|||
.count {
|
||||
color: var(--grey-500);
|
||||
margin-right: .5rem;
|
||||
// align brackets with number
|
||||
font-feature-settings: "case";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,5 +98,6 @@ function setSubscriptionInStore(sub: ISubscription) {
|
|||
<style scoped lang="scss">
|
||||
.dropdown-trigger {
|
||||
padding: 0.5rem;
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
|
@ -38,7 +38,7 @@
|
|||
<template v-for="(pt, i) in task.relatedTasks.parenttask">
|
||||
{{ pt.title }}<template v-if="(i + 1) < task.relatedTasks.parenttask.length">, </template>
|
||||
</template>
|
||||
>
|
||||
›
|
||||
</span>
|
||||
{{ task.title }}
|
||||
</span>
|
||||
|
@ -71,7 +71,7 @@
|
|||
class="is-italic"
|
||||
:aria-expanded="showDefer ? 'true' : 'false'"
|
||||
>
|
||||
- {{ $t('task.detail.due', {at: formatDateSince(task.dueDate)}) }}
|
||||
– {{ $t('task.detail.due', {at: formatDateSince(task.dueDate)}) }}
|
||||
</time>
|
||||
</BaseButton>
|
||||
<CustomTransition name="fade">
|
||||
|
|
|
@ -10,13 +10,14 @@
|
|||
// are defined here.
|
||||
//
|
||||
|
||||
$family-sans-serif: 'Open Sans', Helvetica, Arial, sans-serif;
|
||||
|
||||
// the default values get overwritten by the definitions above
|
||||
@import "bulma-css-variables/sass/utilities/_all";
|
||||
|
||||
// since $tablet is defined by bulma we can just define it after importing the utilities
|
||||
$mobile: math.div($tablet, 2);
|
||||
|
||||
$family-sans-serif: 'Open Sans', Helvetica, Arial, sans-serif;
|
||||
$vikunja-font: 'Quicksand', sans-serif;
|
||||
|
||||
$pagination-current-border: var(--primary);
|
||||
|
|
|
@ -1,65 +1,105 @@
|
|||
$font-files-path: '/fonts/';
|
||||
$font-files-path: '@/assets/fonts/';
|
||||
|
||||
// quicksand-regular - latin
|
||||
@font-face {
|
||||
font-family: 'Quicksand';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url($font-files-path + 'quicksand-v7-latin-regular.woff2') format('woff2');
|
||||
|
||||
// this is the same as the latin range that google uses.
|
||||
// see for examle the unicode-range definition here:
|
||||
// https://fonts.googleapis.com/css2?family=Open+Sans
|
||||
$unicode-range: "U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,\
|
||||
U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,\
|
||||
U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD";
|
||||
|
||||
@supports (font-variation-settings: normal) {
|
||||
@font-face {
|
||||
font-family: 'Quicksand';
|
||||
src: url($font-files-path + 'Quicksand[wght]_87bdcc7f.woff2') format('woff2-variations');
|
||||
src: url($font-files-path + 'Quicksand[wght]_87bdcc7f.woff2') format('woff2') tech('variations');
|
||||
font-style: normal;
|
||||
font-weight: 400 700;
|
||||
font-display: swap;
|
||||
unicode-range: $unicode-range;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url($font-files-path + 'OpenSans[wght]_54a65da5.woff2') format('woff2-variations');
|
||||
src: url($font-files-path + 'OpenSans[wght]_54a65da5.woff2') format('woff2') tech('variations');
|
||||
font-weight: 400 700;
|
||||
font-display: swap;
|
||||
unicode-range: $unicode-range;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url($font-files-path + 'OpenSans-Italic[wght]_c9a8fe68.woff2') format('woff2-variations');
|
||||
src: url($font-files-path + 'OpenSans-Italic[wght]_c9a8fe68.woff2') format('woff2') tech('variations');
|
||||
font-weight: 400 700;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
unicode-range: $unicode-range;
|
||||
}
|
||||
}
|
||||
|
||||
// quicksand-500 - latin
|
||||
@font-face {
|
||||
font-family: 'Quicksand';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url($font-files-path + 'quicksand-v7-latin-500.woff2') format('woff2');
|
||||
}
|
||||
/* Set up for old browsers */
|
||||
@supports not (font-variation-settings: normal) {
|
||||
@font-face {
|
||||
font-family: 'Quicksand';
|
||||
src: url($font-files-path + 'Quicksand-Regular_3e913e7e.woff2') format('woff2');
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
unicode-range: $unicode-range;
|
||||
}
|
||||
|
||||
// quicksand-700 - latin
|
||||
@font-face {
|
||||
font-family: 'Quicksand';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url($font-files-path + 'quicksand-v7-latin-700.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Quicksand';
|
||||
src: url($font-files-path + 'Quicksand-SemiBold_be48a442.woff2') format('woff2');
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
unicode-range: $unicode-range;
|
||||
}
|
||||
|
||||
// open-sans-regular - latin
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url($font-files-path + 'open-sans-v15-latin-regular.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Quicksand';
|
||||
src: url($font-files-path + 'Quicksand-Bold_20b26f76.woff2') format('woff2');
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
unicode-range: $unicode-range;
|
||||
}
|
||||
|
||||
// open-sans-italic - latin
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url($font-files-path + 'open-sans-v15-latin-italic.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url($font-files-path + 'OpenSans-Regular_d0acb717.woff2') format('woff2');
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
unicode-range: $unicode-range;
|
||||
}
|
||||
|
||||
// open-sans-700 - latin
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url($font-files-path + 'open-sans-v15-latin-700.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url($font-files-path + 'OpenSans-RegularItalic_48244a7a.woff2') format('woff2');
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
unicode-range: $unicode-range;
|
||||
}
|
||||
|
||||
// open-sans-700italic - latin
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url($font-files-path + 'open-sans-v15-latin-700italic.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url($font-files-path + 'OpenSans-Bold_eb52363b.woff2') format('woff2');
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
unicode-range: $unicode-range;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url($font-files-path + 'OpenSans-BoldItalic_3ff98862.woff2') format('woff2');
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
unicode-range: $unicode-range;
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
ref="heading"
|
||||
/>
|
||||
<h6 class="subtitle" v-if="parent && parent.namespace && parent.list">
|
||||
{{ getNamespaceTitle(parent.namespace) }} >
|
||||
{{ getNamespaceTitle(parent.namespace) }} ›
|
||||
<router-link :to="{ name: 'list.index', params: { listId: parent.list.id } }">
|
||||
{{ getListTitle(parent.list) }}
|
||||
</router-link>
|
||||
|
|
Loading…
Reference in New Issue