Skip to content

Commit

Permalink
feat: branding (#50)
Browse files Browse the repository at this point in the history
* feat: allow site name and sidebar colour to be set

* feat: sidebar icon

* fix: fix build issues

* docs: document new branding options
  • Loading branch information
Arcath authored Oct 28, 2024
1 parent 593e7a7 commit 7bbc607
Show file tree
Hide file tree
Showing 52 changed files with 379 additions and 98 deletions.
46 changes: 46 additions & 0 deletions app/lib/settings.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {asyncForEach} from '@arcath/utils'
import {getPrisma} from './prisma.server'

type SettingKey = 'site-name' | 'site-color' | 'site-icon'

export const DEFAULT_SETTINGS: {[setting in SettingKey]: string} = {
'site-name': 'Net Doc',
'site-color': '#d1d5db',
'site-icon': '/icon.png'
}

export const getSetting = async (setting: SettingKey) => {
const prisma = getPrisma()

const dbSetting = await prisma.setting.findFirst({where: {key: setting}})

if (dbSetting === null) {
return DEFAULT_SETTINGS[setting]
}

return dbSetting.value
}

export const getSettings = async <RequestedKey extends SettingKey>(
settings: RequestedKey[]
) => {
const results = Object.fromEntries(settings.map(v => [v, ''])) as {
[key in RequestedKey]: string
}

await asyncForEach(settings, async setting => {
results[setting] = await getSetting(setting)
})

return results
}

export const setSetting = async (setting: SettingKey, value: string) => {
const prisma = getPrisma()

await prisma.setting.upsert({
where: {key: setting},
create: {key: setting, value},
update: {value}
})
}
22 changes: 22 additions & 0 deletions app/lib/utils/contrast-color.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export const contrastColor = (color: string) => {
return luma(color) >= 165 ? '#444' : '#fff'
}
const luma = (color: string | Array<number>) => {
// color can be a hx string or an array of RGB values 0-255
const rgb = typeof color === 'string' ? hexToRGBArray(color) : color
return 0.2126 * rgb[0] + 0.7152 * rgb[1] + 0.0722 * rgb[2] // SMPTE C, Rec. 709 weightings
}
const hexToRGBArray = (color: string) => {
if (color.length === 3)
color =
color.charAt(0) +
color.charAt(0) +
color.charAt(1) +
color.charAt(1) +
color.charAt(2) +
color.charAt(2)
else if (color.length !== 6) throw 'Invalid hex color: ' + color
const rgb = []
for (let i = 0; i <= 2; i++) rgb[i] = parseInt(color.substr(i * 2, 2), 16)
return rgb
}
12 changes: 10 additions & 2 deletions app/lib/utils/page-title.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
export const pageTitle = (...parts: string[]) => {
return ['Net Doc', ...parts].join(' / ')
import {type MetaArgs} from '@remix-run/node'

export const pageTitle = (matches: MetaArgs['matches'], ...parts: string[]) => {
const appName = (
matches.filter(match => match.pathname === '/app')[0].data as {
settings: {'site-name': string}
}
).settings['site-name']

return [appName, ...parts].join(' / ')
}
4 changes: 2 additions & 2 deletions app/routes/app.$assetslug.$entry.$revision.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ export const loader = async ({request, params}: LoaderFunctionArgs) => {
return json({user, entry, name, values, revisions, pastValues})
}

export const meta: MetaFunction<typeof loader> = ({data}) => {
return [{title: pageTitle(data!.entry.asset.singular, data!.name)}]
export const meta: MetaFunction<typeof loader> = ({matches, data}) => {
return [{title: pageTitle(matches, data!.entry.asset.singular, data!.name)}]
}

const AssetEntry = () => {
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.$assetslug.$entry._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ export const loader = async ({request, params}: LoaderFunctionArgs) => {
)
}

export const meta: MetaFunction<typeof loader> = ({data}) => {
return [{title: pageTitle(data!.entry.asset.singular, data!.name)}]
export const meta: MetaFunction<typeof loader> = ({matches, data}) => {
return [{title: pageTitle(matches, data!.entry.asset.singular, data!.name)}]
}

export const headers = ({loaderHeaders}: HeadersArgs) => {
Expand Down
13 changes: 11 additions & 2 deletions app/routes/app.$assetslug.$entry.delete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,17 @@ export const action = async ({request, params}: ActionFunctionArgs) => {
return json({error: 'Name does not match'})
}

export const meta: MetaFunction<typeof loader> = ({data}) => {
return [{title: pageTitle(data!.entry.asset.singular, data!.name, 'Delete')}]
export const meta: MetaFunction<typeof loader> = ({matches, data}) => {
return [
{
title: pageTitle(
matches,
data!.entry.asset.singular,
data!.name,
'Delete'
)
}
]
}

const AssetEntryDelete = () => {
Expand Down
6 changes: 4 additions & 2 deletions app/routes/app.$assetslug.$entry.edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,10 @@ export const action = async ({request, params}: ActionFunctionArgs) => {
return redirect(`/app/${params.assetslug}/${params.entry}`)
}

export const meta: MetaFunction<typeof loader> = ({data}) => {
return [{title: pageTitle(data!.entry.asset.singular, data!.name, 'Edit')}]
export const meta: MetaFunction<typeof loader> = ({matches, data}) => {
return [
{title: pageTitle(matches, data!.entry.asset.singular, data!.name, 'Edit')}
]
}

const Asset = () => {
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.$assetslug.$entry.link-password.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ export const action = async ({request, params}: ActionFunctionArgs) => {
return redirect(`/app/${params.assetslug}/${params.entry}`)
}

export const meta: MetaFunction<typeof loader> = ({data}) => {
export const meta: MetaFunction<typeof loader> = ({matches, data}) => {
return [
{
title: pageTitle(data!.entry.asset.singular, 'Link a Password')
title: pageTitle(matches, data!.entry.asset.singular, 'Link a Password')
}
]
}
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.$assetslug._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ export const loader = async ({request, params}: LoaderFunctionArgs) => {
)
}

export const meta: MetaFunction<typeof loader> = ({data}) => {
return [{title: pageTitle(data!.asset.plural)}]
export const meta: MetaFunction<typeof loader> = ({matches, data}) => {
return [{title: pageTitle(matches, data!.asset.plural)}]
}

export const headers = ({loaderHeaders}: HeadersArgs) => {
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.$assetslug.add.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,10 @@ export const action = async ({request, params}: ActionFunctionArgs) => {
return redirect(`/app/${params.assetslug}/${entry.id}`)
}

export const meta: MetaFunction<typeof loader> = ({data}) => {
export const meta: MetaFunction<typeof loader> = ({matches, data}) => {
return [
{
title: pageTitle(data!.asset.singular, 'New')
title: pageTitle(matches, data!.asset.singular, 'New')
}
]
}
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.$assetslug.import.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ export const action = async ({request, params}: ActionFunctionArgs) => {
return json({status: 200})
}

export const meta: MetaFunction<typeof loader> = ({data}) => {
export const meta: MetaFunction<typeof loader> = ({matches, data}) => {
return [
{
title: pageTitle(data!.asset.singular, 'Import')
title: pageTitle(matches, data!.asset.singular, 'Import')
}
]
}
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ export const loader = async ({request, params}: LoaderFunctionArgs) => {
return json({user, boxes: boxesWithData}, {headers: headers()})
}

export const meta: MetaFunction = () => {
return [{title: pageTitle('Dashboard')}]
export const meta: MetaFunction = ({matches}) => {
return [{title: pageTitle(matches, 'Dashboard')}]
}

export const headers = ({loaderHeaders}: HeadersArgs) => {
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.acl-manager.$acl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ export const action: ActionFunction = async ({request, params}) => {
return redirect(`/app/acl-manager/${params.acl}`)
}

export const meta: MetaFunction = () => {
export const meta: MetaFunction = ({matches}) => {
return [
{
title: pageTitle('ACL Manager')
title: pageTitle(matches, 'ACL Manager')
}
]
}
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.acl-manager._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ export const loader = async ({request}: LoaderFunctionArgs) => {
return json({user, acls})
}

export const meta: MetaFunction = () => {
export const meta: MetaFunction = ({matches}) => {
return [
{
title: pageTitle('AACL Manager')
title: pageTitle(matches, 'ACL Manager')
}
]
}
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.acl-manager.add.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ export const action = async ({request}: ActionFunctionArgs) => {
return redirect(`/app/acl-manager/${acl.id}`)
}

export const meta: MetaFunction = () => {
return [{title: pageTitle('ACL Manager', 'Add')}]
export const meta: MetaFunction = ({matches}) => {
return [{title: pageTitle(matches, 'ACL Manager', 'Add')}]
}

const ACLManagerAdd = () => {
Expand Down
3 changes: 2 additions & 1 deletion app/routes/app.asset-manager.$asset.$assetfield.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ export const action = async ({request, params}: ActionFunctionArgs) => {
return redirect(`/app/asset-manager/${params.asset}`)
}

export const meta: MetaFunction<typeof loader> = ({data}) => {
export const meta: MetaFunction<typeof loader> = ({matches, data}) => {
return [
{
title: pageTitle(
matches,
'Asset Manager',
'Edit Field',
data!.assetField.field.name
Expand Down
11 changes: 10 additions & 1 deletion app/routes/app.asset-manager.$asset.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {type LoaderFunctionArgs, json} from '@remix-run/node'
import {type LoaderFunctionArgs, type MetaFunction, json} from '@remix-run/node'
import {Outlet, useLoaderData, Link} from '@remix-run/react'

import {ensureUser} from '~/lib/utils/ensure-user'
import {getPrisma} from '~/lib/prisma.server'
import {pageTitle} from '~/lib/utils/page-title'

export const loader = async ({request, params}: LoaderFunctionArgs) => {
const user = await ensureUser(request, 'asset-manager:edit', {
Expand All @@ -29,6 +30,14 @@ export const loader = async ({request, params}: LoaderFunctionArgs) => {
return json({user, asset, fields})
}

export const meta: MetaFunction<typeof loader> = ({matches, data}) => {
return [
{
title: pageTitle(matches, 'Asset Manager', data!.asset.name)
}
]
}

const AssetManagerAsset = () => {
const {asset, fields} = useLoaderData<typeof loader>()

Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.asset-manager._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ export const loader = async ({request}: LoaderFunctionArgs) => {
return json({user, assets})
}

export const meta: MetaFunction = () => {
export const meta: MetaFunction = ({matches}) => {
return [
{
title: pageTitle('Asset Manager')
title: pageTitle(matches, 'Asset Manager')
}
]
}
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.asset-manager.add.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ export const action = async ({request}: ActionFunctionArgs) => {
return redirect(`/app/asset-manager/${asset.id}`)
}

export const meta: MetaFunction = () => {
return [{title: pageTitle('Asset Manager', 'Add')}]
export const meta: MetaFunction = ({matches}) => {
return [{title: pageTitle(matches, 'Asset Manager', 'Add')}]
}

const AssetManagerAdd = () => {
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ export const action = async ({request}: ActionFunctionArgs) => {
return redirect('/app')
}

export const meta: MetaFunction = () => {
return [{title: pageTitle('Dashboard')}]
export const meta: MetaFunction = ({matches}) => {
return [{title: pageTitle(matches, 'Dashboard')}]
}

export const headers = ({loaderHeaders}: HeadersArgs) => {
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.documents.$document.$revision.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export const loader = async ({request, params}: LoaderFunctionArgs) => {
return json({user, document, code, title: revision.previousTitle})
}

export const meta: MetaFunction<typeof loader> = ({data}) => {
return [{title: pageTitle('Document', data!.document.title)}]
export const meta: MetaFunction<typeof loader> = ({data, matches}) => {
return [{title: pageTitle(matches, 'Document', data!.document.title)}]
}

const DocumentViewRevision = () => {
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.documents.$document._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export const loader = async ({request, params}: LoaderFunctionArgs) => {
})
}

export const meta: MetaFunction<typeof loader> = ({data}) => {
return [{title: pageTitle('Document', data!.document.title)}]
export const meta: MetaFunction<typeof loader> = ({matches, data}) => {
return [{title: pageTitle(matches, 'Document', data!.document.title)}]
}

const DocumentView = () => {
Expand Down
15 changes: 9 additions & 6 deletions app/routes/app.documents.$document.attach.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ import {ensureUser} from '~/lib/utils/ensure-user'
import {getPrisma} from '~/lib/prisma.server'
import {pageTitle} from '~/lib/utils/page-title'
import {Input} from '~/lib/components/input'
import {Button} from '~/lib/components/button'
import {getUploadMetaData} from '~/lib/utils/upload-handler.server'
import {getUploadHandler} from '~/lib/utils/upload-handler.server'
import {AButton} from '~/lib/components/button'
import {Button, AButton} from '~/lib/components/button'
import {
getUploadMetaData,
getUploadHandler
} from '~/lib/utils/upload-handler.server'

export type Attachment = {
uri: string
Expand Down Expand Up @@ -59,8 +60,10 @@ export const loader = async ({request, params}: LoaderFunctionArgs) => {
})
}

export const meta: MetaFunction<typeof loader> = ({data}) => {
return [{title: pageTitle('Document', data!.document.title, 'Attachments')}]
export const meta: MetaFunction<typeof loader> = ({data, matches}) => {
return [
{title: pageTitle(matches, 'Document', data!.document.title, 'Attachments')}
]
}

export const action = async ({request, params}: ActionFunctionArgs) => {
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.documents.$document.edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ export const action = async ({request, params}: ActionFunctionArgs) => {
return redirect(`/app/documents/${updatedDocument.id}`)
}

export const meta: MetaFunction<typeof loader> = ({data}) => {
return [{title: pageTitle('Document', data!.document.title, 'Edit')}]
export const meta: MetaFunction<typeof loader> = ({data, matches}) => {
return [{title: pageTitle(matches, 'Document', data!.document.title, 'Edit')}]
}

const DocumentEdit = () => {
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.documents._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export const loader = async ({request}: LoaderFunctionArgs) => {
return json({user, documents})
}

export const meta: MetaFunction = () => {
return [{title: pageTitle('Documents')}]
export const meta: MetaFunction = ({matches}) => {
return [{title: pageTitle(matches, 'Documents')}]
}

const DocumentsList = () => {
Expand Down
4 changes: 2 additions & 2 deletions app/routes/app.documents.add.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ export const action = async ({request}: ActionFunctionArgs) => {
return redirect(`/app/documents/${document.id}`)
}

export const meta: MetaFunction = () => {
return [{title: pageTitle('Documents', 'Add')}]
export const meta: MetaFunction = ({matches}) => {
return [{title: pageTitle(matches, 'Documents', 'Add')}]
}

const DocumentAdd = () => {
Expand Down
Loading

0 comments on commit 7bbc607

Please sign in to comment.