mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
🎉 Add multiple fonts to text editor WASM playground
This commit is contained in:
958
frontend/text-editor/src/fonts.css
Normal file
958
frontend/text-editor/src/fonts.css
Normal file
@@ -0,0 +1,958 @@
|
|||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTjWacfw6zH4dthXcyms1lPpC8I_b0juU057p-xEJZj11l4.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTjWacfw6zH4dthXcyms1lPpC8I_b0juU057p-xEJ9j11l4.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTjWacfw6zH4dthXcyms1lPpC8I_b0juU057p-xEJRj11l4.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTjWacfw6zH4dthXcyms1lPpC8I_b0juU057p-xEJVj11l4.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTjWacfw6zH4dthXcyms1lPpC8I_b0juU057p-xEJtj1w.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8dAYxJ8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8dAYxA8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8dAYxL8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8dAYxK8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8dAYxE8mQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p95AoxJ8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p95AoxA8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p95AoxL8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p95AoxK8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p95AoxE8mQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFThWacfw6zH4dthXcyms1lPpC8I_b0juU057pffIJl70w.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFThWacfw6zH4dthXcyms1lPpC8I_b0juU057pfWIJl70w.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFThWacfw6zH4dthXcyms1lPpC8I_b0juU057pfdIJl70w.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFThWacfw6zH4dthXcyms1lPpC8I_b0juU057pfcIJl70w.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFThWacfw6zH4dthXcyms1lPpC8I_b0juU057pfSIJk.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8hA4xJ8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8hA4xA8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8hA4xL8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8hA4xK8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8hA4xE8mQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8NBIxJ8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8NBIxA8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8NBIxL8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8NBIxK8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p8NBIxE8mQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p9pBYxJ8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p9pBYxA8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p9pBYxL8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p9pBYxK8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p9pBYxE8mQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p91BoxJ8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p91BoxA8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p91BoxL8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p91BoxK8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p91BoxE8mQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p9RB4xJ8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p9RB4xA8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p9RB4xL8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p9RB4xK8mRBkw.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTkWacfw6zH4dthXcyms1lPpC8I_b0juU057p9RB4xE8mQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFThWacfw6zH4dthXcyms1lPpC8I_b0juU0xiJffIJl70w.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFThWacfw6zH4dthXcyms1lPpC8I_b0juU0xiJfWIJl70w.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFThWacfw6zH4dthXcyms1lPpC8I_b0juU0xiJfdIJl70w.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFThWacfw6zH4dthXcyms1lPpC8I_b0juU0xiJfcIJl70w.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFThWacfw6zH4dthXcyms1lPpC8I_b0juU0xiJfSIJk.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xJIbFCrxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xJIbFA7xG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xJIbFCLxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xJIbFCbxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xJIbFB7xG.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xQIXFCrxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xQIXFA7xG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xQIXFCLxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xQIXFCbxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xQIXFB7xG.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTvWacfw6zH4dthXcyms1lPpC8I_b0juU055qfQOJ0.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTvWacfw6zH4dthXcyms1lPpC8I_b0juU0576fQOJ0.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTvWacfw6zH4dthXcyms1lPpC8I_b0juU055KfQOJ0.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTvWacfw6zH4dthXcyms1lPpC8I_b0juU055afQOJ0.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTvWacfw6zH4dthXcyms1lPpC8I_b0juU0566fQ.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xGITFCrxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xGITFA7xG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xGITFCLxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xGITFCbxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xGITFB7xG.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xNIPFCrxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xNIPFA7xG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xNIPFCLxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xNIPFCbxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xNIPFB7xG.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xUILFCrxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xUILFA7xG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xUILFCLxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xUILFCbxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xUILFB7xG.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xTIHFCrxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xTIHFA7xG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xTIHFCLxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xTIHFCbxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xTIHFB7xG.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xaIDFCrxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xaIDFA7xG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xaIDFCLxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xaIDFCbxG6mA.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'MontserratAlternates';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/montserratalternates/v17/mFTiWacfw6zH4dthXcyms1lPpC8I_b0juU0xaIDFB7xG.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Oswald';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/oswald/v56/TK3iWkUHHAIjg752FD8Ghe4.woff2) format('woff2');
|
||||||
|
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cyrillic */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Oswald';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/oswald/v56/TK3iWkUHHAIjg752HT8Ghe4.woff2) format('woff2');
|
||||||
|
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vietnamese */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Oswald';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/oswald/v56/TK3iWkUHHAIjg752Fj8Ghe4.woff2) format('woff2');
|
||||||
|
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin-ext */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Oswald';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/oswald/v56/TK3iWkUHHAIjg752Fz8Ghe4.woff2) format('woff2');
|
||||||
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Oswald';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/oswald/v56/TK3iWkUHHAIjg752GT8G.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fallback */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Playwrite MX Guides';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url(https://fonts.gstatic.com/s/playwritemxguides/v1/k3kMo9ESPe9dzQ1UGbvoZhnhbtfklWqN0qk.woff2) format('woff2');
|
||||||
|
}
|
||||||
@@ -2,225 +2,551 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/javascript.svg" />
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&family=Playwrite+ES:wght@100..400&family=Playwrite+NZ:wght@100..400&family=Playwrite+US+Trad:wght@100..400&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Penpot - Text Editor Playground</title>
|
<title>Penpot - Text Editor Playground</title>
|
||||||
<style>
|
|
||||||
#output {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<form>
|
<div class="playground">
|
||||||
<fieldset>
|
<form>
|
||||||
<legend>Styles</legend>
|
<fieldset>
|
||||||
<!-- Font -->
|
<legend>Styles</legend>
|
||||||
<div class="form-group">
|
<!-- Font -->
|
||||||
<label for="font-family">Font family</label>
|
<div class="form-group">
|
||||||
<select id="font-family">
|
<label for="font-family">Font family</label>
|
||||||
<option value="Open+Sans">Open Sans</option>
|
<select id="font-family">
|
||||||
<option value="sourcesanspro">Source Sans Pro</option>
|
<option value="Open+Sans">Open Sans</option>
|
||||||
<option value="whatever">Whatever</option>
|
<option value="sourcesanspro">Source Sans Pro</option>
|
||||||
</select>
|
<option value="whatever">Whatever</option>
|
||||||
</div>
|
</select>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="font-size">Font size</label>
|
<div class="form-group">
|
||||||
<input id="font-size" type="number" value="14" />
|
<label for="font-size">Font size</label>
|
||||||
</div>
|
<input id="font-size" type="number" value="14" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="font-weight">Font weight</label>
|
<div class="form-group">
|
||||||
<select id="font-weight">
|
<label for="font-weight">Font weight</label>
|
||||||
<option value="100">100</option>
|
<select id="font-weight">
|
||||||
<option value="200">200</option>
|
<option value="100">100</option>
|
||||||
<option value="300">300</option>
|
<option value="200">200</option>
|
||||||
<option value="400">400 (normal)</option>
|
<option value="300">300</option>
|
||||||
<option value="500">500</option>
|
<option value="400">400 (normal)</option>
|
||||||
<option value="600">600</option>
|
<option value="500">500</option>
|
||||||
<option value="700">700 (bold)</option>
|
<option value="600">600</option>
|
||||||
<option value="800">800</option>
|
<option value="700">700 (bold)</option>
|
||||||
<option value="900">900</option>
|
<option value="800">800</option>
|
||||||
</select>
|
<option value="900">900</option>
|
||||||
</div>
|
</select>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="font-style">Font style</label>
|
<div class="form-group">
|
||||||
<select id="font-style">
|
<label for="font-style">Font style</label>
|
||||||
<option value="normal">normal</option>
|
<select id="font-style">
|
||||||
<option value="italic">italic</option>
|
<option value="normal">normal</option>
|
||||||
<option value="oblique">oblique</option>
|
<option value="italic">italic</option>
|
||||||
</select>
|
<option value="oblique">oblique</option>
|
||||||
</div>
|
</select>
|
||||||
<!-- Text attributes -->
|
</div>
|
||||||
<div class="form-group">
|
<!-- Text attributes -->
|
||||||
<label for="line-height">Line height</label>
|
<div class="form-group">
|
||||||
<input id="line-height" type="number" value="1.0" />
|
<label for="line-height">Line height</label>
|
||||||
</div>
|
<input id="line-height" type="number" value="1.0" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="letter-spacing">Letter spacing</label>
|
<div class="form-group">
|
||||||
<input id="letter-spacing" type="number" value="0.0" />
|
<label for="letter-spacing">Letter spacing</label>
|
||||||
</div>
|
<input id="letter-spacing" type="number" value="0.0" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="direction-ltr">LTR</label>
|
<div class="form-group">
|
||||||
<input id="direction-ltr" type="radio" name="direction" value="ltr" checked />
|
<label for="direction-ltr">LTR</label>
|
||||||
</div>
|
<input id="direction-ltr" type="radio" name="direction" value="ltr" checked />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="direction-rtl">RTL</label>
|
<div class="form-group">
|
||||||
<input id="direction-rtl" type="radio" name="direction" value="rtl" />
|
<label for="direction-rtl">RTL</label>
|
||||||
</div>
|
<input id="direction-rtl" type="radio" name="direction" value="rtl" />
|
||||||
<!-- Text Align -->
|
</div>
|
||||||
<div class="form-group">
|
<!-- Text Align -->
|
||||||
<label for="text-align-left">Align left</label>
|
<div class="form-group">
|
||||||
<input id="text-align-left" type="radio" name="text-align" value="left" checked />
|
<label for="text-align-left">Align left</label>
|
||||||
</div>
|
<input id="text-align-left" type="radio" name="text-align" value="left" checked />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="text-align-center">Align center</label>
|
<div class="form-group">
|
||||||
<input id="text-align-center" type="radio" name="text-align" value="center" />
|
<label for="text-align-center">Align center</label>
|
||||||
</div>
|
<input id="text-align-center" type="radio" name="text-align" value="center" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="text-align-right">Align right</label>
|
<div class="form-group">
|
||||||
<input id="text-align-right" type="radio" name="text-align" value="right" />
|
<label for="text-align-right">Align right</label>
|
||||||
</div>
|
<input id="text-align-right" type="radio" name="text-align" value="right" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="text-align-justify">Align justify</label>
|
<div class="form-group">
|
||||||
<input id="text-align-justify" type="radio" name="text-align" value="justify" />
|
<label for="text-align-justify">Align justify</label>
|
||||||
</div>
|
<input id="text-align-justify" type="radio" name="text-align" value="justify" />
|
||||||
<!-- Text Transform -->
|
</div>
|
||||||
<div class="form-group">
|
<!-- Text Transform -->
|
||||||
<label for="text-transform-none">None</label>
|
<div class="form-group">
|
||||||
<input id="text-transform-none" type="radio" name="text-transform" value="none" checked />
|
<label for="text-transform-none">None</label>
|
||||||
</div>
|
<input id="text-transform-none" type="radio" name="text-transform" value="none" checked />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="text-transform-uppercase">Uppercase</label>
|
<div class="form-group">
|
||||||
<input id="text-transform-uppercase" type="radio" name="text-transform" value="uppercase" checked />
|
<label for="text-transform-uppercase">Uppercase</label>
|
||||||
</div>
|
<input id="text-transform-uppercase" type="radio" name="text-transform" value="uppercase" checked />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="text-transform-capitalize">Capitalize</label>
|
<div class="form-group">
|
||||||
<input id="text-transform-capitalize" type="radio" name="text-transform" value="capitalize" />
|
<label for="text-transform-capitalize">Capitalize</label>
|
||||||
</div>
|
<input id="text-transform-capitalize" type="radio" name="text-transform" value="capitalize" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="text-transform-lowercase">Lowercase</label>
|
<div class="form-group">
|
||||||
<input id="text-transform-lowercase" type="radio" name="text-transform" value="lowercase" />
|
<label for="text-transform-lowercase">Lowercase</label>
|
||||||
</div>
|
<input id="text-transform-lowercase" type="radio" name="text-transform" value="lowercase" />
|
||||||
</fieldset>
|
</div>
|
||||||
<fieldset>
|
</fieldset>
|
||||||
<legend>Debug</legend>
|
<fieldset>
|
||||||
<div class="form-group">
|
<legend>Debug</legend>
|
||||||
<label for="direction">Direction</label>
|
<div class="form-group">
|
||||||
<input id="direction" readonly type="text" />
|
<label for="direction">Direction</label>
|
||||||
</div>
|
<input id="direction" readonly type="text" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="focus-node">Focus Node</label>
|
<div class="form-group">
|
||||||
<input id="focus-node" readonly type="text" />
|
<label for="focus-node">Focus Node</label>
|
||||||
</div>
|
<input id="focus-node" readonly type="text" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="focus-offset">Focus offset</label>
|
<div class="form-group">
|
||||||
<input id="focus-offset" readonly type="number">
|
<label for="focus-offset">Focus offset</label>
|
||||||
</div>
|
<input id="focus-offset" readonly type="number">
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="focus-inline">Focus Inline</label>
|
<div class="form-group">
|
||||||
<input id="focus-inline" readonly type="text" />
|
<label for="focus-inline">Focus Inline</label>
|
||||||
</div>
|
<input id="focus-inline" readonly type="text" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="focus-paragraph">Focus Paragraph</label>
|
<div class="form-group">
|
||||||
<input id="focus-paragraph" readonly type="text" />
|
<label for="focus-paragraph">Focus Paragraph</label>
|
||||||
</div>
|
<input id="focus-paragraph" readonly type="text" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="anchor-node">Anchor Node</label>
|
<div class="form-group">
|
||||||
<input id="anchor-node" readonly type="text" />
|
<label for="anchor-node">Anchor Node</label>
|
||||||
</div>
|
<input id="anchor-node" readonly type="text" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="anchor-offset">Anchor offset</label>
|
<div class="form-group">
|
||||||
<input id="anchor-offset" readonly type="number">
|
<label for="anchor-offset">Anchor offset</label>
|
||||||
</div>
|
<input id="anchor-offset" readonly type="number">
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="anchor-inline">Anchor Inline</label>
|
<div class="form-group">
|
||||||
<input id="anchor-inline" readonly type="text" />
|
<label for="anchor-inline">Anchor Inline</label>
|
||||||
</div>
|
<input id="anchor-inline" readonly type="text" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="anchor-paragraph">Anchor Paragraph</label>
|
<div class="form-group">
|
||||||
<input id="anchor-paragraph" readonly type="text" />
|
<label for="anchor-paragraph">Anchor Paragraph</label>
|
||||||
</div>
|
<input id="anchor-paragraph" readonly type="text" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="start-container">Start container</label>
|
<div class="form-group">
|
||||||
<input id="start-container" readonly type="text" />
|
<label for="start-container">Start container</label>
|
||||||
</div>
|
<input id="start-container" readonly type="text" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="start-offset">Start offset</label>
|
<div class="form-group">
|
||||||
<input id="start-offset" readonly type="text" />
|
<label for="start-offset">Start offset</label>
|
||||||
</div>
|
<input id="start-offset" readonly type="text" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="end-container">End container</label>
|
<div class="form-group">
|
||||||
<input id="end-container" readonly type="text" />
|
<label for="end-container">End container</label>
|
||||||
</div>
|
<input id="end-container" readonly type="text" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="end-offset">End offset</label>
|
<div class="form-group">
|
||||||
<input id="end-offset" readonly type="text" />
|
<label for="end-offset">End offset</label>
|
||||||
</div>
|
<input id="end-offset" readonly type="text" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="multi">Multi?</label>
|
<div class="form-group">
|
||||||
<input id="multi" readonly type="checkbox" />
|
<label for="multi">Multi?</label>
|
||||||
</div>
|
<input id="multi" readonly type="checkbox" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="multi-inline">Multi inline?</label>
|
<div class="form-group">
|
||||||
<input id="multi-inline" readonly type="checkbox" />
|
<label for="multi-inline">Multi inline?</label>
|
||||||
</div>
|
<input id="multi-inline" readonly type="checkbox" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="multi-paragraph">Multi paragraph?</label>
|
<div class="form-group">
|
||||||
<input id="multi-paragraph" readonly type="checkbox" />
|
<label for="multi-paragraph">Multi paragraph?</label>
|
||||||
</div>
|
<input id="multi-paragraph" readonly type="checkbox" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="is-text-focus">Is text focus?</label>
|
<div class="form-group">
|
||||||
<input id="is-text-focus" readonly type="checkbox" />
|
<label for="is-text-focus">Is text focus?</label>
|
||||||
</div>
|
<input id="is-text-focus" readonly type="checkbox" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="is-text-anchor">Is text anchor?</label>
|
<div class="form-group">
|
||||||
<input id="is-text-anchor" readonly type="checkbox" />
|
<label for="is-text-anchor">Is text anchor?</label>
|
||||||
</div>
|
<input id="is-text-anchor" readonly type="checkbox" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="is-paragraph-start">Is paragraph start?</label>
|
<div class="form-group">
|
||||||
<input id="is-paragraph-start" readonly type="checkbox" />
|
<label for="is-paragraph-start">Is paragraph start?</label>
|
||||||
</div>
|
<input id="is-paragraph-start" readonly type="checkbox" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="is-paragraph-end">Is paragraph end?</label>
|
<div class="form-group">
|
||||||
<input id="is-paragraph-end" readonly type="checkbox" />
|
<label for="is-paragraph-end">Is paragraph end?</label>
|
||||||
</div>
|
<input id="is-paragraph-end" readonly type="checkbox" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="is-inline-start">Is inline start?</label>
|
<div class="form-group">
|
||||||
<input id="is-inline-start" readonly type="checkbox" />
|
<label for="is-inline-start">Is inline start?</label>
|
||||||
</div>
|
<input id="is-inline-start" readonly type="checkbox" />
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label for="is-inline-end">Is inline end?</label>
|
<div class="form-group">
|
||||||
<input id="is-inline-end" readonly type="checkbox">
|
<label for="is-inline-end">Is inline end?</label>
|
||||||
</div>
|
<input id="is-inline-end" readonly type="checkbox">
|
||||||
</fieldset>
|
</div>
|
||||||
</form>
|
</fieldset>
|
||||||
<!--
|
</form>
|
||||||
|
<!--
|
||||||
|
|
||||||
Editor
|
Editor
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<div class="text-editor-container align-top">
|
<div class="text-editor-container align-top">
|
||||||
<div
|
<div
|
||||||
id="text-editor-selection-imposter"
|
id="text-editor-selection-imposter"
|
||||||
class="text-editor-selection-imposter"></div>
|
class="text-editor-selection-imposter"></div>
|
||||||
<div
|
<div
|
||||||
class="text-editor-content"
|
class="text-editor-content"
|
||||||
contenteditable="true"
|
contenteditable="true"
|
||||||
role="textbox"
|
role="textbox"
|
||||||
aria-multiline="true"
|
aria-multiline="true"
|
||||||
aria-autocomplete="none"
|
aria-autocomplete="none"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
autocapitalize="false"></div>
|
autocapitalize="false"></div>
|
||||||
|
</div>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
Text output
|
||||||
|
|
||||||
|
-->
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
</div>
|
</div>
|
||||||
<!--
|
<script type="module">
|
||||||
|
import "./style.css";
|
||||||
|
import "./fonts.css";
|
||||||
|
import "./editor/TextEditor.css";
|
||||||
|
import { TextEditor } from "./editor/TextEditor";
|
||||||
|
import { SelectionControllerDebug } from "./editor/debug/SelectionControllerDebug";
|
||||||
|
import initWasmModule from './wasm/render_wasm.js';
|
||||||
|
import {
|
||||||
|
init, assignCanvas, render, setupInteraction, useShape, setShapeChildren, addTextShape, updateTextShape, hexToU32ARGB,getRandomInt, getRandomColor, getRandomFloat, addShapeSolidFill, addShapeSolidStrokeFill, storeFonts
|
||||||
|
} from './wasm/lib.js';
|
||||||
|
|
||||||
Text output
|
async function loadFontList() {
|
||||||
|
const response = await fetch('fonts/fonts.txt')
|
||||||
|
const text = await response.text()
|
||||||
|
const fonts = text.split('\n').filter(l => !!l)
|
||||||
|
return fonts
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFontStyleWeight(fontStyleName) {
|
||||||
|
if (fontStyleName.startsWith('Thin')) {
|
||||||
|
return 100
|
||||||
|
} else if (fontStyleName.startsWith('ExtraLight')) {
|
||||||
|
return 200
|
||||||
|
} else if (fontStyleName.startsWith('Light')) {
|
||||||
|
return 300
|
||||||
|
} else if (fontStyleName.startsWith('Regular')) {
|
||||||
|
return 400
|
||||||
|
} else if (fontStyleName.startsWith('Medium')) {
|
||||||
|
return 500
|
||||||
|
} else if (fontStyleName.startsWith('SemiBold')) {
|
||||||
|
return 600
|
||||||
|
} else if (fontStyleName.startsWith('Bold')) {
|
||||||
|
return 700
|
||||||
|
} else if (fontStyleName.startsWith('ExtraBold')) {
|
||||||
|
return 800
|
||||||
|
} else if (fontStyleName.startsWith('Black')) {
|
||||||
|
return 900
|
||||||
|
} else {
|
||||||
|
return 400
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadFonts() {
|
||||||
|
const fontData = new Map()
|
||||||
|
const fonts = await loadFontList()
|
||||||
|
for (const font of fonts) {
|
||||||
|
const response = await fetch(`fonts/${font}`)
|
||||||
|
const arrayBuffer = await response.arrayBuffer()
|
||||||
|
const [fontName, fontStyleNameAndExtension] = font.split('-')
|
||||||
|
const [fontStyleName, extension] = fontStyleNameAndExtension.split('.')
|
||||||
|
if (!fontData.has(fontName)) {
|
||||||
|
fontData.set(fontName, [])
|
||||||
|
}
|
||||||
|
const id = crypto.randomUUID()
|
||||||
|
const weight = getFontStyleWeight(fontStyleName)
|
||||||
|
const isItalic = (fontStyleName.endsWith('Italic'))
|
||||||
|
const currentFontData = fontData.get(fontName)
|
||||||
|
currentFontData.push({
|
||||||
|
id,
|
||||||
|
url: `fonts/${font}`,
|
||||||
|
name: fontName,
|
||||||
|
weight: weight,
|
||||||
|
style: isItalic ? 'italic' : 'normal',
|
||||||
|
arrayBuffer,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return fontData
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchParams = new URLSearchParams(location.search);
|
||||||
|
const debug = searchParams.has("debug")
|
||||||
|
? searchParams.get("debug").split(",")
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const textEditorSelectionImposterElement = document.getElementById(
|
||||||
|
"text-editor-selection-imposter",
|
||||||
|
);
|
||||||
|
|
||||||
|
const textEditorElement = document.querySelector(".text-editor-content");
|
||||||
|
const textEditor = new TextEditor(textEditorElement, {
|
||||||
|
styleDefaults: {
|
||||||
|
"font-family": "MontserratAlternates",
|
||||||
|
"font-size": "14",
|
||||||
|
"font-weight": "500",
|
||||||
|
"font-style": "normal",
|
||||||
|
"line-height": "1.2",
|
||||||
|
"letter-spacing": "0",
|
||||||
|
direction: "ltr",
|
||||||
|
"text-align": "left",
|
||||||
|
"text-transform": "none",
|
||||||
|
"text-decoration": "none",
|
||||||
|
"--typography-ref-id": '["~#\'",null]',
|
||||||
|
"--typography-ref-file": '["~#\'",null]',
|
||||||
|
"--font-id": '["~#\'","MontserratAlternates"]',
|
||||||
|
"--fills": '[["^ ","~:fill-color","#000000","~:fill-opacity",1]]',
|
||||||
|
},
|
||||||
|
selectionImposterElement: textEditorSelectionImposterElement,
|
||||||
|
debug: new SelectionControllerDebug({
|
||||||
|
direction: document.getElementById("direction"),
|
||||||
|
multiElement: document.getElementById("multi"),
|
||||||
|
multiInlineElement: document.getElementById("multi-inline"),
|
||||||
|
multiParagraphElement: document.getElementById("multi-paragraph"),
|
||||||
|
isParagraphStart: document.getElementById("is-paragraph-start"),
|
||||||
|
isParagraphEnd: document.getElementById("is-paragraph-end"),
|
||||||
|
isInlineStart: document.getElementById("is-inline-start"),
|
||||||
|
isInlineEnd: document.getElementById("is-inline-end"),
|
||||||
|
isTextAnchor: document.getElementById("is-text-anchor"),
|
||||||
|
isTextFocus: document.getElementById("is-text-focus"),
|
||||||
|
focusNode: document.getElementById("focus-node"),
|
||||||
|
focusOffset: document.getElementById("focus-offset"),
|
||||||
|
focusInline: document.getElementById("focus-inline"),
|
||||||
|
focusParagraph: document.getElementById("focus-paragraph"),
|
||||||
|
anchorNode: document.getElementById("anchor-node"),
|
||||||
|
anchorOffset: document.getElementById("anchor-offset"),
|
||||||
|
anchorInline: document.getElementById("anchor-inline"),
|
||||||
|
anchorParagraph: document.getElementById("anchor-paragraph"),
|
||||||
|
startContainer: document.getElementById("start-container"),
|
||||||
|
startOffset: document.getElementById("start-offset"),
|
||||||
|
endContainer: document.getElementById("end-container"),
|
||||||
|
endOffset: document.getElementById("end-offset"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const fontFamilyElement = document.getElementById("font-family");
|
||||||
|
const fontSizeElement = document.getElementById("font-size");
|
||||||
|
const fontWeightElement = document.getElementById("font-weight");
|
||||||
|
const fontStyleElement = document.getElementById("font-style");
|
||||||
|
|
||||||
|
const directionLTRElement = document.getElementById("direction-ltr");
|
||||||
|
const directionRTLElement = document.getElementById("direction-rtl");
|
||||||
|
|
||||||
|
const lineHeightElement = document.getElementById("line-height");
|
||||||
|
const letterSpacingElement = document.getElementById("letter-spacing");
|
||||||
|
|
||||||
|
const textAlignLeftElement = document.getElementById("text-align-left");
|
||||||
|
const textAlignCenterElement = document.getElementById("text-align-center");
|
||||||
|
const textAlignRightElement = document.getElementById("text-align-right");
|
||||||
|
const textAlignJustifyElement = document.getElementById("text-align-justify");
|
||||||
|
|
||||||
|
const fonts = await loadFonts()
|
||||||
|
console.log(fonts)
|
||||||
|
const fontFamiliesFragment = document.createDocumentFragment()
|
||||||
|
for (const [font, fontData] of fonts) {
|
||||||
|
const fontFamilyOptionElement = document.createElement('option')
|
||||||
|
fontFamilyOptionElement.value = font
|
||||||
|
fontFamilyOptionElement.textContent = font
|
||||||
|
fontFamiliesFragment.appendChild(fontFamilyOptionElement)
|
||||||
|
}
|
||||||
|
fontFamilyElement.replaceChildren(fontFamiliesFragment)
|
||||||
|
|
||||||
|
function onDirectionChange(e) {
|
||||||
|
if (debug.includes("events")) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
if (e.target.checked) {
|
||||||
|
textEditor.applyStylesToSelection({
|
||||||
|
direction: e.target.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
directionLTRElement.addEventListener("change", onDirectionChange);
|
||||||
|
directionRTLElement.addEventListener("change", onDirectionChange);
|
||||||
|
|
||||||
|
function onTextAlignChange(e) {
|
||||||
|
if (debug.includes("events")) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
if (e.target.checked) {
|
||||||
|
textEditor.applyStylesToSelection({
|
||||||
|
"text-align": e.target.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textAlignLeftElement.addEventListener("change", onTextAlignChange);
|
||||||
|
textAlignCenterElement.addEventListener("change", onTextAlignChange);
|
||||||
|
textAlignRightElement.addEventListener("change", onTextAlignChange);
|
||||||
|
textAlignJustifyElement.addEventListener("change", onTextAlignChange);
|
||||||
|
|
||||||
|
fontFamilyElement.addEventListener("change", (e) => {
|
||||||
|
if (debug.includes("events")) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
const fontStyles = fonts.get(e.target.value)
|
||||||
|
console.log('fontStyles', fontStyles)
|
||||||
|
textEditor.applyStylesToSelection({
|
||||||
|
"font-family": e.target.value,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
fontWeightElement.addEventListener("change", (e) => {
|
||||||
|
if (debug.includes("events")) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
textEditor.applyStylesToSelection({
|
||||||
|
"font-weight": e.target.value,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
fontSizeElement.addEventListener("change", (e) => {
|
||||||
|
if (debug.includes("events")) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
textEditor.applyStylesToSelection({
|
||||||
|
"font-size": e.target.value,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
lineHeightElement.addEventListener("change", (e) => {
|
||||||
|
if (debug.includes("events")) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
textEditor.applyStylesToSelection({
|
||||||
|
"line-height": e.target.value,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
letterSpacingElement.addEventListener("change", (e) => {
|
||||||
|
if (debug.includes("events")) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
textEditor.applyStylesToSelection({
|
||||||
|
"letter-spacing": e.target.value,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
fontStyleElement.addEventListener("change", (e) => {
|
||||||
|
if (debug.includes("events")) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
textEditor.applyStylesToSelection({
|
||||||
|
"font-style": e.target.value,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function formatHTML(html, options) {
|
||||||
|
const spaces = options?.spaces ?? 4;
|
||||||
|
let indent = 0;
|
||||||
|
return html.replace(/<\/?(.*?)>/g, (fullMatch) => {
|
||||||
|
let str = fullMatch + "\n";
|
||||||
|
if (fullMatch.startsWith("</")) {
|
||||||
|
--indent;
|
||||||
|
str = " ".repeat(indent * spaces) + str;
|
||||||
|
} else {
|
||||||
|
str = " ".repeat(indent * spaces) + str;
|
||||||
|
++indent;
|
||||||
|
if (fullMatch === "<br>") --indent;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fontSize = 14;
|
||||||
|
const children = [];
|
||||||
|
const uuid = crypto.randomUUID();
|
||||||
|
children.push(uuid);
|
||||||
|
const outputElement = document.getElementById("output");
|
||||||
|
textEditorElement.addEventListener("input", (e) => {
|
||||||
|
if (debug.includes("events")) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
outputElement.textContent = formatHTML(textEditor.element.innerHTML);
|
||||||
|
});
|
||||||
|
|
||||||
|
textEditor.addEventListener("needslayout", (e) => {
|
||||||
|
useShape(uuid);
|
||||||
|
updateTextShape(textEditor.root, fonts);
|
||||||
|
render();
|
||||||
|
})
|
||||||
|
|
||||||
|
textEditor.addEventListener("stylechange", (e) => {
|
||||||
|
if (debug.includes("events")) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
const fontSize = parseInt(e.detail.getPropertyValue("font-size"), 10);
|
||||||
|
const fontWeight = e.detail.getPropertyValue("font-weight");
|
||||||
|
const fontStyle = e.detail.getPropertyValue("font-style");
|
||||||
|
const fontFamily = e.detail.getPropertyValue("font-family");
|
||||||
|
|
||||||
|
fontFamilyElement.value = fontFamily;
|
||||||
|
fontSizeElement.value = fontSize;
|
||||||
|
fontStyleElement.value = fontStyle;
|
||||||
|
fontWeightElement.value = fontWeight;
|
||||||
|
|
||||||
|
const textAlign = e.detail.getPropertyValue("text-align");
|
||||||
|
textAlignLeftElement.checked = textAlign === "left";
|
||||||
|
textAlignCenterElement.checked = textAlign === "center";
|
||||||
|
textAlignRightElement.checked = textAlign === "right";
|
||||||
|
textAlignJustifyElement.checked = textAlign === "justify";
|
||||||
|
|
||||||
|
const direction = e.detail.getPropertyValue("direction");
|
||||||
|
directionLTRElement.checked = direction === "ltr";
|
||||||
|
directionRTLElement.checked = direction === "rtl";
|
||||||
|
});
|
||||||
|
|
||||||
|
const canvas = document.getElementById("canvas");
|
||||||
|
canvas.width = window.innerWidth;
|
||||||
|
canvas.height = window.innerHeight;
|
||||||
|
|
||||||
|
const MIN_LINES = 1;
|
||||||
|
const MAX_LINES = 5;
|
||||||
|
const MIN_WORDS = 1;
|
||||||
|
const MAX_WORDS = 10;
|
||||||
|
|
||||||
|
initWasmModule().then(Module => {
|
||||||
|
init(Module);
|
||||||
|
assignCanvas(canvas);
|
||||||
|
Module._set_canvas_background(hexToU32ARGB("#FABADA", 1));
|
||||||
|
Module._set_view(1, 0, 0);
|
||||||
|
Module._init_shapes_pool(1);
|
||||||
|
setupInteraction(canvas);
|
||||||
|
|
||||||
|
storeFonts(fonts)
|
||||||
|
|
||||||
|
useShape(uuid);
|
||||||
|
Module._set_parent(0, 0, 0, 0);
|
||||||
|
Module._set_shape_type(5);
|
||||||
|
|
||||||
|
const x1 = 0;
|
||||||
|
const y1 = 0;
|
||||||
|
const width = canvas.width;
|
||||||
|
const height = canvas.height;
|
||||||
|
Module._set_shape_selrect(x1, y1, x1 + width, y1 + height);
|
||||||
|
|
||||||
|
addTextShape("", fonts);
|
||||||
|
|
||||||
|
useShape("00000000-0000-0000-0000-000000000000");
|
||||||
|
setShapeChildren(children);
|
||||||
|
render()
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
-->
|
|
||||||
<div id="output"></div>
|
|
||||||
<script type="module" src="/main.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,216 +0,0 @@
|
|||||||
/**
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
*
|
|
||||||
* Copyright (c) KALEIDOS INC
|
|
||||||
*/
|
|
||||||
|
|
||||||
import "./style.css";
|
|
||||||
import "./editor/TextEditor.css";
|
|
||||||
import { TextEditor } from "./editor/TextEditor";
|
|
||||||
import { SelectionControllerDebug } from "./editor/debug/SelectionControllerDebug";
|
|
||||||
|
|
||||||
const searchParams = new URLSearchParams(location.search);
|
|
||||||
const debug = searchParams.has("debug")
|
|
||||||
? searchParams.get("debug").split(",")
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const textEditorSelectionImposterElement = document.getElementById(
|
|
||||||
"text-editor-selection-imposter",
|
|
||||||
);
|
|
||||||
|
|
||||||
const textEditorElement = document.querySelector(".text-editor-content");
|
|
||||||
const textEditor = new TextEditor(textEditorElement, {
|
|
||||||
styleDefaults: {
|
|
||||||
"font-family": "sourcesanspro",
|
|
||||||
"font-size": "14",
|
|
||||||
"font-weight": "500",
|
|
||||||
"font-style": "normal",
|
|
||||||
"line-height": "1.2",
|
|
||||||
"letter-spacing": "0",
|
|
||||||
direction: "ltr",
|
|
||||||
"text-align": "left",
|
|
||||||
"text-transform": "none",
|
|
||||||
"text-decoration": "none",
|
|
||||||
"--typography-ref-id": '["~#\'",null]',
|
|
||||||
"--typography-ref-file": '["~#\'",null]',
|
|
||||||
"--font-id": '["~#\'","sourcesanspro"]',
|
|
||||||
"--fills": '[["^ ","~:fill-color","#000000","~:fill-opacity",1]]',
|
|
||||||
},
|
|
||||||
selectionImposterElement: textEditorSelectionImposterElement,
|
|
||||||
debug: new SelectionControllerDebug({
|
|
||||||
direction: document.getElementById("direction"),
|
|
||||||
multiElement: document.getElementById("multi"),
|
|
||||||
multiInlineElement: document.getElementById("multi-inline"),
|
|
||||||
multiParagraphElement: document.getElementById("multi-paragraph"),
|
|
||||||
isParagraphStart: document.getElementById("is-paragraph-start"),
|
|
||||||
isParagraphEnd: document.getElementById("is-paragraph-end"),
|
|
||||||
isInlineStart: document.getElementById("is-inline-start"),
|
|
||||||
isInlineEnd: document.getElementById("is-inline-end"),
|
|
||||||
isTextAnchor: document.getElementById("is-text-anchor"),
|
|
||||||
isTextFocus: document.getElementById("is-text-focus"),
|
|
||||||
focusNode: document.getElementById("focus-node"),
|
|
||||||
focusOffset: document.getElementById("focus-offset"),
|
|
||||||
focusInline: document.getElementById("focus-inline"),
|
|
||||||
focusParagraph: document.getElementById("focus-paragraph"),
|
|
||||||
anchorNode: document.getElementById("anchor-node"),
|
|
||||||
anchorOffset: document.getElementById("anchor-offset"),
|
|
||||||
anchorInline: document.getElementById("anchor-inline"),
|
|
||||||
anchorParagraph: document.getElementById("anchor-paragraph"),
|
|
||||||
startContainer: document.getElementById("start-container"),
|
|
||||||
startOffset: document.getElementById("start-offset"),
|
|
||||||
endContainer: document.getElementById("end-container"),
|
|
||||||
endOffset: document.getElementById("end-offset"),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const fontFamilyElement = document.getElementById("font-family");
|
|
||||||
const fontSizeElement = document.getElementById("font-size");
|
|
||||||
const fontWeightElement = document.getElementById("font-weight");
|
|
||||||
const fontStyleElement = document.getElementById("font-style");
|
|
||||||
|
|
||||||
const directionLTRElement = document.getElementById("direction-ltr");
|
|
||||||
const directionRTLElement = document.getElementById("direction-rtl");
|
|
||||||
|
|
||||||
const lineHeightElement = document.getElementById("line-height");
|
|
||||||
const letterSpacingElement = document.getElementById("letter-spacing");
|
|
||||||
|
|
||||||
const textAlignLeftElement = document.getElementById("text-align-left");
|
|
||||||
const textAlignCenterElement = document.getElementById("text-align-center");
|
|
||||||
const textAlignRightElement = document.getElementById("text-align-right");
|
|
||||||
const textAlignJustifyElement = document.getElementById("text-align-justify");
|
|
||||||
|
|
||||||
function onDirectionChange(e) {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
if (e.target.checked) {
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
direction: e.target.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
directionLTRElement.addEventListener("change", onDirectionChange);
|
|
||||||
directionRTLElement.addEventListener("change", onDirectionChange);
|
|
||||||
|
|
||||||
function onTextAlignChange(e) {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
if (e.target.checked) {
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
"text-align": e.target.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
textAlignLeftElement.addEventListener("change", onTextAlignChange);
|
|
||||||
textAlignCenterElement.addEventListener("change", onTextAlignChange);
|
|
||||||
textAlignRightElement.addEventListener("change", onTextAlignChange);
|
|
||||||
textAlignJustifyElement.addEventListener("change", onTextAlignChange);
|
|
||||||
|
|
||||||
fontFamilyElement.addEventListener("change", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
"font-family": e.target.value,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
fontWeightElement.addEventListener("change", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
"font-weight": e.target.value,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
fontSizeElement.addEventListener("change", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
"font-size": e.target.value,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
lineHeightElement.addEventListener("change", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
"line-height": e.target.value,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
letterSpacingElement.addEventListener("change", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
"letter-spacing": e.target.value,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
fontStyleElement.addEventListener("change", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
"font-style": e.target.value,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function formatHTML(html, options) {
|
|
||||||
const spaces = options?.spaces ?? 4;
|
|
||||||
let indent = 0;
|
|
||||||
return html.replace(/<\/?(.*?)>/g, (fullMatch) => {
|
|
||||||
let str = fullMatch + "\n";
|
|
||||||
if (fullMatch.startsWith("</")) {
|
|
||||||
--indent;
|
|
||||||
str = " ".repeat(indent * spaces) + str;
|
|
||||||
} else {
|
|
||||||
str = " ".repeat(indent * spaces) + str;
|
|
||||||
++indent;
|
|
||||||
if (fullMatch === "<br>") --indent;
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const outputElement = document.getElementById("output");
|
|
||||||
textEditorElement.addEventListener("input", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
outputElement.textContent = formatHTML(textEditor.element.innerHTML);
|
|
||||||
});
|
|
||||||
|
|
||||||
textEditor.addEventListener("stylechange", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
const fontSize = parseInt(e.detail.getPropertyValue("font-size"), 10);
|
|
||||||
const fontWeight = e.detail.getPropertyValue("font-weight");
|
|
||||||
const fontStyle = e.detail.getPropertyValue("font-style");
|
|
||||||
const fontFamily = e.detail.getPropertyValue("font-family");
|
|
||||||
|
|
||||||
fontFamilyElement.value = fontFamily;
|
|
||||||
fontSizeElement.value = fontSize;
|
|
||||||
fontStyleElement.value = fontStyle;
|
|
||||||
fontWeightElement.value = fontWeight;
|
|
||||||
|
|
||||||
const textAlign = e.detail.getPropertyValue("text-align");
|
|
||||||
textAlignLeftElement.checked = textAlign === "left";
|
|
||||||
textAlignCenterElement.checked = textAlign === "center";
|
|
||||||
textAlignRightElement.checked = textAlign === "right";
|
|
||||||
textAlignJustifyElement.checked = textAlign === "justify";
|
|
||||||
|
|
||||||
const direction = e.detail.getPropertyValue("direction");
|
|
||||||
directionLTRElement.checked = direction === "ltr";
|
|
||||||
directionRTLElement.checked = direction === "rtl";
|
|
||||||
});
|
|
||||||
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.
Binary file not shown.
BIN
frontend/text-editor/src/public/fonts/Oswald-Bold.ttf
Normal file
BIN
frontend/text-editor/src/public/fonts/Oswald-Bold.ttf
Normal file
Binary file not shown.
BIN
frontend/text-editor/src/public/fonts/Oswald-ExtraLight.ttf
Normal file
BIN
frontend/text-editor/src/public/fonts/Oswald-ExtraLight.ttf
Normal file
Binary file not shown.
BIN
frontend/text-editor/src/public/fonts/Oswald-Light.ttf
Normal file
BIN
frontend/text-editor/src/public/fonts/Oswald-Light.ttf
Normal file
Binary file not shown.
BIN
frontend/text-editor/src/public/fonts/Oswald-Medium.ttf
Normal file
BIN
frontend/text-editor/src/public/fonts/Oswald-Medium.ttf
Normal file
Binary file not shown.
BIN
frontend/text-editor/src/public/fonts/Oswald-Regular.ttf
Normal file
BIN
frontend/text-editor/src/public/fonts/Oswald-Regular.ttf
Normal file
Binary file not shown.
BIN
frontend/text-editor/src/public/fonts/Oswald-SemiBold.ttf
Normal file
BIN
frontend/text-editor/src/public/fonts/Oswald-SemiBold.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
26
frontend/text-editor/src/public/fonts/fonts.txt
Normal file
26
frontend/text-editor/src/public/fonts/fonts.txt
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
MontserratAlternates-BlackItalic.ttf
|
||||||
|
MontserratAlternates-Black.ttf
|
||||||
|
MontserratAlternates-BoldItalic.ttf
|
||||||
|
MontserratAlternates-Bold.ttf
|
||||||
|
MontserratAlternates-ExtraBoldItalic.ttf
|
||||||
|
MontserratAlternates-ExtraBold.ttf
|
||||||
|
MontserratAlternates-ExtraLightItalic.ttf
|
||||||
|
MontserratAlternates-ExtraLight.ttf
|
||||||
|
MontserratAlternates-Italic.ttf
|
||||||
|
MontserratAlternates-LightItalic.ttf
|
||||||
|
MontserratAlternates-Light.ttf
|
||||||
|
MontserratAlternates-MediumItalic.ttf
|
||||||
|
MontserratAlternates-Medium.ttf
|
||||||
|
MontserratAlternates-Regular.ttf
|
||||||
|
MontserratAlternates-SemiBoldItalic.ttf
|
||||||
|
MontserratAlternates-SemiBold.ttf
|
||||||
|
MontserratAlternates-ThinItalic.ttf
|
||||||
|
MontserratAlternates-Thin.ttf
|
||||||
|
Oswald-Bold.ttf
|
||||||
|
Oswald-ExtraLight.ttf
|
||||||
|
Oswald-Light.ttf
|
||||||
|
Oswald-Medium.ttf
|
||||||
|
Oswald-Regular.ttf
|
||||||
|
Oswald-SemiBold.ttf
|
||||||
|
Oswald-VariableFont_wght.ttf
|
||||||
|
PlaywriteMXGuides-Regular.ttf
|
||||||
|
Before Width: | Height: | Size: 995 B After Width: | Height: | Size: 995 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -1,482 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&family=Playwrite+ES:wght@100..400&family=Playwrite+NZ:wght@100..400&family=Playwrite+US+Trad:wght@100..400&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Penpot - Text Editor Playground</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="playground">
|
|
||||||
<form>
|
|
||||||
<fieldset>
|
|
||||||
<legend>Styles</legend>
|
|
||||||
<!-- Font -->
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="font-family">Font family</label>
|
|
||||||
<select id="font-family">
|
|
||||||
<option value="Open+Sans">Open Sans</option>
|
|
||||||
<option value="sourcesanspro">Source Sans Pro</option>
|
|
||||||
<option value="whatever">Whatever</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="font-size">Font size</label>
|
|
||||||
<input id="font-size" type="number" value="14" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="font-weight">Font weight</label>
|
|
||||||
<select id="font-weight">
|
|
||||||
<option value="100">100</option>
|
|
||||||
<option value="200">200</option>
|
|
||||||
<option value="300">300</option>
|
|
||||||
<option value="400">400 (normal)</option>
|
|
||||||
<option value="500">500</option>
|
|
||||||
<option value="600">600</option>
|
|
||||||
<option value="700">700 (bold)</option>
|
|
||||||
<option value="800">800</option>
|
|
||||||
<option value="900">900</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="font-style">Font style</label>
|
|
||||||
<select id="font-style">
|
|
||||||
<option value="normal">normal</option>
|
|
||||||
<option value="italic">italic</option>
|
|
||||||
<option value="oblique">oblique</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<!-- Text attributes -->
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="line-height">Line height</label>
|
|
||||||
<input id="line-height" type="number" value="1.0" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="letter-spacing">Letter spacing</label>
|
|
||||||
<input id="letter-spacing" type="number" value="0.0" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="direction-ltr">LTR</label>
|
|
||||||
<input id="direction-ltr" type="radio" name="direction" value="ltr" checked />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="direction-rtl">RTL</label>
|
|
||||||
<input id="direction-rtl" type="radio" name="direction" value="rtl" />
|
|
||||||
</div>
|
|
||||||
<!-- Text Align -->
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="text-align-left">Align left</label>
|
|
||||||
<input id="text-align-left" type="radio" name="text-align" value="left" checked />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="text-align-center">Align center</label>
|
|
||||||
<input id="text-align-center" type="radio" name="text-align" value="center" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="text-align-right">Align right</label>
|
|
||||||
<input id="text-align-right" type="radio" name="text-align" value="right" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="text-align-justify">Align justify</label>
|
|
||||||
<input id="text-align-justify" type="radio" name="text-align" value="justify" />
|
|
||||||
</div>
|
|
||||||
<!-- Text Transform -->
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="text-transform-none">None</label>
|
|
||||||
<input id="text-transform-none" type="radio" name="text-transform" value="none" checked />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="text-transform-uppercase">Uppercase</label>
|
|
||||||
<input id="text-transform-uppercase" type="radio" name="text-transform" value="uppercase" checked />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="text-transform-capitalize">Capitalize</label>
|
|
||||||
<input id="text-transform-capitalize" type="radio" name="text-transform" value="capitalize" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="text-transform-lowercase">Lowercase</label>
|
|
||||||
<input id="text-transform-lowercase" type="radio" name="text-transform" value="lowercase" />
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<fieldset>
|
|
||||||
<legend>Debug</legend>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="direction">Direction</label>
|
|
||||||
<input id="direction" readonly type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="focus-node">Focus Node</label>
|
|
||||||
<input id="focus-node" readonly type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="focus-offset">Focus offset</label>
|
|
||||||
<input id="focus-offset" readonly type="number">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="focus-inline">Focus Inline</label>
|
|
||||||
<input id="focus-inline" readonly type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="focus-paragraph">Focus Paragraph</label>
|
|
||||||
<input id="focus-paragraph" readonly type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="anchor-node">Anchor Node</label>
|
|
||||||
<input id="anchor-node" readonly type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="anchor-offset">Anchor offset</label>
|
|
||||||
<input id="anchor-offset" readonly type="number">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="anchor-inline">Anchor Inline</label>
|
|
||||||
<input id="anchor-inline" readonly type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="anchor-paragraph">Anchor Paragraph</label>
|
|
||||||
<input id="anchor-paragraph" readonly type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="start-container">Start container</label>
|
|
||||||
<input id="start-container" readonly type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="start-offset">Start offset</label>
|
|
||||||
<input id="start-offset" readonly type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="end-container">End container</label>
|
|
||||||
<input id="end-container" readonly type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="end-offset">End offset</label>
|
|
||||||
<input id="end-offset" readonly type="text" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="multi">Multi?</label>
|
|
||||||
<input id="multi" readonly type="checkbox" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="multi-inline">Multi inline?</label>
|
|
||||||
<input id="multi-inline" readonly type="checkbox" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="multi-paragraph">Multi paragraph?</label>
|
|
||||||
<input id="multi-paragraph" readonly type="checkbox" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="is-text-focus">Is text focus?</label>
|
|
||||||
<input id="is-text-focus" readonly type="checkbox" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="is-text-anchor">Is text anchor?</label>
|
|
||||||
<input id="is-text-anchor" readonly type="checkbox" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="is-paragraph-start">Is paragraph start?</label>
|
|
||||||
<input id="is-paragraph-start" readonly type="checkbox" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="is-paragraph-end">Is paragraph end?</label>
|
|
||||||
<input id="is-paragraph-end" readonly type="checkbox" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="is-inline-start">Is inline start?</label>
|
|
||||||
<input id="is-inline-start" readonly type="checkbox" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="is-inline-end">Is inline end?</label>
|
|
||||||
<input id="is-inline-end" readonly type="checkbox">
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</form>
|
|
||||||
<!--
|
|
||||||
|
|
||||||
Editor
|
|
||||||
|
|
||||||
-->
|
|
||||||
<div class="text-editor-container align-top">
|
|
||||||
<div
|
|
||||||
id="text-editor-selection-imposter"
|
|
||||||
class="text-editor-selection-imposter"></div>
|
|
||||||
<div
|
|
||||||
class="text-editor-content"
|
|
||||||
contenteditable="true"
|
|
||||||
role="textbox"
|
|
||||||
aria-multiline="true"
|
|
||||||
aria-autocomplete="none"
|
|
||||||
spellcheck="false"
|
|
||||||
autocapitalize="false"></div>
|
|
||||||
</div>
|
|
||||||
<!--
|
|
||||||
|
|
||||||
Text output
|
|
||||||
|
|
||||||
-->
|
|
||||||
<canvas id="canvas"></canvas>
|
|
||||||
</div>
|
|
||||||
<script type="module">
|
|
||||||
import "./style.css";
|
|
||||||
import "./editor/TextEditor.css";
|
|
||||||
import { TextEditor } from "./editor/TextEditor";
|
|
||||||
import { SelectionControllerDebug } from "./editor/debug/SelectionControllerDebug";
|
|
||||||
import initWasmModule from './wasm/render_wasm.js';
|
|
||||||
import {
|
|
||||||
init, assignCanvas, render, setupInteraction, useShape, setShapeChildren, addTextShape, updateTextShape, hexToU32ARGB,getRandomInt, getRandomColor, getRandomFloat, addShapeSolidFill, addShapeSolidStrokeFill
|
|
||||||
} from './wasm/lib.js';
|
|
||||||
|
|
||||||
const searchParams = new URLSearchParams(location.search);
|
|
||||||
const debug = searchParams.has("debug")
|
|
||||||
? searchParams.get("debug").split(",")
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const textEditorSelectionImposterElement = document.getElementById(
|
|
||||||
"text-editor-selection-imposter",
|
|
||||||
);
|
|
||||||
|
|
||||||
const textEditorElement = document.querySelector(".text-editor-content");
|
|
||||||
const textEditor = new TextEditor(textEditorElement, {
|
|
||||||
styleDefaults: {
|
|
||||||
"font-family": "sourcesanspro",
|
|
||||||
"font-size": "14",
|
|
||||||
"font-weight": "500",
|
|
||||||
"font-style": "normal",
|
|
||||||
"line-height": "1.2",
|
|
||||||
"letter-spacing": "0",
|
|
||||||
direction: "ltr",
|
|
||||||
"text-align": "left",
|
|
||||||
"text-transform": "none",
|
|
||||||
"text-decoration": "none",
|
|
||||||
"--typography-ref-id": '["~#\'",null]',
|
|
||||||
"--typography-ref-file": '["~#\'",null]',
|
|
||||||
"--font-id": '["~#\'","sourcesanspro"]',
|
|
||||||
"--fills": '[["^ ","~:fill-color","#000000","~:fill-opacity",1]]',
|
|
||||||
},
|
|
||||||
selectionImposterElement: textEditorSelectionImposterElement,
|
|
||||||
debug: new SelectionControllerDebug({
|
|
||||||
direction: document.getElementById("direction"),
|
|
||||||
multiElement: document.getElementById("multi"),
|
|
||||||
multiInlineElement: document.getElementById("multi-inline"),
|
|
||||||
multiParagraphElement: document.getElementById("multi-paragraph"),
|
|
||||||
isParagraphStart: document.getElementById("is-paragraph-start"),
|
|
||||||
isParagraphEnd: document.getElementById("is-paragraph-end"),
|
|
||||||
isInlineStart: document.getElementById("is-inline-start"),
|
|
||||||
isInlineEnd: document.getElementById("is-inline-end"),
|
|
||||||
isTextAnchor: document.getElementById("is-text-anchor"),
|
|
||||||
isTextFocus: document.getElementById("is-text-focus"),
|
|
||||||
focusNode: document.getElementById("focus-node"),
|
|
||||||
focusOffset: document.getElementById("focus-offset"),
|
|
||||||
focusInline: document.getElementById("focus-inline"),
|
|
||||||
focusParagraph: document.getElementById("focus-paragraph"),
|
|
||||||
anchorNode: document.getElementById("anchor-node"),
|
|
||||||
anchorOffset: document.getElementById("anchor-offset"),
|
|
||||||
anchorInline: document.getElementById("anchor-inline"),
|
|
||||||
anchorParagraph: document.getElementById("anchor-paragraph"),
|
|
||||||
startContainer: document.getElementById("start-container"),
|
|
||||||
startOffset: document.getElementById("start-offset"),
|
|
||||||
endContainer: document.getElementById("end-container"),
|
|
||||||
endOffset: document.getElementById("end-offset"),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const fontFamilyElement = document.getElementById("font-family");
|
|
||||||
const fontSizeElement = document.getElementById("font-size");
|
|
||||||
const fontWeightElement = document.getElementById("font-weight");
|
|
||||||
const fontStyleElement = document.getElementById("font-style");
|
|
||||||
|
|
||||||
const directionLTRElement = document.getElementById("direction-ltr");
|
|
||||||
const directionRTLElement = document.getElementById("direction-rtl");
|
|
||||||
|
|
||||||
const lineHeightElement = document.getElementById("line-height");
|
|
||||||
const letterSpacingElement = document.getElementById("letter-spacing");
|
|
||||||
|
|
||||||
const textAlignLeftElement = document.getElementById("text-align-left");
|
|
||||||
const textAlignCenterElement = document.getElementById("text-align-center");
|
|
||||||
const textAlignRightElement = document.getElementById("text-align-right");
|
|
||||||
const textAlignJustifyElement = document.getElementById("text-align-justify");
|
|
||||||
|
|
||||||
function onDirectionChange(e) {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
if (e.target.checked) {
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
direction: e.target.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
directionLTRElement.addEventListener("change", onDirectionChange);
|
|
||||||
directionRTLElement.addEventListener("change", onDirectionChange);
|
|
||||||
|
|
||||||
function onTextAlignChange(e) {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
if (e.target.checked) {
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
"text-align": e.target.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
textAlignLeftElement.addEventListener("change", onTextAlignChange);
|
|
||||||
textAlignCenterElement.addEventListener("change", onTextAlignChange);
|
|
||||||
textAlignRightElement.addEventListener("change", onTextAlignChange);
|
|
||||||
textAlignJustifyElement.addEventListener("change", onTextAlignChange);
|
|
||||||
|
|
||||||
fontFamilyElement.addEventListener("change", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
"font-family": e.target.value,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
fontWeightElement.addEventListener("change", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
"font-weight": e.target.value,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
fontSizeElement.addEventListener("change", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
"font-size": e.target.value,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
lineHeightElement.addEventListener("change", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
"line-height": e.target.value,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
letterSpacingElement.addEventListener("change", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
"letter-spacing": e.target.value,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
fontStyleElement.addEventListener("change", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
textEditor.applyStylesToSelection({
|
|
||||||
"font-style": e.target.value,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function formatHTML(html, options) {
|
|
||||||
const spaces = options?.spaces ?? 4;
|
|
||||||
let indent = 0;
|
|
||||||
return html.replace(/<\/?(.*?)>/g, (fullMatch) => {
|
|
||||||
let str = fullMatch + "\n";
|
|
||||||
if (fullMatch.startsWith("</")) {
|
|
||||||
--indent;
|
|
||||||
str = " ".repeat(indent * spaces) + str;
|
|
||||||
} else {
|
|
||||||
str = " ".repeat(indent * spaces) + str;
|
|
||||||
++indent;
|
|
||||||
if (fullMatch === "<br>") --indent;
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const fontSize = 14;
|
|
||||||
const children = [];
|
|
||||||
const uuid = crypto.randomUUID();
|
|
||||||
children.push(uuid);
|
|
||||||
const outputElement = document.getElementById("output");
|
|
||||||
textEditorElement.addEventListener("input", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
outputElement.textContent = formatHTML(textEditor.element.innerHTML);
|
|
||||||
});
|
|
||||||
|
|
||||||
textEditor.addEventListener("needslayout", (e) => {
|
|
||||||
useShape(uuid);
|
|
||||||
updateTextShape(fontSize, textEditor.root);
|
|
||||||
render();
|
|
||||||
})
|
|
||||||
|
|
||||||
textEditor.addEventListener("stylechange", (e) => {
|
|
||||||
if (debug.includes("events")) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
const fontSize = parseInt(e.detail.getPropertyValue("font-size"), 10);
|
|
||||||
const fontWeight = e.detail.getPropertyValue("font-weight");
|
|
||||||
const fontStyle = e.detail.getPropertyValue("font-style");
|
|
||||||
const fontFamily = e.detail.getPropertyValue("font-family");
|
|
||||||
|
|
||||||
fontFamilyElement.value = fontFamily;
|
|
||||||
fontSizeElement.value = fontSize;
|
|
||||||
fontStyleElement.value = fontStyle;
|
|
||||||
fontWeightElement.value = fontWeight;
|
|
||||||
|
|
||||||
const textAlign = e.detail.getPropertyValue("text-align");
|
|
||||||
textAlignLeftElement.checked = textAlign === "left";
|
|
||||||
textAlignCenterElement.checked = textAlign === "center";
|
|
||||||
textAlignRightElement.checked = textAlign === "right";
|
|
||||||
textAlignJustifyElement.checked = textAlign === "justify";
|
|
||||||
|
|
||||||
const direction = e.detail.getPropertyValue("direction");
|
|
||||||
directionLTRElement.checked = direction === "ltr";
|
|
||||||
directionRTLElement.checked = direction === "rtl";
|
|
||||||
});
|
|
||||||
|
|
||||||
const canvas = document.getElementById("canvas");
|
|
||||||
canvas.width = window.innerWidth;
|
|
||||||
canvas.height = window.innerHeight;
|
|
||||||
|
|
||||||
const MIN_LINES = 1;
|
|
||||||
const MAX_LINES = 5;
|
|
||||||
const MIN_WORDS = 1;
|
|
||||||
const MAX_WORDS = 10;
|
|
||||||
|
|
||||||
initWasmModule().then(Module => {
|
|
||||||
init(Module);
|
|
||||||
assignCanvas(canvas);
|
|
||||||
Module._set_canvas_background(hexToU32ARGB("#FABADA", 1));
|
|
||||||
Module._set_view(1, 0, 0);
|
|
||||||
Module._init_shapes_pool(1);
|
|
||||||
setupInteraction(canvas);
|
|
||||||
|
|
||||||
|
|
||||||
useShape(uuid);
|
|
||||||
Module._set_parent(0, 0, 0, 0);
|
|
||||||
Module._set_shape_type(5);
|
|
||||||
|
|
||||||
const x1 = 0;
|
|
||||||
const y1 = 0;
|
|
||||||
const width = canvas.width;
|
|
||||||
const height = canvas.height;
|
|
||||||
Module._set_shape_selrect(x1, y1, x1 + width, y1 + height);
|
|
||||||
|
|
||||||
addTextShape(fontSize, "");
|
|
||||||
|
|
||||||
useShape("00000000-0000-0000-0000-000000000000");
|
|
||||||
setShapeChildren(children);
|
|
||||||
render()
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -182,7 +182,6 @@ export function set_parent(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function render() {
|
export function render() {
|
||||||
console.log('render')
|
|
||||||
Module._set_view(1, 0, 0);
|
Module._set_view(1, 0, 0);
|
||||||
Module._render_from_cache();
|
Module._render_from_cache();
|
||||||
debouncedRender();
|
debouncedRender();
|
||||||
@@ -284,9 +283,11 @@ function getFontStyle(fontStyle) {
|
|||||||
switch (fontStyle) {
|
switch (fontStyle) {
|
||||||
default:
|
default:
|
||||||
case 'normal':
|
case 'normal':
|
||||||
|
case 'regular':
|
||||||
|
return 0;
|
||||||
case 'oblique':
|
case 'oblique':
|
||||||
case 'italic':
|
case 'italic':
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,6 +317,7 @@ function setParagraphData(dview, { numLeaves, textAlign, textDirection, textDeco
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setLeafData(dview, leafOffset, {
|
function setLeafData(dview, leafOffset, {
|
||||||
|
fontId,
|
||||||
fontStyle,
|
fontStyle,
|
||||||
fontSize,
|
fontSize,
|
||||||
fontWeight,
|
fontWeight,
|
||||||
@@ -331,10 +333,10 @@ function setLeafData(dview, leafOffset, {
|
|||||||
dview.setFloat32(leafOffset + 4, fontSize, true); // font-size
|
dview.setFloat32(leafOffset + 4, fontSize, true); // font-size
|
||||||
dview.setFloat32(leafOffset + 8, letterSpacing, true); // letter-spacing
|
dview.setFloat32(leafOffset + 8, letterSpacing, true); // letter-spacing
|
||||||
dview.setInt32(leafOffset + 12, fontWeight, true); // font-weight: normal
|
dview.setInt32(leafOffset + 12, fontWeight, true); // font-weight: normal
|
||||||
dview.setUint32(leafOffset + 16, 0, true); // font-id (UUID part 1)
|
dview.setUint32(leafOffset + 16, fontId[0], true); // font-id (UUID part 1)
|
||||||
dview.setUint32(leafOffset + 20, 0, true); // font-id (UUID part 2)
|
dview.setUint32(leafOffset + 20, fontId[1], true); // font-id (UUID part 2)
|
||||||
dview.setUint32(leafOffset + 24, 0, true); // font-id (UUID part 3)
|
dview.setUint32(leafOffset + 24, fontId[2], true); // font-id (UUID part 3)
|
||||||
dview.setUint32(leafOffset + 28, 0, true); // font-id (UUID part 4)
|
dview.setUint32(leafOffset + 28, fontId[3], true); // font-id (UUID part 4)
|
||||||
dview.setUint32(leafOffset + 32, 0, true); // font-family hash
|
dview.setUint32(leafOffset + 32, 0, true); // font-family hash
|
||||||
dview.setUint32(leafOffset + 36, 0, true); // font-variant-id (UUID part 1)
|
dview.setUint32(leafOffset + 36, 0, true); // font-variant-id (UUID part 1)
|
||||||
dview.setUint32(leafOffset + 40, 0, true); // font-variant-id (UUID part 2)
|
dview.setUint32(leafOffset + 40, 0, true); // font-variant-id (UUID part 2)
|
||||||
@@ -344,7 +346,15 @@ function setLeafData(dview, leafOffset, {
|
|||||||
dview.setUint32(leafOffset + 56, totalFills, true); // total fills count
|
dview.setUint32(leafOffset + 56, totalFills, true); // total fills count
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateTextShape(fontSize, root) {
|
function getFontFrom(fontFamily, fontWeight, fontStyle, fonts) {
|
||||||
|
const fontList = fonts.get(fontFamily)
|
||||||
|
if (!fontList) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return fontList.find(fontData => fontData.weight === fontWeight && fontStyle === fontData.style)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateTextShape(root, fonts) {
|
||||||
// Calculate fills
|
// Calculate fills
|
||||||
const fills = [
|
const fills = [
|
||||||
{
|
{
|
||||||
@@ -358,7 +368,6 @@ export function updateTextShape(fontSize, root) {
|
|||||||
const totalFillsSize = totalFills * FILL_SIZE;
|
const totalFillsSize = totalFills * FILL_SIZE;
|
||||||
|
|
||||||
const paragraphs = root.children;
|
const paragraphs = root.children;
|
||||||
console.log("paragraphs", paragraphs.length);
|
|
||||||
|
|
||||||
Module._clear_shape_text();
|
Module._clear_shape_text();
|
||||||
for (const paragraph of paragraphs) {
|
for (const paragraph of paragraphs) {
|
||||||
@@ -366,19 +375,16 @@ export function updateTextShape(fontSize, root) {
|
|||||||
|
|
||||||
const leaves = paragraph.children;
|
const leaves = paragraph.children;
|
||||||
const numLeaves = leaves.length;
|
const numLeaves = leaves.length;
|
||||||
console.log("leaves", numLeaves);
|
|
||||||
|
|
||||||
for (const leaf of leaves) {
|
for (const leaf of leaves) {
|
||||||
const text = leaf.textContent;
|
const text = leaf.textContent;
|
||||||
const textBuffer = new TextEncoder().encode(text);
|
const textBuffer = new TextEncoder().encode(text);
|
||||||
const textSize = textBuffer.byteLength;
|
const textSize = textBuffer.byteLength;
|
||||||
console.log("text", text, textSize);
|
|
||||||
totalSize += LEAF_ATTR_SIZE + totalFillsSize;
|
totalSize += LEAF_ATTR_SIZE + totalFillsSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalSize += paragraph.textContent.length;
|
totalSize += paragraph.textContent.length;
|
||||||
|
|
||||||
console.log("Total Size", totalSize);
|
|
||||||
// Allocate buffer
|
// Allocate buffer
|
||||||
const bufferPtr = allocBytes(totalSize);
|
const bufferPtr = allocBytes(totalSize);
|
||||||
const heap = new Uint8Array(Module.HEAPU8.buffer, bufferPtr, totalSize);
|
const heap = new Uint8Array(Module.HEAPU8.buffer, bufferPtr, totalSize);
|
||||||
@@ -387,39 +393,21 @@ export function updateTextShape(fontSize, root) {
|
|||||||
const textAlign = getTextAlign(
|
const textAlign = getTextAlign(
|
||||||
paragraph.style.getPropertyValue("text-align"),
|
paragraph.style.getPropertyValue("text-align"),
|
||||||
);
|
);
|
||||||
console.log("text-align", textAlign);
|
|
||||||
const textDirection = getTextDirection(
|
const textDirection = getTextDirection(
|
||||||
paragraph.style.getPropertyValue("text-direction"),
|
paragraph.style.getPropertyValue("text-direction"),
|
||||||
);
|
);
|
||||||
console.log("text-direction", textDirection);
|
|
||||||
const textDecoration = getTextDecoration(
|
const textDecoration = getTextDecoration(
|
||||||
paragraph.style.getPropertyValue("text-decoration"),
|
paragraph.style.getPropertyValue("text-decoration"),
|
||||||
);
|
);
|
||||||
console.log("text-decoration", textDecoration);
|
|
||||||
const textTransform = getTextTransform(
|
const textTransform = getTextTransform(
|
||||||
paragraph.style.getPropertyValue("text-transform"),
|
paragraph.style.getPropertyValue("text-transform"),
|
||||||
);
|
);
|
||||||
console.log("text-transform", textTransform);
|
|
||||||
const lineHeight = parseFloat(
|
const lineHeight = parseFloat(
|
||||||
paragraph.style.getPropertyValue("line-height"),
|
paragraph.style.getPropertyValue("line-height"),
|
||||||
);
|
);
|
||||||
console.log("line-height", lineHeight);
|
|
||||||
const letterSpacing = parseFloat(
|
const letterSpacing = parseFloat(
|
||||||
paragraph.style.getPropertyValue("letter-spacing"),
|
paragraph.style.getPropertyValue("letter-spacing"),
|
||||||
);
|
);
|
||||||
console.log("letter-spacing", letterSpacing);
|
|
||||||
|
|
||||||
/*
|
|
||||||
num_leaves: u32,
|
|
||||||
text_align: u8,
|
|
||||||
text_direction: u8,
|
|
||||||
text_decoration: u8,
|
|
||||||
text_transform: u8,
|
|
||||||
line_height: f32,
|
|
||||||
letter_spacing: f32,
|
|
||||||
typography_ref_file: [u32; 4],
|
|
||||||
typography_ref_id: [u32; 4],
|
|
||||||
*/
|
|
||||||
|
|
||||||
setParagraphData(dview, {
|
setParagraphData(dview, {
|
||||||
numLeaves,
|
numLeaves,
|
||||||
@@ -432,31 +420,25 @@ export function updateTextShape(fontSize, root) {
|
|||||||
})
|
})
|
||||||
let leafOffset = PARAGRAPH_ATTR_SIZE;
|
let leafOffset = PARAGRAPH_ATTR_SIZE;
|
||||||
for (const leaf of leaves) {
|
for (const leaf of leaves) {
|
||||||
console.log(
|
const fontStyle = leaf.style.getPropertyValue("font-style");
|
||||||
"leafOffset",
|
const fontStyleSerialized = getFontStyle(fontStyle);
|
||||||
leafOffset,
|
|
||||||
PARAGRAPH_ATTR_SIZE,
|
|
||||||
LEAF_ATTR_SIZE,
|
|
||||||
FILL_SIZE,
|
|
||||||
totalFills,
|
|
||||||
totalFillsSize,
|
|
||||||
);
|
|
||||||
const fontStyle = getFontStyle(leaf.style.getPropertyValue("font-style"));
|
|
||||||
const fontSize = parseFloat(leaf.style.getPropertyValue("font-size"));
|
const fontSize = parseFloat(leaf.style.getPropertyValue("font-size"));
|
||||||
const letterSpacing = parseFloat(leaf.style.getPropertyValue("letter-spacing"))
|
const letterSpacing = parseFloat(leaf.style.getPropertyValue("letter-spacing"))
|
||||||
console.log("font-size", fontSize, "letter-spacing", letterSpacing);
|
|
||||||
const fontWeight = parseInt(
|
const fontWeight = parseInt(
|
||||||
leaf.style.getPropertyValue("font-weight"),
|
leaf.style.getPropertyValue("font-weight"),
|
||||||
10,
|
10,
|
||||||
);
|
);
|
||||||
console.log("font-weight", fontWeight);
|
|
||||||
|
|
||||||
const text = leaf.textContent;
|
const text = leaf.textContent;
|
||||||
const textBuffer = new TextEncoder().encode(text);
|
const textBuffer = new TextEncoder().encode(text);
|
||||||
const textSize = textBuffer.byteLength;
|
const textSize = textBuffer.byteLength;
|
||||||
|
const fontFamily = leaf.style.getPropertyValue('font-family');
|
||||||
|
const fontData = getFontFrom(fontFamily, fontWeight, fontStyle, fonts)
|
||||||
|
const defaultFontId = new Uint32Array([0, 0, 0, 0])
|
||||||
|
const fontId = fontData ? getU32(fontData.id) : defaultFontId
|
||||||
setLeafData(dview, leafOffset, {
|
setLeafData(dview, leafOffset, {
|
||||||
fontStyle,
|
fontId,
|
||||||
|
fontStyle: fontStyleSerialized,
|
||||||
textDecoration: 0,
|
textDecoration: 0,
|
||||||
textTransform: 0,
|
textTransform: 0,
|
||||||
textDirection: 0,
|
textDirection: 0,
|
||||||
@@ -464,8 +446,8 @@ export function updateTextShape(fontSize, root) {
|
|||||||
fontWeight,
|
fontWeight,
|
||||||
letterSpacing,
|
letterSpacing,
|
||||||
textSize,
|
textSize,
|
||||||
totalFills
|
totalFills,
|
||||||
})
|
});
|
||||||
|
|
||||||
// Serialize fills
|
// Serialize fills
|
||||||
let fillOffset = leafOffset + LEAF_ATTR_SIZE;
|
let fillOffset = leafOffset + LEAF_ATTR_SIZE;
|
||||||
@@ -485,14 +467,13 @@ export function updateTextShape(fontSize, root) {
|
|||||||
|
|
||||||
// Add text content
|
// Add text content
|
||||||
const textOffset = leafOffset;
|
const textOffset = leafOffset;
|
||||||
console.log('textOffset', textOffset);
|
|
||||||
heap.set(textBuffer, textOffset);
|
heap.set(textBuffer, textOffset);
|
||||||
|
|
||||||
Module._set_shape_text_content();
|
Module._set_shape_text_content();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addTextShape(fontSize, text) {
|
export function addTextShape(text, fonts) {
|
||||||
const numLeaves = 1; // Single text leaf for simplicity
|
const numLeaves = 1; // Single text leaf for simplicity
|
||||||
const textBuffer = new TextEncoder().encode(text);
|
const textBuffer = new TextEncoder().encode(text);
|
||||||
const textSize = textBuffer.byteLength;
|
const textSize = textBuffer.byteLength;
|
||||||
@@ -529,13 +510,25 @@ export function addTextShape(fontSize, text) {
|
|||||||
|
|
||||||
// Serialize leaf attributes
|
// Serialize leaf attributes
|
||||||
const leafOffset = PARAGRAPH_ATTR_SIZE;
|
const leafOffset = PARAGRAPH_ATTR_SIZE;
|
||||||
|
const fontStyle = getFontStyle('normal');
|
||||||
|
const fontStyleSerialized = getFontStyle(fontStyle);
|
||||||
|
const fontSize = 14;
|
||||||
|
const letterSpacing = 0;
|
||||||
|
const fontWeight = 400;
|
||||||
|
const fontFamily = 'MontserratAlternates';
|
||||||
|
const fontData = getFontFrom(fontFamily, fontWeight, fontStyle, fonts);
|
||||||
|
const defaultFontId = new Uint32Array([0, 0, 0, 0]);
|
||||||
|
const fontId = fontData ? getU32(fontData.id) : defaultFontId;
|
||||||
|
|
||||||
setLeafData(dview, leafOffset, {
|
setLeafData(dview, leafOffset, {
|
||||||
|
fontId,
|
||||||
fontSize,
|
fontSize,
|
||||||
fontWeight: 400,
|
fontStyle: fontStyleSerialized,
|
||||||
|
fontWeight,
|
||||||
textDecoration: 0,
|
textDecoration: 0,
|
||||||
textDirection: 0,
|
textDirection: 0,
|
||||||
textTransform: 0,
|
textTransform: 0,
|
||||||
letterSpacing: 0,
|
letterSpacing,
|
||||||
textSize,
|
textSize,
|
||||||
totalFills,
|
totalFills,
|
||||||
});
|
});
|
||||||
@@ -558,3 +551,44 @@ export function addTextShape(fontSize, text) {
|
|||||||
// Call the WebAssembly function
|
// Call the WebAssembly function
|
||||||
Module._set_shape_text_content();
|
Module._set_shape_text_content();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function storeFonts(fonts) {
|
||||||
|
for (const [fontName, fontStyles] of fonts) {
|
||||||
|
for (const font of fontStyles) {
|
||||||
|
const shapeId = getU32('00000000-0000-0000-0000-000000000000');
|
||||||
|
const fontId = getU32(font.id);
|
||||||
|
const weight = font.weight;
|
||||||
|
const style = getFontStyle(font.style);
|
||||||
|
const size = font.arrayBuffer.byteLength;
|
||||||
|
const ptr = Module._alloc_bytes(size);
|
||||||
|
const heap = Module.HEAPU8;
|
||||||
|
const mem = new Uint8Array(heap.buffer, ptr, size);
|
||||||
|
mem.set(new Uint8Array(font.arrayBuffer));
|
||||||
|
const emoji = false
|
||||||
|
const fallback = false
|
||||||
|
Module._store_font(
|
||||||
|
shapeId[0],
|
||||||
|
shapeId[1],
|
||||||
|
shapeId[2],
|
||||||
|
shapeId[3],
|
||||||
|
fontId[0],
|
||||||
|
fontId[1],
|
||||||
|
fontId[2],
|
||||||
|
fontId[3],
|
||||||
|
weight,
|
||||||
|
style,
|
||||||
|
emoji,
|
||||||
|
fallback,
|
||||||
|
);
|
||||||
|
Module._is_font_uploaded(
|
||||||
|
fontId[0],
|
||||||
|
fontId[1],
|
||||||
|
fontId[2],
|
||||||
|
fontId[3],
|
||||||
|
weight,
|
||||||
|
style,
|
||||||
|
emoji,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user