coderef

Evernote

Evernote's iOS app is a calm, long-form reading and capture surface. It is the original "second brain" — a place where notes accumulate over years — so the design system optimizes for legibility, reassuring structure, and a single…
DownloadRaw
Evernote

Build with the Evernote look.

Palette, type and components from this DESIGN.md, applied to a sample hero.

Palette

At a glance

Theme
dark
Typefaces
SF Pro, SF Mono
Sections
7
Length
4,231 words
Platforms
Android, Expo, SwiftUI, DESIGN.md

Add it to your project

Then prompt your agent

Design System · Evernote

Light and dark previews, tokens and a ready-to-use package, generated from this DESIGN.md. No AI involved: the same file always produces the same output.

Generating design system…
DownloadRaw

Evernote (iOS) — Jetpack Compose Implementation Guide

Companion to DESIGN.md — the framework-neutral spec. This file ports Evernote’s visual language to Android with Jetpack Compose (Material 3): a color token object, a Typography set, paste-ready @Composables, the note editor + checklist + FAB, motion, and haptics.

Why a Compose guide for an iOS-referenced app? The DESIGN.md tokens are platform-neutral. This file keeps the visual identity (Evernote’s calm neutral canvas, the single brand green, green tag pills, the raised circular FAB, roomy reading rhythm) while making everything idiomatic Android — NavigationBar + a center FloatingActionButton (docked) instead of a UITabBar with embedded FAB, SwipeToDismissBox for swipe actions, sp/dp instead of pt.

Assumes Compose BOM 2024.09+, Kotlin 2.0+, minSdk 24, Material 3, and Coil 2.6+ for thumbnails. No Material You dynamic color — Evernote’s brand green is fixed; a full dark scheme is provided.

1. Color Tokens

// ui/theme/EvernoteColors.kt
import androidx.compose.ui.graphics.Color

object EverColors {
    // Brand (interactive)
    val Green        = Color(0xFF00A82D)
    val GreenBright  = Color(0xFF2DBE60) // interactive on dark
    val GreenPressed = Color(0xFF007A20)
    val GreenDeep    = Color(0xFF108A00)
    val Ink          = Color(0xFF1C2B33)

    // Canvas & Surfaces (Light)
    val Canvas   = Color(0xFFFFFFFF)
    val OffWhite = Color(0xFFFAFAFA)
    val Pressed  = Color(0xFFF1F2F2)
    val Divider  = Color(0xFFE4E5E5)
    val Border   = Color(0xFFDCDEDE)

    // Canvas & Surfaces (Dark) — true near-black
    val DarkCanvas   = Color(0xFF1C1C1E)
    val DarkSurface1 = Color(0xFF242426)
    val DarkSurface2 = Color(0xFF2E2E30)
    val DarkSurface3 = Color(0xFF3A3A3C)
    val DarkDivider  = Color(0xFF38383A)

    // Text
    val TextPrimary   = Color(0xFF1C2B33) // Evernote warm ink — NOT pure black
    val TextSecondary = Color(0xFF5C6970)
    val TextTertiary  = Color(0xFF8C969C)
    val DarkTextPrimary   = Color(0xFFE4E4E6) // NOT pure white — reading comfort
    val DarkTextSecondary = Color(0xFF9A9A9E)
    val DarkTextTertiary  = Color(0xFF6E6E72)

    // Tag chips
    val TagBgLight   = Color(0xFFE6F4EA); val TagTextLight = Color(0xFF1F7A33)
    val TagBgDark    = Color(0xFF1C3A24); val TagTextDark  = Color(0xFF5FD68A)

    // Semantic
    val Blue    = Color(0xFF2F80ED)
    val Warn    = Color(0xFFF6A609)
    val Error   = Color(0xFFE5484D)
    val Yellow  = Color(0xFFF6C544)
    val HiLight = Color(0xFFFFF3B0)
    val HiDark  = Color(0xFF5A4A12)

    // Notebook accents
    val NbBlue   = Color(0xFF2F80ED)
    val NbYellow = Color(0xFFF6C544)
    val NbRed    = Color(0xFFE5484D)
    val NbPurple = Color(0xFF7A5AF8)
    val NbTeal   = Color(0xFF1AAE9F)
}

