mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-04-15 17:24:10 +00:00
Add dark mode with CSS custom property theme system
Define 13 semantic color tokens (surface, text, border, hover) with light/dark values in themes.css. Register with Tailwind via @theme inline. Migrate all 335 Vue files from hardcoded gray/white classes to semantic tokens. Add theme toggle (sun/moon/system) in user avatar dropdown. Replace @tailwindcss/forms with custom form reset using theme vars. Add status badge and alert tokens for dark mode. Theme-aware chart grid/labels, skeleton placeholders, and editor. Inline script in <head> prevents flash of wrong theme on load. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -53,7 +53,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="mt-24">
|
||||
<label class="flex items-center justify-center text-gray-500">
|
||||
<label class="flex items-center justify-center text-muted">
|
||||
{{ $t('modules.no_modules_installed') }}
|
||||
</label>
|
||||
</div>
|
||||
@@ -61,10 +61,10 @@
|
||||
</div>
|
||||
|
||||
<BaseCard v-else class="mt-6">
|
||||
<h6 class="text-gray-900 text-lg font-medium">
|
||||
<h6 class="text-heading text-lg font-medium">
|
||||
{{ $t('modules.connect_installation') }}
|
||||
</h6>
|
||||
<p class="mt-1 text-sm text-gray-500">
|
||||
<p class="mt-1 text-sm text-muted">
|
||||
{{
|
||||
$t('modules.api_token_description', {
|
||||
url: globalStore.config.base_url.replace(/^http:\/\//, ''),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<ModulePlaceholder v-if="isFetchingInitialData" />
|
||||
<BasePage v-else class="bg-white">
|
||||
<BasePage v-else class="bg-surface">
|
||||
<BasePageHeader :title="moduleData.name">
|
||||
<BaseBreadcrumb>
|
||||
<BaseBreadcrumbItem :title="$t('general.home')" to="dashboard" />
|
||||
@@ -30,7 +30,7 @@
|
||||
<button
|
||||
v-if="thumbnail && videoUrl"
|
||||
:class="[
|
||||
'relative md:h-24 lg:h-36 rounded hover:bg-gray-50',
|
||||
'relative md:h-24 lg:h-36 rounded hover:bg-hover',
|
||||
{
|
||||
'outline-hidden ring-3 ring-offset-1 ring-primary-500':
|
||||
displayVideo,
|
||||
@@ -64,7 +64,7 @@
|
||||
id="tabs-1-tab-1"
|
||||
:key="ssIndx"
|
||||
:class="[
|
||||
'relative md:h-24 lg:h-36 rounded hover:bg-gray-50',
|
||||
'relative md:h-24 lg:h-36 rounded hover:bg-hover',
|
||||
{
|
||||
'outline-hidden ring-3 ring-offset-1 ring-primary-500':
|
||||
displayImage === screenshot.url,
|
||||
@@ -108,7 +108,7 @@
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="aspect-w-4 aspect-h-3 rounded-lg bg-gray-100 overflow-hidden"
|
||||
class="aspect-w-4 aspect-h-3 rounded-lg bg-surface-tertiary overflow-hidden"
|
||||
>
|
||||
<img
|
||||
:src="displayImage"
|
||||
@@ -146,7 +146,7 @@
|
||||
text-2xl
|
||||
font-extrabold
|
||||
tracking-tight
|
||||
text-gray-900
|
||||
text-heading
|
||||
sm:text-3xl
|
||||
"
|
||||
>
|
||||
@@ -159,7 +159,7 @@
|
||||
|
||||
<p
|
||||
v-if="moduleData.latest_module_version"
|
||||
class="text-sm text-gray-500 mt-2"
|
||||
class="text-sm text-muted mt-2"
|
||||
>
|
||||
{{ $t('modules.version') }}
|
||||
{{ moduleVersion }} ({{ $t('modules.last_updated') }}
|
||||
@@ -170,7 +170,7 @@
|
||||
|
||||
<!-- Module Description -->
|
||||
<div
|
||||
class="prose prose-sm max-w-none text-gray-500 text-sm my-10"
|
||||
class="prose prose-sm max-w-none text-muted text-sm my-10"
|
||||
v-html="moduleData.long_description"
|
||||
/>
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
<div v-if="!moduleData.purchased">
|
||||
<RadioGroup v-model="selectedPlan">
|
||||
<RadioGroupLabel class="sr-only"> Pricing plans </RadioGroupLabel>
|
||||
<div class="relative bg-white rounded-md -space-y-px">
|
||||
<div class="relative bg-surface rounded-md -space-y-px">
|
||||
<RadioGroupOption
|
||||
v-for="(size, sizeIdx) in modulePrice"
|
||||
:key="size.name"
|
||||
@@ -194,7 +194,7 @@
|
||||
: '',
|
||||
checked
|
||||
? 'bg-primary-50 border-primary-200 z-10'
|
||||
: 'border-gray-200',
|
||||
: 'border-line-default',
|
||||
'relative border p-4 flex flex-col cursor-pointer md:pl-4 md:pr-6 md:grid md:grid-cols-2 focus:outline-hidden',
|
||||
]"
|
||||
>
|
||||
@@ -203,18 +203,18 @@
|
||||
:class="[
|
||||
checked
|
||||
? 'bg-primary-600 border-transparent'
|
||||
: 'bg-white border-gray-300',
|
||||
: 'bg-surface border-line-strong',
|
||||
active ? 'ring-2 ring-offset-2 ring-primary-500' : '',
|
||||
'h-4 w-4 rounded-full border flex items-center justify-center',
|
||||
]"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<span class="rounded-full bg-white w-1.5 h-1.5" />
|
||||
<span class="rounded-full bg-surface w-1.5 h-1.5" />
|
||||
</span>
|
||||
<RadioGroupLabel
|
||||
as="span"
|
||||
:class="[
|
||||
checked ? 'text-primary-900' : 'text-gray-900',
|
||||
checked ? 'text-primary-900' : 'text-heading',
|
||||
'ml-3 font-medium',
|
||||
]"
|
||||
>
|
||||
@@ -226,7 +226,7 @@
|
||||
>
|
||||
<span
|
||||
:class="[
|
||||
checked ? 'text-primary-900' : 'text-gray-900',
|
||||
checked ? 'text-primary-900' : 'text-heading',
|
||||
'font-medium',
|
||||
]"
|
||||
>
|
||||
@@ -328,18 +328,18 @@
|
||||
<div class="mt-10"></div>
|
||||
|
||||
<!-- HighLights -->
|
||||
<div class="border-t border-gray-200 mt-10 pt-10">
|
||||
<h3 class="text-sm font-medium text-gray-900">
|
||||
<div class="border-t border-line-default mt-10 pt-10">
|
||||
<h3 class="text-sm font-medium text-heading">
|
||||
{{ $t('modules.what_you_get') }}
|
||||
</h3>
|
||||
<div class="mt-4 prose prose-sm max-w-none text-gray-500">
|
||||
<div class="mt-4 prose prose-sm max-w-none text-muted">
|
||||
<div
|
||||
class="prose prose-sm max-w-none text-gray-500 text-sm"
|
||||
class="prose prose-sm max-w-none text-muted text-sm"
|
||||
v-html="moduleData.highlights"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-gray-200 mt-10 pt-10">
|
||||
<div class="border-t border-line-default mt-10 pt-10">
|
||||
<div
|
||||
v-for="(link, key) in moduleData.links"
|
||||
:key="key"
|
||||
@@ -352,7 +352,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- Installation Steps -->
|
||||
<div v-if="isInstalling" class="border-t border-gray-200 mt-10 pt-10">
|
||||
<div v-if="isInstalling" class="border-t border-line-default mt-10 pt-10">
|
||||
<ul class="w-full p-0 list-none">
|
||||
<li
|
||||
v-for="step in installationSteps"
|
||||
@@ -362,7 +362,7 @@
|
||||
justify-between
|
||||
w-full
|
||||
py-3
|
||||
border-b border-gray-200 border-solid
|
||||
border-b border-line-default border-solid
|
||||
last:border-b-0
|
||||
"
|
||||
>
|
||||
@@ -370,7 +370,7 @@
|
||||
{{ $t(step.translationKey) }}
|
||||
</p>
|
||||
<div class="flex flex-row items-center">
|
||||
<span v-if="step.time" class="mr-3 text-xs text-gray-500">
|
||||
<span v-if="step.time" class="mr-3 text-xs text-muted">
|
||||
{{ step.time }}
|
||||
</span>
|
||||
<span
|
||||
@@ -386,8 +386,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Social Share -->
|
||||
<!-- <div class="border-t border-gray-200 mt-10 pt-10">
|
||||
<h3 class="text-sm font-medium text-gray-900">Share</h3>
|
||||
<!-- <div class="border-t border-line-default mt-10 pt-10">
|
||||
<h3 class="text-sm font-medium text-heading">Share</h3>
|
||||
<ul role="list" class="flex items-center space-x-6 mt-4">
|
||||
<li>
|
||||
<a
|
||||
@@ -398,8 +398,8 @@
|
||||
justify-center
|
||||
w-6
|
||||
h-6
|
||||
text-gray-400
|
||||
hover:text-gray-500
|
||||
text-subtle
|
||||
hover:text-muted
|
||||
"
|
||||
>
|
||||
<span class="sr-only">Share on Facebook</span>
|
||||
@@ -426,8 +426,8 @@
|
||||
justify-center
|
||||
w-6
|
||||
h-6
|
||||
text-gray-400
|
||||
hover:text-gray-500
|
||||
text-subtle
|
||||
hover:text-muted
|
||||
"
|
||||
>
|
||||
<span class="sr-only">Share on Instagram</span>
|
||||
@@ -454,8 +454,8 @@
|
||||
justify-center
|
||||
w-6
|
||||
h-6
|
||||
text-gray-400
|
||||
hover:text-gray-500
|
||||
text-subtle
|
||||
hover:text-muted
|
||||
"
|
||||
>
|
||||
<span class="sr-only">Share on Twitter</span>
|
||||
@@ -485,13 +485,13 @@
|
||||
"
|
||||
>
|
||||
<TabGroup as="div">
|
||||
<TabList class="-mb-px flex space-x-8 border-b border-gray-200">
|
||||
<TabList class="-mb-px flex space-x-8 border-b border-line-default">
|
||||
<Tab v-slot="{ selected }" as="template">
|
||||
<button
|
||||
:class="[
|
||||
selected
|
||||
? 'border-primary-600 text-primary-600'
|
||||
: 'border-transparent text-gray-700 hover:text-gray-800 hover:border-gray-300',
|
||||
: 'border-transparent text-body hover:text-heading hover:border-line-strong',
|
||||
'whitespace-nowrap py-6 border-b-2 font-medium text-sm',
|
||||
]"
|
||||
>
|
||||
@@ -503,7 +503,7 @@
|
||||
:class="[
|
||||
selected
|
||||
? 'border-primary-600 text-primary-600'
|
||||
: 'border-transparent text-gray-700 hover:text-gray-800 hover:border-gray-300',
|
||||
: 'border-transparent text-body hover:text-heading hover:border-line-strong',
|
||||
'whitespace-nowrap py-6 border-b-2 font-medium text-sm',
|
||||
]"
|
||||
>
|
||||
@@ -515,7 +515,7 @@
|
||||
:class="[
|
||||
selected
|
||||
? 'border-primary-600 text-primary-600'
|
||||
: 'border-transparent text-gray-700 hover:text-gray-800 hover:border-gray-300',
|
||||
: 'border-transparent text-body hover:text-heading hover:border-line-strong',
|
||||
'whitespace-nowrap py-6 border-b-2 font-medium text-sm',
|
||||
]"
|
||||
>
|
||||
@@ -531,7 +531,7 @@
|
||||
<div
|
||||
v-for="(review, reviewIdx) in moduleData.reviews"
|
||||
:key="reviewIdx"
|
||||
class="flex text-sm text-gray-500 space-x-4"
|
||||
class="flex text-sm text-muted space-x-4"
|
||||
>
|
||||
<div class="flex-none py-10">
|
||||
<span
|
||||
@@ -542,7 +542,7 @@
|
||||
h-12
|
||||
w-12
|
||||
rounded-full
|
||||
bg-gray-500
|
||||
bg-surface-secondary0
|
||||
"
|
||||
>
|
||||
<span
|
||||
@@ -559,11 +559,11 @@
|
||||
</div>
|
||||
<div
|
||||
:class="[
|
||||
reviewIdx === 0 ? '' : 'border-t border-gray-200',
|
||||
reviewIdx === 0 ? '' : 'border-t border-line-default',
|
||||
'py-10',
|
||||
]"
|
||||
>
|
||||
<h3 class="font-medium text-gray-900">
|
||||
<h3 class="font-medium text-heading">
|
||||
{{ review.customer.name }}
|
||||
</h3>
|
||||
<p>
|
||||
@@ -575,28 +575,28 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mt-4 prose prose-sm max-w-none text-gray-500"
|
||||
class="mt-4 prose prose-sm max-w-none text-muted"
|
||||
v-html="review.feedback"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="flex w-full items-center justify-center">
|
||||
<p class="text-gray-500 mt-10 text-sm">
|
||||
<p class="text-muted mt-10 text-sm">
|
||||
{{ $t('modules.no_reviews_found') }}
|
||||
</p>
|
||||
</div>
|
||||
</TabPanel>
|
||||
|
||||
<!-- FAQs -->
|
||||
<TabPanel as="dl" class="text-sm text-gray-500">
|
||||
<TabPanel as="dl" class="text-sm text-muted">
|
||||
<h3 class="sr-only">Frequently Asked Questions</h3>
|
||||
|
||||
<template v-for="faq in moduleData.faq" :key="faq.question">
|
||||
<dt class="mt-10 font-medium text-gray-900">
|
||||
<dt class="mt-10 font-medium text-heading">
|
||||
{{ faq.question }}
|
||||
</dt>
|
||||
<dd class="mt-2 prose prose-sm max-w-none text-gray-500">
|
||||
<dd class="mt-2 prose prose-sm max-w-none text-muted">
|
||||
<p>{{ faq.answer }}</p>
|
||||
</dd>
|
||||
</template>
|
||||
@@ -607,7 +607,7 @@
|
||||
<h3 class="sr-only">License</h3>
|
||||
|
||||
<div
|
||||
class="prose prose-sm max-w-none text-gray-500"
|
||||
class="prose prose-sm max-w-none text-muted"
|
||||
v-html="moduleData.license"
|
||||
/>
|
||||
</TabPanel>
|
||||
@@ -622,7 +622,7 @@
|
||||
class="mt-24 sm:mt-32 lg:max-w-none"
|
||||
>
|
||||
<div class="flex items-center justify-between space-x-4">
|
||||
<h2 class="text-lg font-medium text-gray-900">
|
||||
<h2 class="text-lg font-medium text-heading">
|
||||
{{ $t('modules.other_modules') }}
|
||||
</h2>
|
||||
<a
|
||||
@@ -955,7 +955,7 @@ function statusClass(step) {
|
||||
|
||||
switch (status) {
|
||||
case 'pending':
|
||||
return 'text-primary-800 bg-gray-200'
|
||||
return 'text-primary-800 bg-surface-muted'
|
||||
case 'finished':
|
||||
return 'text-teal-500 bg-teal-100'
|
||||
case 'running':
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
class="
|
||||
relative
|
||||
shadow-md
|
||||
border-2 border-gray-200/60
|
||||
border-2 border-line-default/60
|
||||
rounded-lg
|
||||
cursor-pointer
|
||||
overflow-hidden
|
||||
@@ -55,7 +55,7 @@
|
||||
:src="data.cover"
|
||||
alt="cover"
|
||||
/>
|
||||
<div class="px-6 py-5 flex flex-col bg-gray-50 flex-1 justify-between">
|
||||
<div class="px-6 py-5 flex flex-col bg-surface-secondary flex-1 justify-between">
|
||||
<span
|
||||
class="
|
||||
text-lg
|
||||
@@ -85,7 +85,7 @@
|
||||
</div>
|
||||
<base-text
|
||||
:text="data.short_description"
|
||||
class="pt-4 text-gray-500 h-16 line-clamp-2"
|
||||
class="pt-4 text-muted h-16 line-clamp-2"
|
||||
>
|
||||
</base-text>
|
||||
<div
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div
|
||||
class="
|
||||
shadow-md
|
||||
border-2 border-gray-200/60
|
||||
border-2 border-line-default/60
|
||||
rounded-lg
|
||||
cursor-pointer
|
||||
overflow-hidden
|
||||
@@ -11,7 +11,7 @@
|
||||
"
|
||||
>
|
||||
<BaseContentPlaceholdersBox class="h-48 lg:h-64 md:h-48 w-full" rounded />
|
||||
<div class="px-6 py-5 flex flex-col bg-gray-50 flex-1 justify-between">
|
||||
<div class="px-6 py-5 flex flex-col bg-surface-secondary flex-1 justify-between">
|
||||
<BaseContentPlaceholdersText class="w-32 h-8" :lines="1" rounded />
|
||||
<div class="flex items-center mt-2">
|
||||
<BaseContentPlaceholdersBox
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<BaseContentPlaceholders rounded>
|
||||
<BasePage class="bg-white">
|
||||
<BasePage class="bg-surface">
|
||||
|
||||
<!-- Breadcrumb-->
|
||||
<BaseContentPlaceholdersText class="mt-4 h-8 w-40" :lines="1"/>
|
||||
@@ -70,7 +70,7 @@
|
||||
<div class="mt-10"></div>
|
||||
|
||||
<!-- HightLight -->
|
||||
<div class="border-t border-gray-200 mt-10 pt-10">
|
||||
<div class="border-t border-line-default mt-10 pt-10">
|
||||
<div>
|
||||
<BaseContentPlaceholdersText class="w-24 h-6" :lines="1" />
|
||||
<BaseContentPlaceholdersText
|
||||
@@ -81,7 +81,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Social Share -->
|
||||
<div class="border-t border-gray-200 mt-10 pt-10">
|
||||
<div class="border-t border-line-default mt-10 pt-10">
|
||||
<BaseContentPlaceholdersText class="h-6 w-24" :lines="1" />
|
||||
<BaseContentPlaceholdersText class="h-10 w-32 mt-4" :lines="1" />
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<router-link class="relative group" :to="`/admin/modules/${data.slug}`">
|
||||
<div class="relative group">
|
||||
<div class="aspect-w-4 aspect-h-3 rounded-lg overflow-hidden bg-gray-100">
|
||||
<div class="aspect-w-4 aspect-h-3 rounded-lg overflow-hidden bg-surface-tertiary">
|
||||
<img :src="data.cover" class="object-center object-cover" />
|
||||
<div
|
||||
class="flex items-end opacity-0 p-4 group-hover:opacity-100"
|
||||
@@ -32,7 +32,7 @@
|
||||
justify-between
|
||||
text-base
|
||||
font-medium
|
||||
text-gray-900
|
||||
text-heading
|
||||
space-x-8
|
||||
cursor-pointer
|
||||
"
|
||||
|
||||
Reference in New Issue
Block a user