From dcf50c6986b17efb83af8d0b4ed22324b2afa5ee Mon Sep 17 00:00:00 2001 From: Dylan Audius Date: Fri, 23 Oct 2026 16:56:11 -0700 Subject: [PATCH] design(tokens): revert tokens v2 fonts and colors, keep track rows Reverts #14683 and #14699. Web goes back to Avenir and the original Neue palette, gradient headings and accent nav selection. The TrackRow layouts from #14684-#14690 stay; the rank column drops Bricolage. Avenir keeps the woff2 loading from #14677, with the Medium, DemiBold and Bold preloads restored now that it is the primary face. Co-Authored-By: Claude Opus 5.5 --- package-lock.json | 20 -- packages/harmony/README.md | 2 - packages/harmony/rollup.config.mjs | 5 +- packages/harmony/rollup.css.config.mjs | 7 +- packages/harmony/rollup.fonts.mjs | 30 --- .../src/components/button/Button/Button.tsx | 17 +- .../input/SelectablePill/SelectablePill.tsx | 6 +- .../src/components/nav-item/NavItem.tsx | 23 +- packages/harmony/src/components/text/Text.tsx | 14 +- .../harmony/src/components/text/constants.ts | 11 +- .../src/components/track-row/TrackRow.tsx | 2 - packages/harmony/src/css-entry.ts | 1 + .../src/foundations/color/primitive.css | 138 +++++----- .../src/foundations/color/primitive.ts | 178 ++++++------- .../src/foundations/color/semantic.css | 10 +- .../harmony/src/foundations/color/semantic.ts | 34 +-- .../harmony/src/foundations/theme/types.ts | 6 +- .../src/foundations/typography/fonts.css | 11 +- .../src/foundations/typography/typography.ts | 9 +- packages/harmony/src/index.ts | 1 + packages/harmony/turbo.json | 9 +- .../harmony-native/components/Text/Text.tsx | 5 +- packages/web/index.html | 252 ++++++++++-------- packages/web/package.json | 2 - packages/web/public/fonts.css | 4 +- packages/web/src/Root.tsx | 4 +- .../src/app/web-player/ServerWebPlayer.tsx | 4 +- .../edit/fields/DatePickerField.module.css | 2 +- .../nav/desktop/CollapsedNavItem.tsx | 18 +- .../UserBalanceHistoryGraph.module.css | 4 +- .../src/utils/animations/music-confetti.js | 2 +- 31 files changed, 345 insertions(+), 486 deletions(-) delete mode 100644 packages/harmony/rollup.fonts.mjs diff --git a/package-lock.json b/package-lock.json index b713fb22718..302f2a4df9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13161,24 +13161,6 @@ "vue-demi": ">=0.13.0" } }, - "node_modules/@fontsource-variable/bricolage-grotesque": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@fontsource-variable/bricolage-grotesque/-/bricolage-grotesque-5.3.0.tgz", - "integrity": "sha512-TLi9Q4hJjS2UvoTMRSS2nHu6c4R56lAw60NR9QYtVRCHn0XtsFpiEhNffZ8Glsoxu6wEEwLKBP8lb94J52PNBA==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@fontsource-variable/inter": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@fontsource-variable/inter/-/inter-5.3.0.tgz", - "integrity": "sha512-OupL48va4JNofb97w6NYeF9S7W/kHNKM0Er8Dem5nqi4jeOLrVJDoE8tZEpnMJmtkvNbB1EIPPwHcdkF6b1oUA==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, "node_modules/@gar/promisify": { "version": "1.1.3", "dev": true, @@ -126878,8 +126860,6 @@ "@emotion/react": "11.14.0", "@emotion/server": "11.11.0", "@emotion/styled": "11.14.0", - "@fontsource-variable/bricolage-grotesque": "^5.3.0", - "@fontsource-variable/inter": "^5.3.0", "@google/model-viewer": "3.3.0", "@hcaptcha/react-hcaptcha": "0.3.6", "@juggle/resize-observer": "^3.3.1", diff --git a/packages/harmony/README.md b/packages/harmony/README.md index ad8a17e2b0c..81c5f91259f 100644 --- a/packages/harmony/README.md +++ b/packages/harmony/README.md @@ -60,8 +60,6 @@ Import styles exported by Harmony import '@audius/harmony/dist/harmony.css' ``` -`harmony.css` inlines the Avenir Next LT Pro font faces as base64. If you serve the font files yourself, import `@audius/harmony/dist/harmony-no-fonts.css` instead and declare the `@font-face` rules in your app. - Setup the ThemeProvider exported by Harmony ```tsx diff --git a/packages/harmony/rollup.config.mjs b/packages/harmony/rollup.config.mjs index 315fb6cf900..95d82b967f7 100644 --- a/packages/harmony/rollup.config.mjs +++ b/packages/harmony/rollup.config.mjs @@ -8,8 +8,6 @@ import svgr from '@svgr/rollup' import postcss from 'rollup-plugin-postcss' import rollupTypescript from 'rollup-plugin-typescript2' -import { NO_FONTS_CSS, harmonyCssWithFonts } from './rollup.fonts.mjs' - const cjsRequire = createRequire(import.meta.url) const pkg = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8')) const tspCompiler = cjsRequire('ts-patch/compiler') @@ -44,10 +42,9 @@ export default { }), postcss({ minimize: true, - extract: NO_FONTS_CSS, + extract: 'harmony.css', modules: true }), - harmonyCssWithFonts(), svgr(), image({ exclude: /\.svg$/ // Exclude SVG files since they're handled by SVGR diff --git a/packages/harmony/rollup.css.config.mjs b/packages/harmony/rollup.css.config.mjs index c7e9785aa6e..8001835c8ef 100644 --- a/packages/harmony/rollup.css.config.mjs +++ b/packages/harmony/rollup.css.config.mjs @@ -3,8 +3,6 @@ import { createRequire } from 'node:module' import postcss from 'rollup-plugin-postcss' import rollupTypescript from 'rollup-plugin-typescript2' -import { NO_FONTS_CSS, harmonyCssWithFonts } from './rollup.fonts.mjs' - const cjsRequire = createRequire(import.meta.url) const tspCompiler = cjsRequire('ts-patch/compiler') @@ -28,11 +26,10 @@ export default { }), postcss({ minimize: true, - extract: NO_FONTS_CSS, + extract: 'harmony.css', modules: true, inject: false - }), - harmonyCssWithFonts() + }) ], // External everything since we only care about CSS extraction external: () => true, diff --git a/packages/harmony/rollup.fonts.mjs b/packages/harmony/rollup.fonts.mjs deleted file mode 100644 index 4dd27a16999..00000000000 --- a/packages/harmony/rollup.fonts.mjs +++ /dev/null @@ -1,30 +0,0 @@ -import { readFileSync } from 'node:fs' - -// postcss extracts this file; harmony.css is emitted as the Avenir font faces + this. -export const NO_FONTS_CSS = 'harmony-no-fonts.css' - -const avenirCss = readFileSync( - new URL('./src/foundations/typography/avenir.css', import.meta.url), - 'utf8' -) - .replace(/\/\*[\s\S]*?\*\//g, '') - .replace(/\s+/g, ' ') - .trim() - -// Emits harmony.css (with base64 Avenir) next to harmony-no-fonts.css so apps -// that host the font files themselves can skip the inlined font data. -export const harmonyCssWithFonts = () => ({ - name: 'harmony-css-with-fonts', - generateBundle(_options, bundle) { - const asset = bundle[NO_FONTS_CSS] - if (!asset || asset.type !== 'asset') { - this.warn(`${NO_FONTS_CSS} was not emitted, skipping harmony.css`) - return - } - this.emitFile({ - type: 'asset', - fileName: 'harmony.css', - source: `${avenirCss}\n${asset.source}` - }) - } -}) diff --git a/packages/harmony/src/components/button/Button/Button.tsx b/packages/harmony/src/components/button/Button/Button.tsx index 4504cacf45b..4747730d764 100644 --- a/packages/harmony/src/components/button/Button/Button.tsx +++ b/packages/harmony/src/components/button/Button/Button.tsx @@ -41,15 +41,6 @@ export const Button = forwardRef( const isSmallOrXs = size === 'small' || size === 'xs' - // static.white is dark in Neue dark, but the Neue accent needs light text. - // Custom colors (e.g. the light green Buy button) keep dark text. - const onAccent = - type === 'default-dark' - ? themeColors.static.staticWhite - : themeColors.static.white - const onPrimary = color || hexColor ? themeColors.static.white : onAccent - const onPrimaryHover = hoverColor ? themeColors.static.white : onPrimary - // Size Styles const smallStyles: CSSObject = { gap: spacing.xs, @@ -100,9 +91,9 @@ export const Button = forwardRef( // Variant Styles const primaryStyles: CSSObject = { - '&:hover': { color: onPrimaryHover }, + '&:hover': { color: themeColors.static.white }, - ...((_isHovered || _isPressed) && { color: onPrimaryHover }), + ...((_isHovered || _isPressed) && { color: themeColors.static.white }), ...(disabled && { background: themeColors.neutral.n150, boxShadow: 'none' @@ -111,7 +102,7 @@ export const Button = forwardRef( const secondaryHoverStyles: CSSObject = { background: themeColors.primary.primary, - color: onAccent + color: themeColors.static.white } const secondaryStyles: CSSObject = { background: 'transparent', @@ -183,7 +174,7 @@ export const Button = forwardRef( const buttonCss: CSSObject = { background: themeColors.primary.primary, - color: onPrimary, + color: themeColors.static.white, boxSizing: 'border-box', border: 'none', borderRadius: rounded ? cornerRadius['2xl'] : cornerRadius.s, diff --git a/packages/harmony/src/components/input/SelectablePill/SelectablePill.tsx b/packages/harmony/src/components/input/SelectablePill/SelectablePill.tsx index 45a8520e8aa..83d2294dd53 100644 --- a/packages/harmony/src/components/input/SelectablePill/SelectablePill.tsx +++ b/packages/harmony/src/components/input/SelectablePill/SelectablePill.tsx @@ -36,11 +36,7 @@ export const SelectablePill = (props: SelectablePillProps) => { const hoverCss: CSSObject = { backgroundColor: theme.color.secondary.s200, - // s200 is the dark accent in Neue dark, where static.white is dark too. - color: - theme.type === 'default-dark' - ? theme.color.static.staticWhite - : theme.color.static.white, + color: theme.color.static.white, border: `1px solid ${theme.color.secondary.secondary}`, ...(size === 'large' && { boxShadow: 'none' diff --git a/packages/harmony/src/components/nav-item/NavItem.tsx b/packages/harmony/src/components/nav-item/NavItem.tsx index 8fc2f5985d5..fcb2c74c3fc 100644 --- a/packages/harmony/src/components/nav-item/NavItem.tsx +++ b/packages/harmony/src/components/nav-item/NavItem.tsx @@ -3,7 +3,6 @@ import { useMemo } from 'react' import { useTheme } from '@emotion/react' import { motion } from '../../foundations/motion' -import { isNeueTheme } from '../../foundations/theme/types' import { Flex } from '../layout/Flex' import { NotificationCount } from '../notification-count' import { Text } from '../text/Text' @@ -28,19 +27,14 @@ export const NavItem = ({ isChild = false, ...props }: NavItemProps) => { - const { color, type } = useTheme() - const isNeue = isNeueTheme(type) + const { color } = useTheme() const hasLeftIcon = !!LeftIcon const hasRightIcon = !!RightIcon - const backgroundColor = isSelected - ? isNeue - ? color.background.surface2 - : color.secondary.s400 - : undefined + const backgroundColor = isSelected ? color.secondary.s400 : undefined - const textAndIconColor = isSelected && !isNeue ? 'white' : 'default' + const textAndIconColor = isSelected ? 'white' : 'default' const insetBorderColor = isSelected ? 'none' : `inset 0 0 0 1px ${color.border.default}` @@ -52,20 +46,13 @@ export const NavItem = ({ if (hasNotification && !!icon) { return ( - + {icon} ) } return icon - }, [ - hasNotification, - hasLeftIcon, - LeftIcon, - textAndIconColor, - isSelected, - isNeue - ]) + }, [hasNotification, hasLeftIcon, LeftIcon, textAndIconColor, isSelected]) return ( { if (!color) return {} if (color === 'heading') { - if (isNeueTheme(theme.type)) return { color: theme.color.text.heading } return { color: theme.color.secondary.secondary, WebkitTextFillColor: 'transparent', @@ -102,17 +99,8 @@ export const Text = forwardRef( const variantConfig = variant && variantStylesMap[variant] const hasSubscripts = containsSubscripts(children) - const isDisplayFace = variant === 'display' || variant === 'heading' - const css = { - fontFamily: isDisplayFace - ? theme.typography.fontDisplay - : theme.typography.font, - // Apps that force `font-family: var(--harmony-font-family)` globally - // still get the display face on display and heading text. - ...(isDisplayFace && { - '--harmony-font-family': theme.typography.fontDisplay - }), + fontFamily: theme.typography.font, position: 'relative', boxSizing: 'border-box', ...getColorCss(color, theme), diff --git a/packages/harmony/src/components/text/constants.ts b/packages/harmony/src/components/text/constants.ts index 192ca2f98d2..82a2a71f34e 100644 --- a/packages/harmony/src/components/text/constants.ts +++ b/packages/harmony/src/components/text/constants.ts @@ -27,32 +27,31 @@ export const variantTagMap = { } export const variantStylesMap = { - // Tokens v2: four weights (400/500/600/700). Heavy (900) is no longer used. display: { fontSize: { s: '6xl', m: '7xl', l: '8xl', xl: '9xl' }, lineHeight: { s: '3xl', m: '4xl', l: '5xl', xl: '6xl' }, - fontWeight: { default: 'bold', strong: 'bold' } + fontWeight: { default: 'bold', strong: 'heavy' } }, heading: { fontSize: { s: 'xl', m: '2xl', l: '3xl', xl: '5xl' }, lineHeight: { s: 'l', m: 'xl', l: 'hl', xl: '2xl' }, - fontWeight: { default: 'bold', strong: 'bold' } + fontWeight: { default: 'bold', strong: 'heavy' } }, title: { fontSize: { xs: 'xs', s: 's', m: 'm', l: 'l' }, lineHeight: { xs: 's', s: 'm', m: 'l', l: 'l' }, - fontWeight: { weak: 'medium', default: 'demiBold', strong: 'bold' } + fontWeight: { weak: 'demiBold', default: 'bold', strong: 'heavy' } }, label: { fontSize: { xs: '2xs', s: 'xs', m: 's', l: 'm', xl: 'xl' }, lineHeight: { xs: 'xs', s: 'xs', m: 's', l: 's', xl: 'l' }, - fontWeight: { default: 'demiBold', strong: 'bold' }, + fontWeight: { default: 'bold', strong: 'heavy' }, css: { textTransform: 'uppercase' as const, letterSpacing: 0.5 } }, body: { fontSize: { xs: 'xs', s: 's', m: 'm', l: 'l' }, lineHeight: { xs: 's', s: 'm', m: 'l', l: 'l' }, - fontWeight: { default: 'regular', strong: 'demiBold' } + fontWeight: { default: 'medium', strong: 'demiBold' } } } diff --git a/packages/harmony/src/components/track-row/TrackRow.tsx b/packages/harmony/src/components/track-row/TrackRow.tsx index 30d71033363..2b756eaa252 100644 --- a/packages/harmony/src/components/track-row/TrackRow.tsx +++ b/packages/harmony/src/components/track-row/TrackRow.tsx @@ -175,8 +175,6 @@ export const TrackRow = forwardRef( }) const rankFace = css({ - fontFamily: typography.fontDisplay, - '--harmony-font-family': typography.fontDisplay, transition: `opacity ${motion.hover}` }) diff --git a/packages/harmony/src/css-entry.ts b/packages/harmony/src/css-entry.ts index da1ee578ef2..e326544e54b 100644 --- a/packages/harmony/src/css-entry.ts +++ b/packages/harmony/src/css-entry.ts @@ -2,6 +2,7 @@ // Only imports CSS files, no TypeScript/JavaScript exports import './foundations/reset/reset.css' +import './foundations/typography/avenir.css' import './foundations/typography/fonts.css' import './foundations/spacing/spacing.css' import './foundations/color/primitive.css' diff --git a/packages/harmony/src/foundations/color/primitive.css b/packages/harmony/src/foundations/color/primitive.css index 35403aa369b..0ab60cc26e7 100644 --- a/packages/harmony/src/foundations/color/primitive.css +++ b/packages/harmony/src/foundations/color/primitive.css @@ -229,46 +229,46 @@ html[data-theme='classic-dark'] { /* Default Light (Neue design system) */ html[data-theme='default-light'] { /* Primary Colors */ - --harmony-primary: #6a52e0; - --harmony-p-100: #efebff; - --harmony-p-200: #d9d1ff; - --harmony-p-300: #6a52e0; + --harmony-primary: #7f6ad6; + --harmony-p-100: #e9e3ff; + --harmony-p-200: #cfc3ff; + --harmony-p-300: #7f6ad6; --harmony-p-400: #5b44b8; --harmony-p-500: #3b2a86; /* Secondary Colors */ - --harmony-secondary: #5b44b8; - --harmony-s-100: #efebff; - --harmony-s-200: #cfc3ff; - --harmony-s-300: #5b44b8; - --harmony-s-400: #4a369e; - --harmony-s-500: #3b2a86; + --harmony-secondary: #a74cff; + --harmony-s-100: #f0e0ff; + --harmony-s-200: #ddbbff; + --harmony-s-300: #a74cff; + --harmony-s-400: #7d2fdb; + --harmony-s-500: #4f159e; /* Neutral Colors */ - --harmony-neutral: #16161a; - --harmony-n-25: #f5f5f7; - --harmony-n-50: #ececf0; - --harmony-n-100: #e4e4ea; - --harmony-n-150: #c4c4cc; - --harmony-n-200: #a8a8b2; - --harmony-n-300: #6b6b75; - --harmony-n-400: #5c5c66; - --harmony-n-500: #50505a; - --harmony-n-600: #44444e; - --harmony-n-700: #30303a; - --harmony-n-800: #16161a; - --harmony-n-900: #101014; - --harmony-n-950: #0b0b0e; + --harmony-neutral: #343b49; + --harmony-n-25: #f7f7f8; + --harmony-n-50: #f0f1f3; + --harmony-n-100: #e6e8ec; + --harmony-n-150: #d8dbe2; + --harmony-n-200: #c7ccd6; + --harmony-n-300: #b2b8c5; + --harmony-n-400: #9aa1b0; + --harmony-n-500: #7f8798; + --harmony-n-600: #636c7e; + --harmony-n-700: #4a5263; + --harmony-n-800: #343b49; + --harmony-n-900: #232834; + --harmony-n-950: #0c0f14; /* Special Colors */ --harmony-white: #ffffff; - --harmony-background: #f7f7f9; - --harmony-blue: #6a52e0; - --harmony-orange: #b45309; - --harmony-red: #dc2626; - --harmony-dark-red: #b91c1c; + --harmony-background: #f6f5f7; + --harmony-blue: #7f6ad6; + --harmony-orange: #ff9400; + --harmony-red: #f94d62; + --harmony-dark-red: #c44357; --harmony-green: #0f9e48; - --harmony-light-green: #15803d; - --harmony-gradient-color-1: #6a52e0; + --harmony-light-green: #a74cff; + --harmony-gradient-color-1: #7f6ad6; --harmony-gradient-color-2: #5b44b8; - --harmony-gradient: linear-gradient(315deg, #6a52e0 0%, #5b44b8 100%); + --harmony-gradient: linear-gradient(315deg, #7f6ad6 0%, #5b44b8 100%); --harmony-coin-gradient: linear-gradient( 85deg, #7f6ad6 -4.82%, @@ -276,52 +276,52 @@ html[data-theme='default-light'] { #7f6ad6 104.43% ); --harmony-trending-blue: #2a85e8; - --harmony-glass-overlay: #ffffffc7; + --harmony-glass-overlay: #00000014; } /* Default Dark (Neue design system) */ html[data-theme='default-dark'] { /* Primary Colors */ - --harmony-primary: #6a52e0; - --harmony-p-100: #1e1a33; - --harmony-p-200: #2e2752; - --harmony-p-300: #6a52e0; - --harmony-p-400: #8e7ce8; + --harmony-primary: #806ad8; + --harmony-p-100: #261f40; + --harmony-p-200: #443873; + --harmony-p-300: #806ad8; + --harmony-p-400: #9e8ee8; --harmony-p-500: #d8cfff; /* Secondary Colors */ - --harmony-secondary: #a594ff; - --harmony-s-100: #2e2752; - --harmony-s-200: #6a52e0; - --harmony-s-300: #a594ff; - --harmony-s-400: #bdb2ff; - --harmony-s-500: #d8cfff; + --harmony-secondary: #c67cff; + --harmony-s-100: #9a66ca; + --harmony-s-200: #b071e4; + --harmony-s-300: #c67cff; + --harmony-s-400: #cf90ff; + --harmony-s-500: #d7a3ff; /* Neutral Colors */ - --harmony-neutral: #f2f2f5; - --harmony-n-25: #141418; - --harmony-n-50: #1c1c21; - --harmony-n-100: #2a2a31; - --harmony-n-150: #42424b; - --harmony-n-200: #55555f; - --harmony-n-300: #85858f; - --harmony-n-400: #a9a9b3; - --harmony-n-500: #b8b8c1; - --harmony-n-600: #c8c8cf; - --harmony-n-700: #d8d8de; - --harmony-n-800: #f2f2f5; - --harmony-n-900: #f7f7f9; - --harmony-n-950: #ffffff; + --harmony-neutral: #d1d1d1; + --harmony-n-25: #0f0f0f; + --harmony-n-50: #141414; + --harmony-n-100: #1f1f1f; + --harmony-n-150: #292929; + --harmony-n-200: #333333; + --harmony-n-300: #474747; + --harmony-n-400: #636363; + --harmony-n-500: #757575; + --harmony-n-600: #8f8f8f; + --harmony-n-700: #9e9e9e; + --harmony-n-800: #d1d1d1; + --harmony-n-900: #e0e0e0; + --harmony-n-950: #ededed; /* Special Colors */ - --harmony-white: #1c1c21; - --harmony-background: #0b0b0e; - --harmony-blue: #a594ff; - --harmony-orange: #fbbf24; - --harmony-red: #f87171; - --harmony-dark-red: #dc2626; + --harmony-white: #0f0f0f; + --harmony-background: #000000; + --harmony-blue: #806ad8; + --harmony-orange: #efb360; + --harmony-red: #f94d62; + --harmony-dark-red: #c44357; --harmony-green: #84df64; - --harmony-light-green: #4ade80; - --harmony-gradient-color-1: #6a52e0; - --harmony-gradient-color-2: #a594ff; - --harmony-gradient: linear-gradient(315deg, #6a52e0 0%, #a594ff 100%); + --harmony-light-green: #c67cff; + --harmony-gradient-color-1: #806ad8; + --harmony-gradient-color-2: #9e8ee8; + --harmony-gradient: linear-gradient(315deg, #806ad8 0%, #9e8ee8 100%); --harmony-coin-gradient: linear-gradient( 85deg, #806ad8 -4.82%, @@ -329,7 +329,7 @@ html[data-theme='default-dark'] { #806ad8 104.43% ); --harmony-trending-blue: #2a85e8; - --harmony-glass-overlay: #0b0b0eb8; + --harmony-glass-overlay: #0f0f0f99; } /* Dark Theme */ diff --git a/packages/harmony/src/foundations/color/primitive.ts b/packages/harmony/src/foundations/color/primitive.ts index b4affcf2142..c771bae7e2b 100644 --- a/packages/harmony/src/foundations/color/primitive.ts +++ b/packages/harmony/src/foundations/color/primitive.ts @@ -1,142 +1,142 @@ /** - * Default [Neue] theme - light variant - * Tokens v2 (Oct 2026): neutral chrome, one accent, AA contrast on every text pair. + * Default [Neue] theme - modern design system (light variant) + * From Figma Default [Neue].tokens.json */ const defaultLightPrimitives = { static: { - primary: '#6A52E0', - secondary: '#5B44B8', + primary: '#7F6AD6', + secondary: '#A74CFF', white: '#FFFFFF', staticWhite: '#F6F8FC', - black: '#0B0B0E' + black: '#0F0F0F' }, primary: { - p100: '#EFEBFF', - p200: '#D9D1FF', - p300: '#6A52E0', + p100: '#E9E3FF', + p200: '#CFC3FF', + p300: '#7F6AD6', p400: '#5B44B8', p500: '#3B2A86', - default: '#6A52E0', - primary: '#6A52E0' + default: '#7F6AD6', + primary: '#7F6AD6' }, secondary: { - s100: '#EFEBFF', - s200: '#CFC3FF', - s300: '#5B44B8', - s400: '#4A369E', - s500: '#3B2A86', - default: '#5B44B8', - secondary: '#5B44B8' + s100: '#F0E0FF', + s200: '#DDBBFF', + s300: '#A74CFF', + s400: '#7D2FDB', + s500: '#4F159E', + default: '#A74CFF', + secondary: '#A74CFF' }, neutral: { - n25: '#F5F5F7', - n50: '#ECECF0', - n100: '#E4E4EA', - n150: '#C4C4CC', - n200: '#A8A8B2', - n300: '#6B6B75', - n400: '#5C5C66', - n500: '#50505A', - n600: '#44444E', - n700: '#30303A', - n800: '#16161A', - n900: '#101014', - n950: '#0B0B0E', - default: '#16161A', - neutral: '#16161A' + n25: '#F7F7F8', + n50: '#F0F1F3', + n100: '#E6E8EC', + n150: '#D8DBE2', + n200: '#C7CCD6', + n300: '#B2B8C5', + n400: '#9AA1B0', + n500: '#7F8798', + n600: '#636C7E', + n700: '#4A5263', + n800: '#343B49', + n900: '#232834', + n950: '#0C0F14', + default: '#343B49', + neutral: '#343B49' }, special: { - background: '#F7F7F9', - blue: '#6A52E0', - darkRed: '#B91C1C', - glassOverlay: '#FFFFFFC7', - gradientStop1: '#6A52E0', + background: '#F6F5F7', + blue: '#7F6AD6', + darkRed: '#C44357', + glassOverlay: '#00000014', + gradientStop1: '#7F6AD6', gradientStop2: '#5B44B8', - gradient: 'linear-gradient(315deg, #6A52E0 0%, #5B44B8 100%)', + gradient: 'linear-gradient(315deg, #7F6AD6 0%, #5B44B8 100%)', coinGradient: 'linear-gradient(85deg, #7F6AD6 -4.82%, #A74CFF 49.8%, #7F6AD6 104.43%)', coinGradientColor1: '#7F6AD6', coinGradientColor2: '#A74CFF', coinGradientColor3: '#7F6AD6', green: '#0F9E48', - lightGreen: '#15803D', - orange: '#B45309', - red: '#DC2626', + lightGreen: '#A74CFF', + orange: '#FF9400', + red: '#F94D62', trendingBlue: '#2A85E8', white: '#FFFFFF', - default: '#6A52E0', - special: '#6A52E0' + default: '#7F6AD6', + special: '#7F6AD6' } } /** - * Default [Neue] theme - dark variant - * Tokens v2 (Oct 2026): neutral chrome, one accent, AA contrast on every text pair. + * Dark [Neue] theme - modern design system (dark variant) + * From Figma Dark [Neue].tokens.json */ const defaultDarkPrimitives = { static: { - primary: '#6A52E0', - secondary: '#A594FF', - white: '#1C1C21', + primary: '#917FD8', + secondary: '#C67CFF', + white: '#0F0F0F', staticWhite: '#F6F8FC', black: '#FFFFFF' }, primary: { - p100: '#1E1A33', - p200: '#2E2752', - p300: '#6A52E0', - p400: '#8E7CE8', + p100: '#261F40', + p200: '#443873', + p300: '#806AD8', + p400: '#9E8EE8', p500: '#D8CFFF', - default: '#6A52E0', - primary: '#6A52E0' + default: '#806AD8', + primary: '#806AD8' }, secondary: { - s100: '#2E2752', - s200: '#6A52E0', - s300: '#A594FF', - s400: '#BDB2FF', - s500: '#D8CFFF', - default: '#A594FF', - secondary: '#A594FF' + s100: '#9A66CA', + s200: '#B071E4', + s300: '#C67CFF', + s400: '#CF90FF', + s500: '#D7A3FF', + default: '#C67CFF', + secondary: '#C67CFF' }, neutral: { - n25: '#141418', - n50: '#1C1C21', - n100: '#2A2A31', - n150: '#42424B', - n200: '#55555F', - n300: '#85858F', - n400: '#A9A9B3', - n500: '#B8B8C1', - n600: '#C8C8CF', - n700: '#D8D8DE', - n800: '#F2F2F5', - n900: '#F7F7F9', - n950: '#FFFFFF', - default: '#F2F2F5', - neutral: '#F2F2F5' + n25: '#0F0F0F', + n50: '#141414', + n100: '#1F1F1F', + n150: '#292929', + n200: '#333333', + n300: '#474747', + n400: '#636363', + n500: '#757575', + n600: '#8F8F8F', + n700: '#9E9E9E', + n800: '#D1D1D1', + n900: '#E0E0E0', + n950: '#EDEDED', + default: '#D1D1D1', + neutral: '#D1D1D1' }, special: { - background: '#0B0B0E', - blue: '#A594FF', - darkRed: '#DC2626', - glassOverlay: '#0B0B0EB8', - gradientStop1: '#6A52E0', - gradientStop2: '#A594FF', - gradient: 'linear-gradient(315deg, #6A52E0 0%, #A594FF 100%)', + background: '#000000', + blue: '#806AD8', + darkRed: '#C44357', + glassOverlay: '#0F0F0F99', + gradientStop1: '#806AD8', + gradientStop2: '#9E8EE8', + gradient: 'linear-gradient(315deg, #806AD8 0%, #9E8EE8 100%)', coinGradient: 'linear-gradient(85deg, #806AD8 -4.82%, #C67CFF 49.8%, #806AD8 104.43%)', coinGradientColor1: '#806AD8', coinGradientColor2: '#C67CFF', coinGradientColor3: '#806AD8', green: '#84DF64', - lightGreen: '#4ADE80', - orange: '#FBBF24', - red: '#F87171', + lightGreen: '#C67CFF', + orange: '#EFB360', + red: '#F94D62', trendingBlue: '#2A85E8', - white: '#1C1C21', - default: '#A594FF', - special: '#A594FF' + white: '#0F0F0F', + default: '#806AD8', + special: '#806AD8' } } diff --git a/packages/harmony/src/foundations/color/semantic.css b/packages/harmony/src/foundations/color/semantic.css index 6208d11452a..3554683a0e7 100644 --- a/packages/harmony/src/foundations/color/semantic.css +++ b/packages/harmony/src/foundations/color/semantic.css @@ -1,7 +1,7 @@ /* Semantic Token Definitions */ :root { /* Text */ - --harmony-text-heading: var(--harmony-neutral); + --harmony-text-heading: var(--harmony-gradient); --harmony-text-default: var(--harmony-neutral); --harmony-text-subdued: var(--harmony-n-400); --harmony-text-disabled: var(--harmony-n-150); @@ -24,11 +24,3 @@ transparent ); } - -html[data-theme='day'], -html[data-theme='dark'], -html[data-theme='classic-light'], -html[data-theme='classic-dark'], -html[data-theme='matrix'] { - --harmony-text-heading: var(--harmony-gradient); -} diff --git a/packages/harmony/src/foundations/color/semantic.ts b/packages/harmony/src/foundations/color/semantic.ts index ba4904f8f7d..05f1a85be5e 100644 --- a/packages/harmony/src/foundations/color/semantic.ts +++ b/packages/harmony/src/foundations/color/semantic.ts @@ -1,11 +1,7 @@ import type { PrimitiveColors } from './primitive' import { primitiveTheme } from './primitive' -// Neue headings are plain text; Classic and Matrix keep the gradient. -const createSemanticTheme = ( - primitives: PrimitiveColors, - { gradientHeading = false } = {} -) => ({ +const createSemanticTheme = (primitives: PrimitiveColors) => ({ text: { default: primitives.neutral.n800, subdued: primitives.neutral.n400, @@ -15,9 +11,7 @@ const createSemanticTheme = ( inverse: primitives.neutral.n950, // Legacy compatibility - heading: gradientHeading - ? primitives.special.gradient - : primitives.neutral.n800, + heading: primitives.special.gradient, active: primitives.primary.p300, white: primitives.special.white, staticWhite: primitives.static.staticWhite, @@ -37,9 +31,7 @@ const createSemanticTheme = ( inverse: primitives.static.staticWhite, // Legacy compatibility - heading: gradientHeading - ? primitives.special.gradient - : primitives.neutral.n800, + heading: primitives.special.gradient, active: primitives.primary.p300, white: primitives.special.white, staticWhite: primitives.static.staticWhite, @@ -88,23 +80,13 @@ const createSemanticTheme = ( export const semanticTheme = { defaultLight: createSemanticTheme(primitiveTheme.defaultLight), defaultDark: createSemanticTheme(primitiveTheme.defaultDark), - classicLight: createSemanticTheme(primitiveTheme.classicLight, { - gradientHeading: true - }), - classicDark: createSemanticTheme(primitiveTheme.classicDark, { - gradientHeading: true - }), - matrix: createSemanticTheme(primitiveTheme.matrix, { - gradientHeading: true - }), + classicLight: createSemanticTheme(primitiveTheme.classicLight), + classicDark: createSemanticTheme(primitiveTheme.classicDark), + matrix: createSemanticTheme(primitiveTheme.matrix), /** @deprecated Use classicLight */ - day: createSemanticTheme(primitiveTheme.day, { - gradientHeading: true - }), + day: createSemanticTheme(primitiveTheme.day), /** @deprecated Use classicDark */ - dark: createSemanticTheme(primitiveTheme.dark, { - gradientHeading: true - }) + dark: createSemanticTheme(primitiveTheme.dark) } export type SemanticColors = typeof semanticTheme.day diff --git a/packages/harmony/src/foundations/theme/types.ts b/packages/harmony/src/foundations/theme/types.ts index 398e18f68c6..d6fcd1f9bf0 100644 --- a/packages/harmony/src/foundations/theme/types.ts +++ b/packages/harmony/src/foundations/theme/types.ts @@ -1,6 +1,6 @@ import { Interpolation } from '@emotion/react' -import type { HarmonyTheme } from './theme' +import { HarmonyTheme } from './theme' /** Resolved theme - which palette + mode combination to display */ export type Theme = @@ -14,10 +14,6 @@ export type Theme = /** @deprecated Use classic-dark */ | 'dark' -/** True for the Neue (default) palette, whose tokens v2 styling skips Classic and Matrix. */ -export const isNeueTheme = (theme: Theme) => - theme === 'default-light' || theme === 'default-dark' - /** Theme palette - selected in dropdown (default, classic, matrix) */ export type ThemePalette = 'default' | 'classic' | 'matrix' diff --git a/packages/harmony/src/foundations/typography/fonts.css b/packages/harmony/src/foundations/typography/fonts.css index b05f3f017af..1776cc6ba52 100644 --- a/packages/harmony/src/foundations/typography/fonts.css +++ b/packages/harmony/src/foundations/typography/fonts.css @@ -1,17 +1,12 @@ /** * Audius Type System * - * When using, ensure the Inter Variable and Bricolage Grotesque Variable - * font-faces are available (web loads them from @fontsource-variable). - * Without them, harmony.css falls back to its bundled Avenir. + * When using, ensure that the Avenir Next LT Pro font-face is available. */ :root, root { - --harmony-font-family: 'Inter Variable', Inter, 'Avenir Next LT Pro', - -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - --harmony-font-family-display: 'Bricolage Grotesque Variable', - 'Bricolage Grotesque', 'Inter Variable', Inter, 'Avenir Next LT Pro', - sans-serif; + --harmony-font-family: 'Avenir Next LT Pro', 'Helvetica Neue', Helvetica, + Arial, sans-serif; /* Font Sizes */ --harmony-font-2xs: 10px; diff --git a/packages/harmony/src/foundations/typography/typography.ts b/packages/harmony/src/foundations/typography/typography.ts index 4a80324d058..ee107e24aee 100644 --- a/packages/harmony/src/foundations/typography/typography.ts +++ b/packages/harmony/src/foundations/typography/typography.ts @@ -1,12 +1,5 @@ export const typography = { - /** - * UI text face. Loaded by the app (web: @fontsource-variable/inter). Apps on - * harmony.css without Inter fall back to its bundled Avenir. - */ - font: "'Inter Variable', Inter, 'Avenir Next LT Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif", - /** Display face for page titles and display text. */ - fontDisplay: - "'Bricolage Grotesque Variable', 'Bricolage Grotesque', 'Inter Variable', Inter, 'Avenir Next LT Pro', sans-serif", + font: "'Avenir Next LT Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif", weight: { ultraLight: 100, thin: 200, diff --git a/packages/harmony/src/index.ts b/packages/harmony/src/index.ts index a4ca5b822f7..2a16cba4aea 100644 --- a/packages/harmony/src/index.ts +++ b/packages/harmony/src/index.ts @@ -1,4 +1,5 @@ import './foundations/reset/reset.css' +import './foundations/typography/avenir.css' import './foundations/typography/fonts.css' import './foundations/spacing/spacing.css' import './foundations/color/primitive.css' diff --git a/packages/harmony/turbo.json b/packages/harmony/turbo.json index 6f86f68d850..fad3c40cba1 100644 --- a/packages/harmony/turbo.json +++ b/packages/harmony/turbo.json @@ -2,13 +2,8 @@ "extends": ["//"], "tasks": { "build:css": { - "inputs": [ - "src/css-entry.ts", - "src/foundations/**/*.css", - "rollup.css.config.mjs", - "rollup.fonts.mjs" - ], - "outputs": ["dist/harmony.css", "dist/harmony-no-fonts.css"], + "inputs": ["src/css-entry.ts", "src/foundations/**/*.css"], + "outputs": ["dist/harmony.css"], "outputLogs": "new-only" }, "test": { diff --git a/packages/mobile/src/harmony-native/components/Text/Text.tsx b/packages/mobile/src/harmony-native/components/Text/Text.tsx index cf13f49fcc7..a23fd4d6b63 100644 --- a/packages/mobile/src/harmony-native/components/Text/Text.tsx +++ b/packages/mobile/src/harmony-native/components/Text/Text.tsx @@ -6,7 +6,6 @@ import { bodyLineHeightMap } from '@audius/harmony/src/components/text/constants' import { TextContext } from '@audius/harmony/src/components/text/textContext' -import { isNeueTheme } from '@audius/harmony/src/foundations/theme/types' import { css } from '@emotion/native' import type { TextProps as NativeTextProps, TextStyle } from 'react-native' import { Platform, Text as TextBase } from 'react-native' @@ -43,9 +42,9 @@ export const Text = forwardRef((props, ref) => { const parentVariant = contextVariant && !variantProp const strength = strengthProp ?? (parentVariant ? undefined : 'default') const size = sizeProp ?? (parentVariant ? undefined : 'm') - // Classic and Matrix headings are a gradient on web; native uses the accent. + // TODO: make heading a proper gradient const color = - colorProp === 'heading' && !isNeueTheme(theme.type) + colorProp === 'heading' ? theme.color.secondary.secondary : theme.color.text[colorProp] diff --git a/packages/web/index.html b/packages/web/index.html index 0b872260e74..841990b89de 100644 --- a/packages/web/index.html +++ b/packages/web/index.html @@ -7,8 +7,28 @@ - + + + + diff --git a/packages/web/package.json b/packages/web/package.json index 0ecebc2eabc..485a62fec3d 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -79,8 +79,6 @@ "@emotion/react": "11.14.0", "@emotion/server": "11.11.0", "@emotion/styled": "11.14.0", - "@fontsource-variable/bricolage-grotesque": "^5.3.0", - "@fontsource-variable/inter": "^5.3.0", "@google/model-viewer": "3.3.0", "@hcaptcha/react-hcaptcha": "0.3.6", "@juggle/resize-observer": "^3.3.1", diff --git a/packages/web/public/fonts.css b/packages/web/public/fonts.css index 99e1575dcca..ad0b86ac4ea 100644 --- a/packages/web/public/fonts.css +++ b/packages/web/public/fonts.css @@ -1,8 +1,8 @@ /** * Avenir Next LT Pro * - * Fallback behind Inter. Each weight is a separate woff2 file, so browsers - * only download the weights a page renders. + * Each weight is a separate woff2 file, so browsers only download the + * weights a page renders. */ @font-face { diff --git a/packages/web/src/Root.tsx b/packages/web/src/Root.tsx index 8e515a9fec5..a844295ce62 100644 --- a/packages/web/src/Root.tsx +++ b/packages/web/src/Root.tsx @@ -1,6 +1,4 @@ -import '@audius/harmony/dist/harmony-no-fonts.css' -import '@fontsource-variable/inter' -import '@fontsource-variable/bricolage-grotesque' +import '@audius/harmony/dist/harmony.css' import { Suspense, useState, useEffect, lazy } from 'react' diff --git a/packages/web/src/app/web-player/ServerWebPlayer.tsx b/packages/web/src/app/web-player/ServerWebPlayer.tsx index 2ff1b2476d3..57a9ac2ac00 100644 --- a/packages/web/src/app/web-player/ServerWebPlayer.tsx +++ b/packages/web/src/app/web-player/ServerWebPlayer.tsx @@ -1,9 +1,7 @@ import { ReactElement } from 'react' import imageProfilePicEmpty from '@audius/common/src/assets/img/imageProfilePicEmpty2X.png' -import '@audius/harmony/dist/harmony-no-fonts.css' -import '@fontsource-variable/inter' -import '@fontsource-variable/bricolage-grotesque' +import '@audius/harmony/dist/harmony.css' import IconAudiusLogoHorizontal from '@audius/harmony/src/assets/icons/AudiusLogoHorizontal.svg' import IconExplore from '@audius/harmony/src/assets/icons/Explore.svg' import IconFeed from '@audius/harmony/src/assets/icons/Feed.svg' diff --git a/packages/web/src/components/edit/fields/DatePickerField.module.css b/packages/web/src/components/edit/fields/DatePickerField.module.css index a51a4b3d36a..478b79eaf46 100644 --- a/packages/web/src/components/edit/fields/DatePickerField.module.css +++ b/packages/web/src/components/edit/fields/DatePickerField.module.css @@ -64,7 +64,7 @@ .reactDatepicker :global(.react-datepicker__current-month) { color: var(--harmony-neutral) !important; - font-family: var(--harmony-font-family) !important; + font-family: Avenir Next LT Pro !important; font-size: 20px !important; font-weight: var(--harmony-font-demi-bold) !important; margin-bottom: 0.5rem !important; diff --git a/packages/web/src/components/nav/desktop/CollapsedNavItem.tsx b/packages/web/src/components/nav/desktop/CollapsedNavItem.tsx index c965ffe885b..67e0a0b7899 100644 --- a/packages/web/src/components/nav/desktop/CollapsedNavItem.tsx +++ b/packages/web/src/components/nav/desktop/CollapsedNavItem.tsx @@ -1,4 +1,4 @@ -import { Flex, isNeueTheme, NotificationCount, useTheme } from '@audius/harmony' +import { Flex, NotificationCount, useTheme } from '@audius/harmony' import type { IconComponent } from '@audius/harmony' type CollapsedNavItemProps = { @@ -18,15 +18,9 @@ export const CollapsedNavItem = ({ onClick, isFocusVisible = false }: CollapsedNavItemProps) => { - const { color, motion, type } = useTheme() - const isNeue = isNeueTheme(type) + const { color, motion } = useTheme() - const backgroundColor = isSelected - ? isNeue - ? color.background.surface2 - : color.secondary.s400 - : undefined - const iconColor = isSelected && !isNeue ? 'white' : 'default' + const backgroundColor = isSelected ? color.secondary.s400 : undefined const insetBorderColor = isSelected ? 'none' : `inset 0 0 0 1px ${color.border.default}` @@ -67,11 +61,11 @@ export const CollapsedNavItem = ({ }} > {hasNotification ? ( - - + + ) : ( - + )} diff --git a/packages/web/src/components/user-balance-history-graph/UserBalanceHistoryGraph.module.css b/packages/web/src/components/user-balance-history-graph/UserBalanceHistoryGraph.module.css index 956251a6a73..1a92a34f7f1 100644 --- a/packages/web/src/components/user-balance-history-graph/UserBalanceHistoryGraph.module.css +++ b/packages/web/src/components/user-balance-history-graph/UserBalanceHistoryGraph.module.css @@ -22,7 +22,7 @@ } .tooltipDate { - font-family: var(--harmony-font-family); + font-family: 'Avenir Next LT Pro', sans-serif; font-size: 12px; font-weight: 700; line-height: 16px; @@ -31,7 +31,7 @@ } .tooltipValue { - font-family: var(--harmony-font-family); + font-family: 'Avenir Next LT Pro', sans-serif; font-size: 18px; font-weight: 700; line-height: 24px; diff --git a/packages/web/src/utils/animations/music-confetti.js b/packages/web/src/utils/animations/music-confetti.js index c9a9a4cbfa1..49673251e33 100644 --- a/packages/web/src/utils/animations/music-confetti.js +++ b/packages/web/src/utils/animations/music-confetti.js @@ -95,7 +95,7 @@ class Particle { const heightMultipler = this.y / 100 // Draw the letter - ctx.font = "14px 'Inter Variable', Inter, sans-serif" + ctx.font = '14px Avenir Next LT Pro' ctx.fillStyle = 'rgba(12, 241, 12, 1)' ctx.fillText(this.randomLetter, 0, 0)