Wire it into both schemes. Evernote is light-first; the dark scheme uses a true near-black #1C1C1E for reading comfort and brightens interactive green.

// ui/theme/Theme.kt
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.*
import androidx.compose.runtime.Composable

private val EverLight = lightColorScheme(
    primary        = EverColors.Green,
    onPrimary      = Color.White,
    background      = EverColors.OffWhite,
    onBackground   = EverColors.TextPrimary,
    surface        = EverColors.Canvas,
    onSurface      = EverColors.TextPrimary,
    surfaceVariant = EverColors.Pressed,
    outline        = EverColors.Divider,
    error          = EverColors.Error,
)

private val EverDark = darkColorScheme(
    primary        = EverColors.GreenBright,
    onPrimary      = Color.White,
    background      = EverColors.DarkCanvas,
    onBackground   = EverColors.DarkTextPrimary,
    surface        = EverColors.DarkSurface1,
    onSurface      = EverColors.DarkTextPrimary,
    surfaceVariant = EverColors.DarkSurface2,
    outline        = EverColors.DarkDivider,
    error          = EverColors.Error,
)

@Composable
fun EvernoteTheme(
    dark: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit,
) = MaterialTheme(
    colorScheme = if (dark) EverDark else EverLight,
    typography = EverTypography,
    content = content,
)

2. Typography

Evernote uses the iOS system font; on Android use Inter (SIL OFL) in res/font/ for cross-platform parity. Body is 16sp at 26sp line-height (≈1.6) — reading comfort first.

// ui/theme/EverType.kt
import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp

val Inter = FontFamily(
    Font(R.font.inter_regular,  FontWeight.Normal),
    Font(R.font.inter_medium,   FontWeight.Medium),
    Font(R.font.inter_semibold, FontWeight.SemiBold),
    Font(R.font.inter_bold,     FontWeight.Bold),
)

object EverText {
    val ScreenTitle = TextStyle(Inter, fontWeight = FontWeight.Bold,     fontSize = 30.sp, lineHeight = 36.sp, letterSpacing = (-0.4).sp)
    val NoteTitle   = TextStyle(Inter, fontWeight = FontWeight.Bold,     fontSize = 24.sp, lineHeight = 30.sp, letterSpacing = (-0.3).sp)
    val NoteH1      = TextStyle(Inter, fontWeight = FontWeight.Bold,     fontSize = 20.sp, lineHeight = 26.sp, letterSpacing = (-0.2).sp)
    val NoteH2      = TextStyle(Inter, fontWeight = FontWeight.Bold,     fontSize = 17.sp, lineHeight = 23.sp, letterSpacing = (-0.1).sp)
    val Body        = TextStyle(Inter, fontWeight = FontWeight.Normal,   fontSize = 16.sp, lineHeight = 26.sp) // ≈1.6
    val ListTitle   = TextStyle(Inter, fontWeight = FontWeight.SemiBold, fontSize = 15.sp, lineHeight = 20.sp)
    val Checklist   = TextStyle(Inter, fontWeight = FontWeight.Normal,   fontSize = 15.sp, lineHeight = 22.sp)
    val Snippet     = TextStyle(Inter, fontWeight = FontWeight.Normal,   fontSize = 14.sp, lineHeight = 20.sp)
    val Tag         = TextStyle(Inter, fontWeight = FontWeight.SemiBold, fontSize = 12.sp, lineHeight = 14.sp, letterSpacing = 0.1.sp)
    val Meta        = TextStyle(Inter, fontWeight = FontWeight.Normal,   fontSize = 12.sp, lineHeight = 16.sp)
    val Button      = TextStyle(Inter, fontWeight = FontWeight.SemiBold, fontSize = 15.sp, lineHeight = 15.sp)
    val Tab         = TextStyle(Inter, fontWeight = FontWeight.Medium,   fontSize = 10.sp, lineHeight = 11.sp, letterSpacing = 0.1.sp)
    val Code        = TextStyle(FontFamily.Monospace, fontWeight = FontWeight.Normal, fontSize = 14.sp, lineHeight = 21.sp)
}

