No description
  • JavaScript 52.4%
  • PHP 14.8%
  • Shell 13.2%
  • CSS 11%
  • Twig 8.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Greyscale Eusebio 2196b7b070
All checks were successful
Propagate to consumers / Re-resolve the bundle in every consumer (push) Successful in 1m31s
Merge pull request 'Cap the injected bar's z-index so a foreign host's own overlays win' (#35) from fix/topbar-toast-stacking into main
Reviewed-on: #35
2026-08-14 11:28:49 +00:00
.claude Add the visual-evidence skill: real screenshots, committed into docs/, before opening a PR 2026-08-10 20:39:28 +02:00
.github/workflows Merge pull request 'ci Update matthewbaggett/php-node Docker tag to v8.5' (#28) from renovate/matthewbaggett-php-node-8.x into main 2026-08-10 15:51:17 +00:00
assets Cap the injected bar's z-index so a foreign host's own overlays win 2026-08-14 13:07:09 +02:00
bin Bring bar.js into symfony-brand-kit, fix its unstyled-content flash 2026-08-10 14:26:57 +02:00
config Initial grey.ooo brand kit: top bar, app switcher, shell, style guide 2026-07-20 23:36:35 +02:00
docs Push down host page content under the injected overlay topbar 2026-08-11 22:58:34 +02:00
src Generate the app roster from repo topics instead of hand-editing it 2026-08-10 12:16:43 +02:00
templates Give someones.computer a staging blade in the switcher 2026-08-10 00:37:28 +02:00
tools Cap the injected bar's z-index so a foreign host's own overlays win 2026-08-14 13:07:09 +02:00
.gitignore Check the deployed apps against the roster daily and ticket the drift (#11) 2026-08-09 10:00:15 +00:00
.gitmodules Add Grey.ooo shared agent-standards 2026-07-25 18:02:36 +02:00
CLAUDE.md Require the base branch to gate the merge before arming auto-merge 2026-08-10 17:45:30 +02:00
composer.json composer Update dependency symfony/ux-twig-component to v3 2026-07-24 11:13:53 +00:00
README.md Generate the app roster from repo topics instead of hand-editing it 2026-08-10 12:16:43 +02:00

grey.ooo brand kit

grey-ooo/brand-kit — a small Symfony bundle that ships the shared grey.ooo chrome: a consistent top bar, an app switcher, and an app shell (top bar + left sidebar + centered main + footer). Drop it into any Grey.ooo Symfony app so they all wear the same skin.

The chrome is self-contained: all styles are namespaced under .gooo-* and driven by --gooo-* custom properties, so it renders identically whatever CSS/Tailwind setup the host app uses, and needs no build step. It is dark-first, matching the someones.computer aesthetic.

Install

composer require grey-ooo/brand-kit

Register the bundle (config/bundles.php):

GreyOoo\BrandKit\GreyOooBrandKitBundle::class => ['all' => true],

Configure it (config/packages/grey_ooo_brand_kit.yaml) — normally just the one line naming which app this is:

grey_ooo_brand_kit:
    current_app: printshop

The app roster is owned by the bundle, not by consumers: it defaults to GreyOoo\BrandKit\Config\GreyOooApps::ALL, rather than the same list repeated in every repo where the copies drift.

That constant is generated, not hand-edited. An app is in the roster because its own repo on git.grey.ooo carries the grey-ooo-app-roster topic, and its URL is that repo's website field; a nightly job regenerates the constant and opens the PR. Adding an app is a topic on its repo plus a name and icon in tools/roster/presentation.mjs, then a composer update grey-ooo/brand-kit in each consumer. See tools/roster/README.md.

You do not set external per app either. Whether an entry is "another app" depends on who is rendering, so it is derived from current_app: every entry is external except the one being served. Set it explicitly only to force a full page load.

Each entry carries an icon, in one of two forms — the switcher, the brand mark and the styleguide all render it through components/_app_icon.html.twig, so they agree:

Field
icon An emoji. The default, and enough for an app with no mark of its own escaped
icon_svg Inline SVG, superseding icon for an app that has a mark — someones ships the terminal display it draws in its own appbar, niall the face he talks with printed raw

Give icon_svg geometry only (a viewBox, no width/height): brand-kit.css sizes it in em so a mark and an emoji sit at one optical scale side by side. It is the only field the kit prints unescaped, so it takes bundle or app config and nothing a request can reach.

An entry may also carry staging_url, which gives its row a blade: a second, amber surface behind the button showing a sliver past the right edge, sliding out from under it on hover (and simply sitting out on touch, where a 4px sliver is not a tap target). It reads as one app with another copy behind it rather than as two apps, which is why it is drawn behind the row and not beside it. The blade lives in the shared roster, so it shows in every app's switcher — a staging box linked here is a shortcut, not a hiding place.

Override the list only when you genuinely need a different one (staging URLs, a local sandbox); apps still accepts a full replacement, and brand still tunes the wordmark:

grey_ooo_brand_kit:
    current_app: printshop
    brand: { name: grey, suffix: .ooo }
    apps:
        - { key: printshop, name: 'PrintShop (staging)', url: 'https://staging.printshop.grey.ooo', icon: '🖨️' }

Expose the bundle's assets to AssetMapper (config/packages/asset_mapper.yaml):

framework:
    asset_mapper:
        paths:
            '%kernel.project_dir%/vendor/grey-ooo/brand-kit/assets': grey-ooo-brand-kit

Then load the CSS + JS. Link the stylesheet in your base template <head> and pull the script in via your importmap.php / app.js (or a <script type="module">):

<link rel="stylesheet" href="{{ asset('grey-ooo-brand-kit/styles/brand-kit.css') }}">

Use

<twig:GreyOoo:Shell current-app="printshop">
    {% block topbar %}
        <twig:GreyOoo:TopBar current-app="printshop">
            {# host app actions: notifications, user menu, … #}
        </twig:GreyOoo:TopBar>
    {% endblock %}

    {% block sidebar %}
        <twig:GreyOoo:NavItem href="{{ path('dashboard') }}" label="Dashboard" :active="true">
            {% block icon %}<twig:ux:icon name="lucide:layout-dashboard"/>{% endblock %}
        </twig:GreyOoo:NavItem>
        {# … #}
    {% endblock %}

    {% block content %}{# page content #}{% endblock %}
    {% block footer %}© grey.ooo{% endblock %}
</twig:GreyOoo:Shell>

Icons are passed via the icon block so the bundle stays independent of any icon set.

The sidebar is optional: omit the sidebar block and the shell renders without a rail and without the drawer toggle, with main spanning the full width. An app with a single page (Niall.chat) has nothing to navigate to, so it leaves the block out.

Components

Component Purpose
GreyOoo:Shell Page scaffold — topbar / sidebar (optional) / content / footer blocks.
GreyOoo:TopBar The grey.ooo bar: mark + wordmark + app switcher, with a right-hand actions slot (default content).
GreyOoo:AppSwitcher Grid-button dropdown of the configured apps.
GreyOoo:NavItem A sidebar link (href, label, active, icon block).

The resolved config is also available in templates as the gooo_brand_kit global.

Style guide

Import the bundle's routes (dev only) to browse a living style guide at /_brand-kit/styleguide:

# config/routes/grey_ooo_brand_kit.yaml
grey_ooo_brand_kit:
    resource: '@GreyOooBrandKitBundle/config/routes.php'