Prepare product layout and reusable Flutter theme #7

Merged
tech merged 1 commits from theme-1 into main 2026-09-11 13:45:28 +00:00
46 changed files with 703 additions and 1 deletions

No files matched your search

+2 -1
View File
@@ -2,7 +2,8 @@
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"command": "npm run dev -- --background",
"cwd": "${workspaceFolder}/website",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
+14
View File
@@ -0,0 +1,14 @@
# SXCHNGE backend
Reserved for a small backend for frontend (BFF) using a supported Sendico API. No service, runtime, or dependencies have been initialized yet.
Planned responsibilities:
- Consumer authentication and sessions, with a stable mapping to organization-scoped Sendico customer references.
- Consumer-authorized access to onboarding, quotes, orders, and transaction history.
- Product-specific orchestration and presentation of Sendico KYC, eligibility, and remaining-limit responses.
- Server-side integration credentials and request correlation with Sendico.
Sendico owns payment execution, authoritative KYC evidence and verification records, policy evaluation, and limit reservations/enforcement. Do not copy its existing BFF or import local Sendico implementation modules.
Before implementation, agree on customer registration and identity mapping, customer KYC operations, eligibility/limits reads, customer-scoped payment access, and retry/idempotency behavior. Validate consumer isolation even when multiple customers use the same sxchnge organization and integration principal.
+13
View File
@@ -0,0 +1,13 @@
# SXCHNGE frontend
Home for the consumer application and its Flutter packages. The existing public Astro website lives in [`../website/`](../website/README.md).
The first package, [`sxchnge_theme`](packages/sxchnge_theme/README.md), provides installable light/dark Material themes and bundled Onest fonts. Its `example/` folder demonstrates installation and component styling. The consumer application in [`app/`](app/README.md) now includes a responsive login/sign-up preview; backend authentication is not connected.
The application will provide consumer registration, sign-in, onboarding and verification screens, exchange flows, and transaction history through the sxchnge backend. Eligibility and remaining limits are projections of Sendico's authoritative decisions.
Flutter is anticipated by the existing website handoff. Optional brand references are in [`../website/design/`](../website/design/README.md) and [`../website/flutter/brand_palette.dart`](../website/flutter/brand_palette.dart); these do not prescribe the application's component styling.
Define the first customer journey and BFF contract before scaffolding the application. Sendico integration credentials belong in the backend.
Shared authentication: [`sxchnge_auth`](packages/sxchnge_auth/README.md) provides reusable login/signup providers, service contracts, and dummy implementations for both web and future mobile clients.
@@ -0,0 +1,5 @@
.dart_tool/
.flutter-plugins-dependencies
build/
pubspec.lock
example/pubspec.lock
@@ -0,0 +1,5 @@
## 0.1.0
- Introduce light and dark Material themes derived from the SXCHNGE website.
- Bundle Onest with its SIL Open Font License.
- Export brand colors and theme factories.
+58
View File
@@ -0,0 +1,58 @@
# sxchnge_theme
Installable SXCHNGE theme package for Flutter 3.47+ / Dart 3.13+. It provides light and dark Material 3 themes, website brand colors, and bundled Onest typography with Latin and Cyrillic support. No runtime network requests or third-party packages are needed.
## Install
From an application at `frontend/app`, add:
```yaml
dependencies:
flutter:
sdk: flutter
sxchnge_theme:
path: ../packages/sxchnge_theme
```
Adjust the path relative to your app's `pubspec.yaml`, then run `flutter pub get`. This is a private package (`publish_to: none`), ready for local use; it has not been published to pub.dev.
## Apply
```dart
import 'package:flutter/material.dart';
import 'package:sxchnge_theme/sxchnge_theme.dart';
MaterialApp(
theme: SxchngeTheme.light(),
darkTheme: SxchngeTheme.dark(),
themeMode: ThemeMode.system,
home: const Scaffold(body: Center(child: Text('Hello, sxchnge'))),
);
```
Onest is declared by the package and the theme uses its package-qualified font family, so the consuming app needs no additional font declarations. The bundled SIL Open Font License is in `assets/fonts/OFL.txt`. Follow Flutter's [TextStyle package font guidance](https://api.flutter.dev/flutter/painting/TextStyle/package.html) when creating standalone text styles outside the theme.
Use `Theme.of(context).colorScheme` and `textTheme` for normal application widgets. `SxchngeBrand` exposes the original palette for intentional brand treatments. Customize locally with `SxchngeTheme.light().copyWith(...)`.
## Design mapping
- Ink, mint, lime, paper, and forest match `website/design/tokens.json` version 1.
- Light mode uses ink actions on paper; dark mode uses mint actions on ink.
- Mint and lime containers use ink foregrounds. Lime is a brand accent, not a success or transaction status.
- Onest body text starts at 16 logical pixels, with 14-pixel secondary text. Text scaling is preserved.
- Cards and dialogs use 24-pixel corners, fields use 14-pixel corners, and buttons use pill shapes with at least 48-pixel minimum height.
- Error colors remain Material semantic roles. A future product status system should define success, warning, and information roles separately.
The palette is a package-owned snapshot: website builds do not modify this package. Deliberate brand updates should update the snapshot and package version together. Campaign layout, rotation, marquee, and decorative motion are not part of the application theme.
## Example and validation
`example/lib/main.dart` is a minimal consumer gallery with English/Russian text, cards, inputs, validation errors, and enabled/disabled buttons. To launch it, generate the platform runner you need from `example/`, for example `flutter create --platforms=web .`, then `flutter run -d chrome`. Platform runners are not included in this theme-only package.
From the repository root:
```sh
make test-frontend
```
From this package and its `example/` folder, run `flutter analyze`. Tests cover core brand synchronization in this repository, foreground contrast in both modes, package font/license bundling in an independent consumer, and rendering/input on a narrow screen at 200% text scale.
File renamed without changes.
@@ -0,0 +1,77 @@
import 'package:flutter/material.dart';
import 'package:sxchnge_theme/sxchnge_theme.dart';
void main() => runApp(const ThemeExample());
class ThemeExample extends StatelessWidget {
const ThemeExample({super.key, this.mode = ThemeMode.system});
final ThemeMode mode;
@override
Widget build(BuildContext context) => MaterialApp(
debugShowCheckedModeBanner: false,
theme: SxchngeTheme.light(),
darkTheme: SxchngeTheme.dark(),
themeMode: mode,
home: const _Gallery(),
);
}
class _Gallery extends StatelessWidget {
const _Gallery();
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(title: const Text('sxchnge')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 560),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Your next exchange',
style: Theme.of(context).textTheme.headlineLarge,
),
const SizedBox(height: 16),
const Text(
'Обмен без лишних шагов.\nA preview of the SXCHNGE theme.',
),
const SizedBox(height: 24),
const Card(
child: Padding(
padding: EdgeInsets.all(24),
child: Text('Clear amounts. Clear choices.'),
),
),
const SizedBox(height: 24),
const TextField(
decoration: InputDecoration(
labelText: 'Amount',
hintText: '0.00',
),
),
const SizedBox(height: 16),
const TextField(
decoration: InputDecoration(
labelText: 'Email',
errorText: 'Enter a valid email address',
),
),
const SizedBox(height: 24),
FilledButton(onPressed: () {}, child: const Text('Continue')),
const SizedBox(height: 12),
OutlinedButton(onPressed: () {}, child: const Text('Back')),
const SizedBox(height: 12),
const FilledButton(onPressed: null, child: Text('Unavailable')),
],
),
),
),
),
);
}
@@ -0,0 +1,15 @@
name: sxchnge_theme_example
description: Minimal consumer and component gallery for the SXCHNGE theme.
publish_to: none
environment:
sdk: '>=3.13.0 <4.0.0'
dependencies:
flutter:
sdk: flutter
sxchnge_theme:
path: ../
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
@@ -0,0 +1,51 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:sxchnge_theme_example/main.dart';
void main() {
testWidgets('consumer bundles the package font and its license', (
tester,
) async {
await tester.pumpWidget(const ThemeExample());
final manifest =
jsonDecode(await rootBundle.loadString('FontManifest.json')) as List;
final family = manifest.cast<Map>().singleWhere(
(font) => font['family'] == 'packages/sxchnge_theme/Onest',
);
final asset = (family['fonts'] as List).first['asset'] as String;
expect((await rootBundle.load(asset)).lengthInBytes, greaterThan(1000));
expect(
await rootBundle.loadString(
'packages/sxchnge_theme/assets/fonts/OFL.txt',
),
contains('SIL OPEN FONT LICENSE'),
);
});
for (final mode in [ThemeMode.light, ThemeMode.dark]) {
testWidgets(
'$mode renders on a narrow screen with large text and accepts input',
(tester) async {
tester.view.physicalSize = const Size(320, 900);
tester.view.devicePixelRatio = 1;
tester.platformDispatcher.textScaleFactorTestValue = 2;
addTearDown(tester.view.resetPhysicalSize);
addTearDown(tester.view.resetDevicePixelRatio);
addTearDown(tester.platformDispatcher.clearTextScaleFactorTestValue);
await tester.pumpWidget(ThemeExample(mode: mode));
await tester.pumpAndSettle();
expect(tester.takeException(), isNull);
await tester.enterText(find.byType(TextField).first, '125.50');
expect(find.text('125.50'), findsOneWidget);
await tester.ensureVisible(find.text('Continue'));
await tester.pumpAndSettle();
expect(tester.takeException(), isNull);
},
);
}
}
@@ -0,0 +1,19 @@
// Brand snapshot from website/design/tokens.json (version 1).
// Keep these values aligned when deliberately updating the package's brand.
import 'dart:ui';
abstract final class SxchngeBrand {
static const ink = Color(0xFF14221D);
static const mint = Color(0xFFC4F9CE);
static const lime = Color(0xFFD7FF5F);
static const paper = Color(0xFFF9FAF6);
static const muted = Color(0xFF637168);
static const line = Color(0xFFD9E0D8);
static const forest = Color(0xFF396A4B);
static const focus = Color(0xFF168850);
static const darkField = Color(0xFF25372E);
static const darkReceive = Color(0xFF203D2D);
static const sageSurface = Color(0xFFEAF0E6);
static const blueSurface = Color(0xFFEDF0F9);
static const fontFamily = 'Onest';
}
@@ -0,0 +1,203 @@
import 'package:flutter/material.dart';
import 'brand.dart';
/// Install with `MaterialApp(theme: SxchngeTheme.light(),
/// darkTheme: SxchngeTheme.dark())`.
abstract final class SxchngeTheme {
static const packageName = 'sxchnge_theme';
static ThemeData light() => _build(Brightness.light);
static ThemeData dark() => _build(Brightness.dark);
static ThemeData _build(Brightness brightness) {
final dark = brightness == Brightness.dark;
// Seed supplies complete Material roles; explicit overrides preserve brand
// colors and readable foregrounds rather than approximating the palette.
final scheme =
ColorScheme.fromSeed(
seedColor: SxchngeBrand.forest,
brightness: brightness,
).copyWith(
primary: dark ? SxchngeBrand.mint : SxchngeBrand.ink,
onPrimary: dark ? SxchngeBrand.ink : SxchngeBrand.mint,
primaryContainer: SxchngeBrand.mint,
onPrimaryContainer: SxchngeBrand.ink,
secondary: dark ? SxchngeBrand.mint : SxchngeBrand.forest,
onSecondary: dark ? SxchngeBrand.ink : SxchngeBrand.paper,
secondaryContainer: dark
? SxchngeBrand.darkReceive
: SxchngeBrand.sageSurface,
onSecondaryContainer: dark ? SxchngeBrand.mint : SxchngeBrand.ink,
tertiary: dark ? SxchngeBrand.lime : SxchngeBrand.forest,
onTertiary: dark ? SxchngeBrand.ink : SxchngeBrand.paper,
tertiaryContainer: SxchngeBrand.lime,
onTertiaryContainer: SxchngeBrand.ink,
surface: dark ? SxchngeBrand.ink : SxchngeBrand.paper,
onSurface: dark ? SxchngeBrand.paper : SxchngeBrand.ink,
onSurfaceVariant: dark ? const Color(0xFFB6C6B9) : SxchngeBrand.muted,
surfaceContainerLowest: dark ? const Color(0xFF101B17) : Colors.white,
surfaceContainerLow: dark
? const Color(0xFF1B2B23)
: SxchngeBrand.paper,
surfaceContainer: dark
? SxchngeBrand.darkField
: SxchngeBrand.sageSurface,
surfaceContainerHigh: dark
? SxchngeBrand.darkReceive
: SxchngeBrand.line,
surfaceContainerHighest: dark
? const Color(0xFF324A3C)
: const Color(0xFFCFD9CE),
outline: dark ? const Color(0xFF8CA291) : SxchngeBrand.muted,
outlineVariant: dark ? const Color(0xFF405A48) : SxchngeBrand.line,
inverseSurface: dark ? SxchngeBrand.paper : SxchngeBrand.ink,
onInverseSurface: dark ? SxchngeBrand.ink : SxchngeBrand.paper,
inversePrimary: dark ? SxchngeBrand.forest : SxchngeBrand.mint,
surfaceTint: Colors.transparent,
);
final base = ThemeData(
useMaterial3: true,
colorScheme: scheme,
fontFamily: SxchngeBrand.fontFamily,
package: packageName,
scaffoldBackgroundColor: scheme.surface,
visualDensity: VisualDensity.standard,
materialTapTargetSize: MaterialTapTargetSize.padded,
);
final text = base.textTheme.copyWith(
displayLarge: base.textTheme.displayLarge!.copyWith(
fontSize: 48,
fontWeight: FontWeight.w600,
letterSpacing: -2,
height: 1.1,
),
displayMedium: base.textTheme.displayMedium!.copyWith(
fontSize: 40,
fontWeight: FontWeight.w600,
letterSpacing: -1.5,
height: 1.15,
),
displaySmall: base.textTheme.displaySmall!.copyWith(
fontSize: 36,
fontWeight: FontWeight.w600,
letterSpacing: -1,
height: 1.2,
),
headlineLarge: base.textTheme.headlineLarge!.copyWith(
fontWeight: FontWeight.w600,
letterSpacing: -1,
),
headlineMedium: base.textTheme.headlineMedium!.copyWith(
fontWeight: FontWeight.w600,
letterSpacing: -0.5,
),
headlineSmall: base.textTheme.headlineSmall!.copyWith(
fontWeight: FontWeight.w600,
),
bodyLarge: base.textTheme.bodyLarge!.copyWith(fontSize: 16, height: 1.65),
bodyMedium: base.textTheme.bodyMedium!.copyWith(
fontSize: 16,
height: 1.5,
),
bodySmall: base.textTheme.bodySmall!.copyWith(fontSize: 14, height: 1.5),
labelLarge: base.textTheme.labelLarge!.copyWith(
fontSize: 16,
fontWeight: FontWeight.w600,
),
labelMedium: base.textTheme.labelMedium!.copyWith(
fontSize: 14,
fontWeight: FontWeight.w600,
),
labelSmall: base.textTheme.labelSmall!.copyWith(fontSize: 14),
);
final border = OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: BorderSide(color: scheme.outline),
);
return base.copyWith(
textTheme: text,
appBarTheme: AppBarThemeData(
backgroundColor: scheme.surface,
foregroundColor: scheme.onSurface,
surfaceTintColor: Colors.transparent,
elevation: 0,
centerTitle: false,
titleTextStyle: text.titleLarge,
),
cardTheme: CardThemeData(
color: scheme.surfaceContainer,
elevation: 0,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
),
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
minimumSize: const Size(64, 48),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
shape: const StadiumBorder(),
textStyle: text.labelLarge,
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
minimumSize: const Size(64, 48),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
shape: const StadiumBorder(),
textStyle: text.labelLarge,
elevation: 0,
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
minimumSize: const Size(64, 48),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
shape: const StadiumBorder(),
textStyle: text.labelLarge,
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
minimumSize: const Size(48, 48),
textStyle: text.labelLarge,
),
),
inputDecorationTheme: InputDecorationThemeData(
filled: true,
fillColor: scheme.surfaceContainerLowest,
contentPadding: const EdgeInsets.all(16),
border: border,
enabledBorder: border,
focusedBorder: border.copyWith(
borderSide: BorderSide(
color: dark ? SxchngeBrand.mint : SxchngeBrand.focus,
width: 2,
),
),
errorBorder: border.copyWith(
borderSide: BorderSide(color: scheme.error),
),
focusedErrorBorder: border.copyWith(
borderSide: BorderSide(color: scheme.error, width: 2),
),
),
dialogTheme: DialogThemeData(
backgroundColor: scheme.surface,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
),
dividerTheme: DividerThemeData(
color: scheme.outlineVariant,
thickness: 1,
),
navigationBarTheme: NavigationBarThemeData(
backgroundColor: scheme.surface,
indicatorColor: scheme.primaryContainer,
),
textSelectionTheme: TextSelectionThemeData(
cursorColor: scheme.primary,
selectionColor: SxchngeBrand.lime.withValues(alpha: dark ? 0.3 : 0.5),
selectionHandleColor: scheme.primary,
),
);
}
}
@@ -0,0 +1,5 @@
/// SXCHNGE brand colors, typography, and Material themes.
library;
export 'src/brand.dart';
export 'src/theme.dart';
@@ -0,0 +1,24 @@
name: sxchnge_theme
description: SXCHNGE Material theme and bundled Onest typography for Flutter apps.
version: 0.1.0
publish_to: none
environment:
sdk: '>=3.13.0 <4.0.0'
flutter: '>=3.47.0'
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
assets:
- assets/fonts/OFL.txt
fonts:
- family: Onest
fonts:
- asset: assets/fonts/Onest-Variable.ttf
@@ -0,0 +1,65 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:sxchnge_theme/sxchnge_theme.dart';
double contrast(Color a, Color b) {
final x = a.computeLuminance();
final y = b.computeLuminance();
return (math.max(x, y) + 0.05) / (math.min(x, y) + 0.05);
}
void main() {
test('website core colors stay aligned with the package snapshot', () {
final source = File('../../../website/design/tokens.json');
if (!source.existsSync())
return; // Also allow testing outside this monorepo.
final colors =
(jsonDecode(source.readAsStringSync()) as Map)['colors'] as Map;
for (final entry in {
'ink': SxchngeBrand.ink,
'mint': SxchngeBrand.mint,
'lime': SxchngeBrand.lime,
'paper': SxchngeBrand.paper,
'forest': SxchngeBrand.forest,
}.entries) {
expect(
entry.value.toARGB32(),
int.parse('ff${(colors[entry.key] as String).substring(1)}', radix: 16),
);
}
});
for (final dark in [false, true]) {
final theme = dark ? SxchngeTheme.dark() : SxchngeTheme.light();
test(
'${dark ? "dark" : "light"} foreground pairs meet normal text contrast',
() {
final c = theme.colorScheme;
for (final pair in [
(c.primary, c.onPrimary),
(c.primaryContainer, c.onPrimaryContainer),
(c.secondary, c.onSecondary),
(c.secondaryContainer, c.onSecondaryContainer),
(c.tertiary, c.onTertiary),
(c.tertiaryContainer, c.onTertiaryContainer),
(c.surface, c.onSurface),
(c.surface, c.onSurfaceVariant),
(c.error, c.onError),
(c.errorContainer, c.onErrorContainer),
]) {
expect(contrast(pair.$1, pair.$2), greaterThanOrEqualTo(4.5));
}
expect(
theme.textTheme.bodyMedium!.fontFamily,
'packages/sxchnge_theme/Onest',
);
},
);
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+24
View File
@@ -0,0 +1,24 @@
## Development
The public Astro site is in `website/`. Run its npm and Astro commands from that folder. `frontend/` and `backend/` are reserved for the new consumer application and BFF.
When starting the dev server, use background mode:
```
astro dev --background
```
Manage the background server with `astro dev stop`, `astro dev status`, and `astro dev logs`.
## Documentation
Full documentation: https://docs.astro.build
Consult these guides before working on related tasks:
- [Adding pages, dynamic routes, or middleware](https://docs.astro.build/en/guides/routing/)
- [Working with Astro components](https://docs.astro.build/en/basics/astro-components/)
- [Using React, Vue, Svelte, or other framework components](https://docs.astro.build/en/guides/framework-components/)
- [Adding or managing content](https://docs.astro.build/en/guides/content-collections/)
- [Adding styles or using Tailwind](https://docs.astro.build/en/guides/styling/)
- [Supporting multiple languages](https://docs.astro.build/en/guides/internationalization/)
+30
View File
@@ -0,0 +1,30 @@
# SXCHNGE
Astro public website for a crypto-to-fiat exchange. English and Russian, responsive layouts, an illustrative exchange calculator, and explicit company / policy placeholders.
## Development
Node >=22.12.0 (Node >=22.18 for the native TypeScript test runner), npm.
Run these commands from `website/` (use `cd website` from the repository root).
```sh
npm ci
npm run dev -- --background --host 127.0.0.1
npm run test
npm run build
```
Use `npm exec astro dev stop` to stop the background preview. Static output is `dist/`. `/` redirects to `/en/`; localized content lives at `/en/` and `/ru/`. Legal placeholders have separate localized routes.
## Content and launch configuration
- Translation source: `src/i18n/copy.ts`.
- Brand reference: `design/tokens.json`, documented in `design/README.md`.
- Optional Flutter palette reference: `flutter/brand_palette.dart`. Compatibility does not require identical application styling.
- Full account URLs: set `PUBLIC_FLUTTER_REGISTER_URL` and `PUBLIC_FLUTTER_LOGIN_URL` at build time, as shown in `.env.example`. Locale is appended as `lang`. Until configured, actions open a clear preview dialog; no credentials are collected.
- Quote fixtures: `src/lib/quote.ts`. Demo only; no rates are fetched, orders placed, or funds handled.
- Replace all company placeholders, supply approved legal policies, and confirm supported assets, payout methods, countries, fees and timelines before launch.
- The preview explicitly uses `noindex,nofollow`. Remove only when launch content is complete, and set the real domain in `astro.config.mjs`.
Fonts are self-hosted with their license. No analytics, third-party trackers, client storage, or authentication backend is included. The website uses Astro's own TypeScript script support; React is unnecessary for the current interactions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
View File
File renamed without changes.
File renamed without changes.
File renamed without changes.
+93
View File
@@ -0,0 +1,93 @@
Copyright 2021 The Onest Project Authors (https://github.com/googlefonts/onest)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.