val EverTypography = Typography(
    headlineLarge = EverText.ScreenTitle,
    headlineMedium = EverText.NoteTitle,
    titleMedium   = EverText.NoteH2,
    bodyMedium    = EverText.Body,
    labelSmall    = EverText.Tab,
)

3. Signature Components

Tag Pill

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp

@Composable
fun TagPill(text: String, dark: Boolean = isSystemInDarkTheme()) {
    Box(
        Modifier
            .clip(RoundedCornerShape(999.dp))
            .background(if (dark) EverColors.TagBgDark else EverColors.TagBgLight)
            .padding(horizontal = 9.dp, vertical = 3.dp)
    ) {
        Text(text, style = EverText.Tag, color = if (dark) EverColors.TagTextDark else EverColors.TagTextLight)
    }
}

Checklist Item

import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.spring
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material3.Icon
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.text.style.TextDecoration

@Composable
fun ChecklistItem(initialDone: Boolean = false, text: String) {
    val dark = isSystemInDarkTheme()
    var done by remember { mutableStateOf(initialDone) }
    val haptics = LocalHapticFeedback.current
    val pop by animateFloatAsState(if (done) 1.12f else 1f, spring(dampingRatio = 0.4f), label = "pop")
    val green = if (dark) EverColors.GreenBright else EverColors.Green

    Row(verticalAlignment = Alignment.Top, horizontalArrangement = Arrangement.spacedBy(10.dp)) {
        Box(
            Modifier
                .size(44.dp)
                .clickable {
                    haptics.performHapticFeedback(HapticFeedbackType.LongPress)
                    done = !done
                },
            contentAlignment = Alignment.TopStart,
        ) {
            Box(
                Modifier
                    .size(19.dp)
                    .scale(if (done) pop else 1f)
                    .clip(RoundedCornerShape(5.dp))
                    .then(if (done) Modifier.background(green)
                          else Modifier.border(2.dp, EverColors.TextTertiary, RoundedCornerShape(5.dp))),
                contentAlignment = Alignment.Center,
            ) {
                if (done) Icon(Icons.Filled.Check, contentDescription = null, tint = Color.White, modifier = Modifier.size(11.dp))
            }
        }
        Text(
            text,
            style = EverText.Checklist.copy(textDecoration = if (done) TextDecoration.LineThrough else TextDecoration.None),
            color = if (done) EverColors.TextTertiary
                    else if (dark) EverColors.DarkTextPrimary else EverColors.TextPrimary,
        )
    }
}

Note List Row

import androidx.compose.material3.HorizontalDivider
import coil.compose.AsyncImage

@Composable
fun NoteRow(
    title: String, snippet: String, date: String, notebook: String, thumbUrl: String? = null,
) {
    val dark = isSystemInDarkTheme()
    Column {
        Row(
            Modifier.fillMaxWidth().padding(vertical = 14.dp),
            horizontalArrangement = Arrangement.spacedBy(12.dp),
        ) {
            Column(Modifier.weight(1f)) {
                Text(title, style = EverText.ListTitle, maxLines = 1,
                    color = if (dark) EverColors.DarkTextPrimary else EverColors.TextPrimary)
                Text(snippet, style = EverText.Snippet, maxLines = 2,
                    color = if (dark) EverColors.DarkTextSecondary else EverColors.TextSecondary)
                Text("$date · $notebook", style = EverText.Meta, modifier = Modifier.padding(top = 3.dp),
                    color = if (dark) EverColors.DarkTextTertiary else EverColors.TextTertiary)
            }
            if (thumbUrl != null) {
                AsyncImage(
                    model = thumbUrl, contentDescription = null,
                    modifier = Modifier.size(52.dp).clip(RoundedCornerShape(8.dp))
                        .background(if (dark) EverColors.DarkSurface3 else EverColors.Pressed),
                )
            }
        }
        HorizontalDivider(color = if (dark) EverColors.DarkDivider else EverColors.Divider, thickness = 1.dp)
    }
}

Format Toolbar (bottom accessory)

import androidx.compose.material.icons.filled.*

