Proposal: Establishing a Unified Front-End Architecture & Design System for the ODE Ecosystem #29
Replies: 5 comments 5 replies
-
|
@IamLRBA Thank you so much for putting together this very detailed and thoughtful proposal. I may not be a front-end architecture expert, but I really appreciate the effort, clarity, and depth you brought into outlining the current gaps and proposing this. From my perspective, here are a few things I strongly agree with and want to highlight:
I truly appreciate the initiative here. Even though I’m not a front-end architecture specialist, I can clearly see the value this will bring to the stability, identity, and long-term maintainability of all ODE applications. I support this proposal and look forward to collaborating and learning through the process. Thanks again for starting this important discussion. |
Beta Was this translation helpful? Give feedback.
-
|
@IamLRBA Thank you! This is indeed a very thoughtful proposal and I completely agree that this would be very valuable for our project. formulus-formplayerSo we are using React "web" here, for a couple of reasons - that perhaps we could re-assess the validity of..
On the other hand, it also has some benefits in terms of future features I for one would love to see in ODE:
Component libraryI really like that idea as well - especially if supported by something like storybook/ladle as you mentioned. However, I also agree that a phased approach is probably the best way to implement this.. Thanks again and looking forward to discussing this! |
Beta Was this translation helpful? Give feedback.
-
|
One more thought: Perhaps we should consider styling the forum to try to match our unified styling as well? I will have look at possible flarum extensions later today to see what's possible to achieve with a reasonable effort :-) |
Beta Was this translation helpful? Give feedback.
-
ODE DESIGN SYSTEM - DESIGN TOKEN SPECIFICATION1. COLOR TOKENS1.1 Brand ColorsBased on ODE Logo Colors
1.2 Complete Color PaletteBrand Primary (Green) Scale:
Brand Secondary (Gold) Scale:
1.3 Semantic ColorsSuccess States:
Error States:
Warning States:
Info States:
1.4 Neutral ColorsGray Scale:
1.5 Opacity & Alpha Tokens
Using Opacity with Colors:/* Modal backdrop - semi-transparent black */
.modal-backdrop {
background-color: rgba(0, 0, 0, var(--opacity-60)); /* 60% black */
}
/* Disabled button - primary color at 40% opacity */
.button-disabled {
background-color: color-mix(in srgb, var(--color-brand-primary-500) var(--opacity-40), transparent);
opacity: var(--opacity-40);
}1.6 Dark Mode Color TokensDark Mode Color Mapping:
Dark Mode Example:/* Automatically switches based on system preference */
.card {
background-color: var(--color-background-primary);
color: var(--color-text-primary);
border-color: var(--color-border-default);
}
/* Or force dark mode */
@media (prefers-color-scheme: dark) {
.card {
background-color: var(--color-background-primary-dark);
color: var(--color-text-primary-dark);
}
}1.7 Application Examples/* Using the color tokens */
.primary-button {
background-color: var(--color-brand-primary-500); /* #4F7F4E */
color: var(--color-neutral-white); /* #FFFFFF */
}
.error-message {
color: var(--color-semantic-error-500); /* #F44336 */
background-color: var(--color-semantic-error-50); /* #FEF2F2 */
}
/* Using opacity */
.overlay {
background-color: rgba(0, 0, 0, var(--opacity-50));
}2. TYPOGRAPHY TOKENS2.1 Font Families
2.2 Font Size Scale (Base: 16px)
2.3 Font Weights
2.4 Line Heights
2.5 Letter Spacing
2.6 Text Decoration & Transform
2.7 Text Styles (Predefined Combinations)Heading Styles:/* H1 - Page Title */
h1 {
font-size: var(--font-size-5xl); /* 48px */
font-weight: var(--font-weight-bold); /* 700 */
line-height: var(--line-height-tight); /* 1.25 */
}
/* Body Text - Regular */
.body-text {
font-size: var(--font-size-base); /* 16px */
font-weight: var(--font-weight-regular); /* 400 */
line-height: var(--line-height-normal); /* 1.5 */
}
/* Caption - Small Text */
.caption {
font-size: var(--font-size-xs); /* 12px */
font-weight: var(--font-weight-regular); /* 400 */
line-height: var(--line-height-normal); /* 1.5 */
}3. LAYOUT & RESPONSIVE TOKENS3.1 BreakpointsWhat are breakpoints? Screen width sizes where the design changes layout. Like when a phone layout switches to tablet or desktop layout.
Breakpoint Usage:/* Mobile-first approach */
.container {
padding: var(--spacing-4); /* Default: mobile */
}
/* Tablet and up */
@media (min-width: var(--breakpoint-md)) {
.container {
padding: var(--spacing-6);
}
}
/* Desktop and up */
@media (min-width: var(--breakpoint-lg)) {
.container {
padding: var(--spacing-8);
}
}3.2 Container Max Widths
Container Example:.container {
width: 100%;
max-width: var(--container-xl); /* 1280px */
margin: 0 auto; /* Centers the container */
padding: var(--spacing-4);
}3.3 Grid System
Grid Example:.grid {
display: grid;
grid-template-columns: repeat(var(--grid-columns), 1fr);
gap: var(--grid-gutter);
}
/* Item spans 6 columns (half width) */
.grid-item-half {
grid-column: span 6;
}
/* Item spans 4 columns (one-third width) */
.grid-item-third {
grid-column: span 4;
}4. SPACING TOKENS3.1 Base Unit System
3.2 Spacing Scale
3.3 Spacing Examples/* Button spacing */
.button {
padding: var(--spacing-3) var(--spacing-6); /* 12px 24px */
margin-bottom: var(--spacing-4); /* 16px */
}
/* Card spacing */
.card {
padding: var(--spacing-6); /* 24px */
margin: var(--spacing-4); /* 16px */
gap: var(--spacing-4); /* 16px between items */
}
/* Layout spacing */
.container {
padding: var(--spacing-8); /* 32px */
max-width: var(--container-max-width-xl); /* 1280px */
}5. ICON & ASSET TOKENS5.1 Icon Sizes
Icon Size Example:.button-icon {
width: var(--icon-md); /* 20px */
height: var(--icon-md); /* 20px */
}
.navigation-icon {
width: var(--icon-lg); /* 24px */
height: var(--icon-lg); /* 24px */
}5.2 Icon Stroke Width
5.3 Avatar Sizes
5.4 Logo Sizes
6. BORDER TOKENS4.1 Border Radius
4.2 Border Width
4.3 Border ColorsUses color tokens from section 1
4.4 Border Examples/* Input field */
.input {
border: var(--border-width-thin) solid var(--border-color-light);
border-radius: var(--border-radius-sm);
}
/* Focus state */
.input:focus {
border-width: var(--border-width-medium);
border-color: var(--border-color-focus);
}
/* Error state */
.input-error {
border-color: var(--border-color-error);
}7. SHADOW TOKENS5.1 Shadow Scale
5.2 React Native Shadows// React Native specific tokens
shadows: {
sm: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.1,
shadowRadius: 2,
elevation: 2
},
md: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.15,
shadowRadius: 4,
elevation: 4
}
}5.3 Shadow Examples/* Card with medium shadow */
.card {
box-shadow: var(--shadow-md);
border-radius: var(--border-radius-md);
}
/* Floating button */
.floating-button {
box-shadow: var(--shadow-lg);
}
/* Modal overlay */
.modal {
box-shadow: var(--shadow-2xl);
}8. MOTION TOKENS6.1 Duration Tokens
6.2 Easing Functions
6.3 Animation PresetsFade In:.fade-in {
animation: fadeIn var(--duration-normal) var(--easing-ease-out);
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}Slide Up:.slide-up {
animation: slideUp var(--duration-normal) var(--easing-ease-out);
}
@keyframes slideUp {
from { transform: translateY(20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}6.4 Motion Examples/* Button hover effect */
.button {
transition: all var(--duration-fast) var(--easing-ease-out);
}
.button:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
/* Modal animation */
.modal-enter {
animation: slideUp var(--duration-slow) var(--easing-ease-out);
}9. Z-INDEX TOKENS7.1 Layering System
10. ACCESSIBILITY TOKENS10.1 Color Contrast Ratios
Contrast Examples:/* ✅ Good contrast - passes AA */
.body-text {
color: var(--color-neutral-900); /* Dark text */
background-color: var(--color-neutral-50); /* Light background */
/* Ratio: 12.6:1 - Excellent! */
}
/* ❌ Poor contrast - fails AA */
.bad-text {
color: var(--color-neutral-400); /* Gray text */
background-color: var(--color-neutral-100); /* Light gray background */
/* Ratio: 2.1:1 - Too low! */
}10.2 Focus States
Focus Example:.button:focus-visible {
outline: var(--focus-ring-width) solid var(--focus-ring-color);
outline-offset: var(--focus-ring-offset);
/* Creates visible ring around button */
}10.3 Touch Target Sizes
Touch Target Example:/* Mobile button - must be at least 44px */
.mobile-button {
min-width: var(--touch-target-min); /* 44px */
min-height: var(--touch-target-min); /* 44px */
padding: var(--spacing-3); /* Adds to size */
}10.4 Screen Reader Tokens
Screen Reader Only Example:/* Hide element visually but keep for screen readers */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
/* Example: Skip to main content link */
.skip-link {
@extend .sr-only;
}
.skip-link:focus {
position: fixed;
top: 0;
left: 0;
z-index: var(--z-index-tooltip);
/* Now visible when focused */
}11. COMPONENT COMPOSITION EXAMPLES
11.1 Button Component TokensPrimary Button: .button-primary {
/* Colors */
background-color: var(--color-brand-primary-500);
color: var(--color-neutral-white);
/* Typography */
font-size: var(--font-size-base);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-normal);
/* Spacing */
padding: var(--spacing-3) var(--spacing-6); /* 12px 24px */
/* Borders */
border: none;
border-radius: var(--border-radius-md); /* 8px */
/* Effects */
box-shadow: var(--shadow-sm);
transition: all var(--duration-fast) var(--easing-ease-out);
/* Accessibility */
min-height: var(--touch-target-min); /* 44px */
}
.button-primary:hover {
background-color: var(--color-brand-primary-400);
box-shadow: var(--shadow-md);
}
.button-primary:focus-visible {
outline: var(--focus-ring-width) solid var(--focus-ring-color);
outline-offset: var(--focus-ring-offset);
}
.button-primary:active {
background-color: var(--color-brand-primary-600);
}11.2 Input Field Component Tokens.input {
/* Colors */
background-color: var(--color-neutral-white);
color: var(--color-text-primary);
border-color: var(--border-color-light);
/* Typography */
font-size: var(--font-size-base);
font-weight: var(--font-weight-regular);
line-height: var(--line-height-normal);
/* Spacing */
padding: var(--spacing-3) var(--spacing-4); /* 12px 16px */
/* Borders */
border-width: var(--border-width-thin); /* 1px */
border-style: solid;
border-radius: var(--border-radius-sm); /* 4px */
/* Effects */
transition: border-color var(--duration-fast) var(--easing-ease-out);
}
.input:focus {
border-width: var(--border-width-medium); /* 2px */
border-color: var(--border-color-focus);
outline: none;
}
.input-error {
border-color: var(--border-color-error);
}
.input:disabled {
background-color: var(--color-neutral-100);
color: var(--color-neutral-400);
opacity: var(--opacity-50);
cursor: not-allowed;
}11.3 Card Component Tokens.card {
/* Colors */
background-color: var(--color-neutral-white);
border-color: var(--border-color-light);
/* Spacing */
padding: var(--spacing-6); /* 24px */
/* Borders */
border-width: var(--border-width-thin);
border-style: solid;
border-radius: var(--border-radius-md); /* 8px */
/* Effects */
box-shadow: var(--shadow-sm);
}
.card-header {
margin-bottom: var(--spacing-4); /* 16px */
font-size: var(--font-size-xl);
font-weight: var(--font-weight-semibold);
color: var(--color-text-primary);
}
.card-body {
color: var(--color-text-secondary);
font-size: var(--font-size-base);
line-height: var(--line-height-relaxed);
}11.4 State Tokens ReferenceCommon states for interactive elements:
IMPLEMENTATION GUIDANCE1. Token Naming ConventionWhy naming matters: Consistent names make tokens easy to find and understand. Think of it like organizing files in folders. Naming Pattern:Example Breakdown: Complete Naming Examples:
Token Aliases (References):
{
"color": {
"background": {
"primary": {
"value": "{color.neutral.white}"
},
"secondary": {
"value": "{color.neutral.50}"
}
}
}
}Result:
Benefits:
2. Choosing How to Distribute TokensWhy Style Dictionary is the Best Choice:Simple Analogy: Style Dictionary is like a "translator" that takes our design tokens (written once) and translates them into different languages (CSS, JavaScript, TypeScript, etc.) for different platforms. Three Key Reasons:
Simple Example:// We write this ONCE:
{
"color": {
"brand": {
"primary": "#4F7F4E"
}
}
}
// Style Dictionary creates ALL these:
// - CSS: --color-brand-primary: #4F7F4E;
// - JS: export const colorBrandPrimary = "#4F7F4E";
// - iOS: let colorBrandPrimary = UIColor(hex: "#4F7F4E")
// And more!Alternative Options (And Why Not to Use Them):
3. Token Organization Structure
Recommended File Structure:Token Grouping Strategy:1. Base Tokens (Foundation)
2. Semantic Tokens (Meaning)
3. Component Tokens (Composition)
4. Layout Tokens (Structure)
5. Accessibility Tokens (Inclusion)
Example: colors.json Structure{
"color": {
"brand": {
"primary": {
"50": { "value": "#F0F7EF" },
"100": { "value": "#D9E9D8" },
"500": { "value": "#4F7F4E" },
"900": { "value": "#173016" }
}
},
"neutral": {
"white": { "value": "#FFFFFF" },
"50": { "value": "#FAFAFA" },
"900": { "value": "#212121" },
"black": { "value": "#000000" }
}
}
}4. Platform-Specific Guidance
Web (CSS) Tokens:/* CSS Variables - Works in all browsers */
:root {
--color-brand-primary-500: #4F7F4E;
--spacing-4: 16px;
}
.button {
background-color: var(--color-brand-primary-500);
padding: var(--spacing-4);
}React Native Tokens:// JavaScript/TypeScript - Import tokens
import { tokens } from '@ode/tokens';
const styles = StyleSheet.create({
button: {
backgroundColor: tokens.color.brand.primary[500], // #4F7F4E
padding: tokens.spacing[4], // 16
}
});Key Differences:
Platform-Specific Token Examples:Shadows: /* Web */
.card {
box-shadow: var(--shadow-md);
}// React Native
const cardStyle = {
...tokens.shadow.md, // Includes shadowColor, shadowOffset, etc.
elevation: tokens.shadow.md.elevation
};Responsive Design: /* Web - Media queries */
.container {
padding: var(--spacing-4);
}
@media (min-width: var(--breakpoint-lg)) {
.container {
padding: var(--spacing-8);
}
}// React Native - Platform detection
import { Dimensions } from 'react-native';
const { width } = Dimensions.get('window');
const isTablet = width >= tokens.breakpoint.md;
const containerStyle = {
padding: isTablet ? tokens.spacing[8] : tokens.spacing[4]
};Mobile-Specific Considerations:Safe Areas (Notches, Home Indicators): // React Native - Safe area handling
import { useSafeAreaInsets } from 'react-native-safe-area-context';
const insets = useSafeAreaInsets();
const safeStyle = {
paddingTop: Math.max(insets.top, tokens.spacing[4]),
paddingBottom: Math.max(insets.bottom, tokens.spacing[4])
};Touch Targets: /* Web - Minimum 44px */
.button {
min-height: var(--touch-target-min); /* 44px */
}// React Native - Same requirement
const buttonStyle = {
minHeight: tokens.touchTarget.min // 44
};5. Creating the Token PackageStep-by-Step:Step 1: We start by creating the folder structure (5 minutes)Step 2: We create three key files (15 minutes)File 1: colors.json (Our brand colors) {
"color": {
"brand": {
"primary": {
"500": { "value": "#4F7F4E" }
}
}
}
}File 2: package.json (Package configuration) {
"name": "@ode/tokens",
"scripts": {
"build": "style-dictionary build"
}
}File 3: build.js (Build configuration) // This tells Style Dictionary what to create
module.exports = {
source: ['src/tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
files: [{
destination: 'tokens.css',
format: 'css/variables'
}]
}
}
};Step 3: Run the build (1 minute)cd packages/tokens
npm run buildStep 4: Use our tokens (2 minutes)In our web app: /* Import the generated CSS */
@import '@ode/tokens/dist/css/tokens.css';
.button {
background: var(--color-brand-primary-500);
}In our React Native app: import { colorBrandPrimary500 } from '@ode/tokens/dist/js/tokens';
const styles = {
button: {
backgroundColor: colorBrandPrimary500
}
};What We Get Automatically:After running the build once, we get:
The Magic Part:When we need to change our brand color:
No more searching through CSS, React, and React Native files to change a color! Quick Start Commands:# 1. Navigate to our project
cd ode
# 2. Create tokens package
mkdir -p packages/tokens/src/tokens
# 3. Initialize package
cd packages/tokens
npm init -y
# 4. Install Style Dictionary
npm install style-dictionary
# 5. Create the three files above
# 6. Add our token JSON files
# 7. Build!
npm run build
# 8. Start using tokens in our apps!12. USAGE GUIDELINES12.1 When to Use Which TokenQuick Decision Guide:
12.2 Common PatternsDO - Use tokens consistently: /* Good - Uses tokens */
.button {
background-color: var(--color-brand-primary-500);
padding: var(--spacing-3) var(--spacing-6);
border-radius: var(--border-radius-md);
}DON'T - Hardcode values: /* Bad - Hardcoded values */
.button {
background-color: #4F7F4E; /* Should use token! */
padding: 12px 24px; /* Should use spacing tokens! */
border-radius: 8px; /* Should use border-radius token! */
}12.3 Token Anti-Patterns1. Don't create one-off values:
2. Don't mix token systems:
3. Don't override tokens unnecessarily:
4. Don't ignore accessibility:
12.4 Token MaintenanceWhen to update tokens:
When NOT to create new tokens:
Document Version: 1.0 |
Beta Was this translation helpful? Give feedback.
-
|
We've completed Phase 1 of the ODE Design System implementation! 🎉
The tokens are based on our ODE brand colors (primary green #4F7F4E and secondary gold #E9B85B) and follow accessibility best practices (WCAG 2.1 AA compliance). Next StepsNow that we have the token foundation in place, here's what comes next:
Thank you all for your patience! |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Overview
Right now, we have three completely separate front-end implementations that don't communicate in terms of design:
NOTE: Other Front-end implementations can include the Synkronus Web UI (dubbed ""synkronus-portal"") being developed by @Ndacyayisenga-droid and @Mishael-2584.
This means users get inconsistent experiences, developers duplicate styling work, and maintenance might prove to be a hurdle. I am trying to propose that we build a unified design system with shared design tokens, component libraries, and clear design principles so everything in the ODE ecosystem feels like one cohesive product (because it really is 😉).
Insight
Before we move forward with the ODE front-end proposal, I would love to get everyone on the same page about a few key things. These are the fundamental decisions that will shape how we build and maintain our user interfaces going forward:
Right now, each project does its own thing with no shared foundation. This leads to inconsistent user experiences, duplicated work, and future maintenance problems. I would love for us to change that so every ODE experience feels cohesive and professional.
Current State
React Native (formulus)
The Good:
The Problems:
#007AFF,#fff,#f5f5f5)An example is how it looks in
formulus/src/screens/WelcomeScreen.tsx:The Problem: No design tokens means these values get repeated across files with slight variations. For example, other screens use
padding: 20orpadding: 16instead of24, creating inconsistency.What I Found:
CustomAppWebView: WebView wrapper with API injectionFormplayerModal: Full-screen form modalQRScannerModal: QR code scanner interfaceSignatureCaptureModal: Signature capture interfaceWhat's Missing:
React Web (formulus-formplayer)
The Good:
The Problems:
Here's an example from
formulus-formplayer/src/App.tsx:The Problem: No brand integration means we're using Material UI's default blue colors and spacing, which doesn't match our ODE identity or the mobile app's styling.
What I Found:
SwipeLayoutRenderer: Multi-page form navigationFinalizeRenderer: Form submission interfaceDraftSelector: Draft management UIErrorBoundary: Error handling componentetc.
Technology Stack:
Design System Status
What's Missing:
Component Analysis
What We Have
Naming Conventions
We actually already have pretty good naming patterns that we should keep:
React Native:
[Feature][Type]Modal→QRScannerModal,SignatureCaptureModal[Feature]Screen→HomeScreen,SettingsScreenCustom[Feature]WebView→CustomAppWebViewReact Web:
[Feature]QuestionRenderer→PhotoQuestionRenderer,AudioQuestionRenderer[Feature]Renderer→SwipeLayoutRenderer,FinalizeRenderer[Feature]Selector→DraftSelectorThese patterns are consistent and make soooo much sense, so we should definitely preserve them.
What's Missing
Here are the critical gaps I managed to find in React Native:
What We Need
Design Tokens
A unified design system needs to define:
Component Library
For React Native:
For React Web:
Design Principles
I am humbly proposing these principles:
Technology Options
Design Token Distribution
Option A: Style Dictionary
Option B: CSS Variables + TypeScript
Option C: JSON Tokens + Platform Adapters
Component Library Architecture
Option A: Monorepo Package
@ode/uipackage with React Native and React Web variantsOption B: Separate Packages
@ode/ui-native,@ode/ui-web,@ode/tokensOption C: In-Repo Components
Material UI Theming
Current: Using default MUI theme
Proposed: We can use custom MUI theme with our design tokens
React Native Styling
Current: Inline
StyleSheet.create()with hardcoded valuesProposed: Token-based styling system
Proposed Solution
Phase 1: Design Token Foundation
@ode/tokensorpackages/tokens) with JSON, TypeScript, and CSS outputsPhase 2: Component Library
Phase 3: Migration & Integration
Decisions We Need
1. Design System Scope
Question: Should ODE build an official Design System?
Options:
My Recommendation: YES: Full design system for consistency and maintainability.
2. Component Library Architecture
Question: How should we structure the component library?
Options:
@ode/ui) with platform variants@ode/ui-native,@ode/ui-web,@ode/tokens)My Recommendation: Option B: Separate packages for clear boundaries and independent versioning.
3. Design Token Distribution
Question: How should design tokens be distributed?
Options:
My Recommendation: Option A: Style Dictionary for scalability and platform support.
4. Design System Strictness
Question: How strict should the design system be?
Options:
My Recommendation: Option B: Flexible with core constraints, allowing innovation of our various contributors while maintaining consistency.
5. UI Pattern Documentation
Question: Should we define UI patterns (navigation, modals, forms)?
Options:
My Recommendation: Option A: Pattern library for complex interactions.
6. Tooling & Documentation
Question: Which tools should we adopt?
Options: Storybook/Ladle, Style Dictionary, Figma (if applicable), Tailwind Preset, MUI Theme Customization, React Native Theme Provider
My Recommendation: All of the above, phased implementation.
How to Contribute
Share Your Thoughts
I'd love to hear what you think about this proposal!
Your Impact
The decisions we make here will shape the UI/UX for:
The entire Front-End Architecture & Design System for the ODE Ecosystem will look like one unified system with similar colors, buttons, forms, fonts etc.
References
Thank you all for reading! Your input will help us build a unified, consistent, and maintainable front-end architecture for the ODE ecosystem.
cc @r0ssing @najuna-brian @Mishael-2584 @Ndacyayisenga-droid @Bahati308
Beta Was this translation helpful? Give feedback.
All reactions