@Composable
fun FormatToolbar() {
    val dark = isSystemInDarkTheme()
    val tools = listOf(
        Icons.Filled.FormatBold, Icons.Filled.FormatItalic, Icons.Filled.FormatListBulleted,
        Icons.Filled.CheckBox, Icons.Filled.Title, Icons.Filled.AttachFile, Icons.Filled.Link,
    )
    Row(
        Modifier.fillMaxWidth()
            .background(if (dark) EverColors.DarkSurface2 else EverColors.Canvas)
            .padding(vertical = 12.dp),
        horizontalArrangement = Arrangement.SpaceAround,
        verticalAlignment = Alignment.CenterVertically,
    ) {
        tools.forEach {
            Icon(it, contentDescription = null, modifier = Modifier.size(20.dp),
                tint = if (dark) EverColors.DarkTextSecondary else EverColors.TextSecondary)
        }
    }
}

4. Navigation

Evernote has a 5-slot bottom strip with a raised green circular new-note button in the center. On Android, model this as a Scaffold with a BottomAppBar/NavigationBar plus a center-docked FloatingActionButton. No tint pill — active is brand green.

import androidx.compose.material3.*

@Composable
fun EvernoteBottomBar(selected: Int, onSelect: (Int) -> Unit, onNewNote: () -> Unit) {
    val dark = isSystemInDarkTheme()
    Box {
        NavigationBar(containerColor = MaterialTheme.colorScheme.surface, tonalElevation = 0.dp) {
            val items = listOf(
                "Home"      to Icons.Filled.Home,
                "Notes"     to Icons.Filled.Description,
                null        to null, // FAB gap
                "Notebooks" to Icons.Filled.LibraryBooks,
                "Search"    to Icons.Filled.Search,
            )
            items.forEachIndexed { i, pair ->
                if (pair.first == null) {
                    NavigationBarItem(selected = false, onClick = {}, enabled = false, icon = {}, label = {})
                } else {
                    NavigationBarItem(
                        selected = selected == i,
                        onClick = { onSelect(i) },
                        icon = { Icon(pair.second!!, contentDescription = pair.first, modifier = Modifier.size(24.dp)) },
                        label = { Text(pair.first!!, style = EverText.Tab) },
                        colors = NavigationBarItemDefaults.colors(
                            selectedIconColor = if (dark) EverColors.GreenBright else EverColors.Green,
                            selectedTextColor = if (dark) EverColors.GreenBright else EverColors.Green,
                            unselectedIconColor = EverColors.TextTertiary,
                            unselectedTextColor = EverColors.TextTertiary,
                            indicatorColor = Color.Transparent, // no Material pill
                        ),
                    )
                }
            }
        }
        FloatingActionButton(
            onClick = onNewNote,
            containerColor = EverColors.Green,
            contentColor = Color.White,
            shape = CircleShape,
            modifier = Modifier.align(Alignment.TopCenter).offset(y = (-22).dp).size(52.dp),
        ) { Icon(Icons.Filled.Add, contentDescription = "New note") }
    }
}

Tapping the FAB opens a ModalBottomSheet (20.dp top radius) with capture rows: Text Note, Camera, Photo, Audio, Reminder — each a tall row with a leading green icon. The notebooks screen lists notebook rows (spine icon + name + count) and stacks as expandable group headers.

5. Motion

Evernote motion is calm — 150–300ms ease-out / soft spring, never aggressive.

Moment Compose recipe
Checkbox toggle box scale via animateFloatAsState(spring(dampingRatio = 0.4f)) + strikethrough applied; light haptic
Note open (list → editor) Nav3/NavHost slide push tween(300)
FAB → capture sheet ModalBottomSheet default slide-up (≈300ms); FAB press scale 0.96 via interactionSource
Sync toast Snackbar / AnimatedVisibility fadeIn + slideInVertically(tween(200)), auto-dismiss 2s
Stack expand chevron animateFloatAsState 0→90° tween(150); rows expandVertically(tween(200)) + fadeIn
Tag add AnimatedVisibility scaleIn(initialScale = 0.8f, tween(150)) + fadeIn
Swipe actions SwipeToDismissBox — leading pin/move, trailing delete; medium haptic on commit
// Checkbox pop — the canonical Evernote micro-motion
val pop by animateFloatAsState(if (done) 1.12f else 1f, spring(dampingRatio = 0.4f), label = "pop")

Haptics: LocalHapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) for the light tick on checkbox toggle and tab change; medium-equivalent on swipe-action commit and note delete; HapticFeedbackConstants.CLOCK_TICK for the soft FAB long-press. Auto-save is silent — only show a Snackbar on explicit save or sync error.

6. Icons

Evernote’s UI maps to filled Material icons; brand green carries state. Add androidx.compose.material:material-icons-extended for the format set.

Purpose SF Symbol (iOS) Material Icon (Compose)
Home (tab) house Icons.Filled.Home
Notes (tab) note.text Icons.Filled.Description
FAB / new note plus Icons.Filled.Add
Notebooks (tab) books.vertical Icons.Filled.LibraryBooks
Search (tab) magnifyingglass Icons.Filled.Search
Back chevron.left Icons.Filled.ArrowBack
Overflow ellipsis Icons.Filled.MoreHoriz
Note info info.circle Icons.Filled.InfoOutline
Checkbox empty square Icons.Outlined.CheckBoxOutlineBlank
Checkbox done checkmark.square.fill Icons.Filled.CheckBox
Bold bold Icons.Filled.FormatBold
Italic italic Icons.Filled.FormatItalic
List list.bullet Icons.Filled.FormatListBulleted
Checklist checklist Icons.Filled.CheckBox
Heading textformat.size Icons.Filled.Title
Attach paperclip Icons.Filled.AttachFile
Camera / scan doc.viewfinder Icons.Filled.DocumentScanner
Audio mic Icons.Filled.Mic
Link link Icons.Filled.Link
Highlight highlighter Icons.Filled.FormatColorFill
Tag tag Icons.Filled.LocalOffer
Pin pin Icons.Filled.PushPin
Reminder clock Icons.Filled.Schedule
Notebook book.closed Icons.Filled.MenuBook
Stack square.stack Icons.Filled.Layers

7. Minimum SDK & Accessibility Notes

  • minSdk 24 (Compose floor 21; ModalBottomSheet, SwipeToDismissBox, modern motion comfortable at 24). compileSdk 34+, Compose BOM 2024.09+, Kotlin 2.0+.
  • Edge-to-edge: call enableEdgeToEdge(); light canvas wants dark-content system bars (light-content in dark mode). The docked FAB must clear the gesture nav inset.
  • Font scaling: sp honors the user’s scale — keep it on titles, headings, body, snippets, checklist (it stays readable as it scales). Pin layout-sensitive text (10sp tab labels, tag pills, sync-toast) so the bottom strip doesn’t break.
  • Reading comfort: keep Body.lineHeight = 26.sp (≈1.6) and 22.dp horizontal editor padding — do not tighten; this is the brand’s core feel.
  • TalkBack: label note rows “{title}, {snippet}, {date}, {notebook}”; checklist items “{text}, checked/unchecked” with a toggle action; the FAB “New note, button”; tag pills “Tag: {name}, filters notes”. Never convey checklist done-state by color alone — strikethrough + dim is the secondary cue.
  • Touch targets: Material guidance is 48.dp — the checkbox sits in a 44–48.dp hit Box; note rows are full-row tappable (≥64.dp); FAB is 52.dp; format-toolbar icons get 48.dp hit padding.
  • Contrast: #1C2B33 on #FFFFFF and #E4E4E6 on #1C1C1E pass WCAG AA for body; use #2DBE60 (not #00A82D) for small interactive green on the dark canvas to clear AA.
  • Reduce motion: when Settings.Global.ANIMATOR_DURATION_SCALE == 0, disable the checkbox pop and stack slide — substitute Crossfade; keep instant state changes.
  • Dark mode: invert via the Dark* palette — the dark canvas is a true near-black #1C1C1E, NOT charcoal-gray; #1C2B33 text → #E4E4E6 (not pure white). Shadows nearly vanish on dark, so signal elevation via the surface step (#242426→#2E2E30→#3A3A3C) + a 1.dp DarkDivider border on menus and sheets; the FAB keeps its green-tinted glow. Do not enable dynamicColorScheme() — Evernote’s single brand green must hold regardless of wallpaper.
All mobile designs →

Brand names describe the visual style only; coderef is not affiliated with or endorsed by any brand listed. Licenses