diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index f0ba489..e4316ad 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -31,113 +31,25 @@ jobs: with: access_token: ${{ github.token }} + # A copy of InvoiceShelf's own workflow used to run here: `pint` from a + # vendor directory the module never installs, `php artisan test` and a + # `make dist` of InvoiceShelf.zip, none of which a module has. It is now the + # style check alone; release.yaml builds the module's zip. php_syntax_errors: name: 1️⃣ PHP Code Style errors runs-on: ubuntu-latest needs: - kill_previous steps: - - name: Set up PHP + - name: Set up PHP with Pint uses: shivammathur/setup-php@v2 with: - php-version: 8.2 + php-version: 8.4 + tools: pint:1.29.0 + coverage: none - name: Checkout code uses: actions/checkout@v4 - - name: Install dependencies - uses: ramsey/composer-install@v2 - - - name: Check source code for syntax errors - run: ./vendor/bin/pint --test - - tests: - name: 2️⃣ PHP ${{ matrix.php-version }} Tests - needs: - - php_syntax_errors - runs-on: ubuntu-latest - strategy: - matrix: - php-version: - - 8.2 - - 8.3 - env: - extensions: bcmath, curl, dom, gd, imagick, json, libxml, mbstring, pcntl, pdo, pdo_mysql, zip - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup PHP Action - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-version }} - extensions: ${{ env.extensions }} - coverage: xdebug - tools: pecl, composer - - - name: Install Composer dependencies - uses: ramsey/composer-install@v2 - - - name: Use Node.js 20 - uses: actions/setup-node@v3 - with: - node-version: 20 - - - name: Install - run: npm install - - - name: Compile Front-end - run: npm run build - - - name: Apply tests ${{ matrix.php-version }} - run: php artisan test - - createReleaseFile: - name: 3️⃣ Build / Upload - Release File - if: github.ref_type == 'tag' - needs: - - tests - runs-on: ubuntu-latest - env: - extensions: bcmath, curl, dom, gd, imagick, json, libxml, mbstring, pcntl, pdo, pdo_mysql, zip - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: 8.2 - extensions: ${{ env.extensions }} - coverage: none - - - name: Install Composer dependencies - uses: ramsey/composer-install@v2 - with: - composer-options: --no-dev - - - name: Use Node.js 20 - uses: actions/setup-node@v3 - with: - node-version: 20 - - - name: Install - run: npm install - - - name: Compile Front-end - run: npm run build - - - name: Build Dist - run: | - make clean dist - - - name: Upload package - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ github.token }} - file: InvoiceShelf.zip - asset_name: InvoiceShelf.zip - tag: ${{ github.ref }} - overwrite: true + - name: Check code style + run: pint --test diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 159dec1..0e0225b 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -13,15 +13,18 @@ jobs: runs-on: [ubuntu-latest] steps: - - name: Checkout InvoiceShelf + # The module is for InvoiceShelf 2.x and bundles host code from it, so it is + # built against the 2.x branch, not the default branch (3.x). + - name: Checkout InvoiceShelf 2.x uses: actions/checkout@v4 with: repository: InvoiceShelf/InvoiceShelf + ref: 2.x - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.2 + php-version: 8.4 extensions: bcmath, curl, dom, gd, imagick, json, libxml, mbstring, pcntl, pdo, pdo_mysql, zip coverage: none @@ -30,13 +33,17 @@ jobs: with: composer-options: --no-dev + - name: Set up pnpm + uses: pnpm/action-setup@v4 + - name: Use Node.js uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 - - name: Install and build InvoiceShelf node dependencies - run: npm install && npm run build + # The module build resolves pinia, axios and host components from here. + - name: Install InvoiceShelf node dependencies + run: pnpm install --frozen-lockfile - name: Checkout WhiteLabel module uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b34843..3389b45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.1.4](https://github.com/InvoiceShelf/module-whitelabel/compare/v1.1.3...v1.1.4) (2026-09-24) + + +### Bug Fixes + +* work on InvoiceShelf 2.3.0 and later: the store uses Pinia 3's `defineStore(id, options)` form and the host's HTTP client instead of the removed `window.axios` +* the module's stylesheet no longer breaks the app's layout on InvoiceShelf 2.3.0 and later (missing sidebar and header controls): it now sits in the app's Tailwind 4 `utilities` cascade layer instead of outside any layer +* saving the customer portal settings with an empty page title no longer fails with a server error +* themes apply again on InvoiceShelf 2.3.0 and later, which reads the colour variables as full colours (Tailwind 4) rather than r, g, b triplets +* build releases against InvoiceShelf's `2.x` branch with its toolchain (PHP 8.4, Node 24, pnpm) + + +### Documentation + +* say the module is for InvoiceShelf 2.x only, add a compatibility table and the cache step after installing + ### [1.1.3](https://github.com/InvoiceShelf/module-whitelabel/compare/v1.1.2...v1.1.3) (2025-02-25) diff --git a/Config/config.php b/Config/config.php index 40022f7..87bf112 100644 --- a/Config/config.php +++ b/Config/config.php @@ -1,5 +1,5 @@ 'WhiteLabel' + 'name' => 'WhiteLabel', ]; diff --git a/Database/Seeders/WhiteLabelDatabaseSeeder.php b/Database/Seeders/WhiteLabelDatabaseSeeder.php index 9f68d6f..9a150c7 100644 --- a/Database/Seeders/WhiteLabelDatabaseSeeder.php +++ b/Database/Seeders/WhiteLabelDatabaseSeeder.php @@ -6,7 +6,6 @@ use App\Models\User; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Seeder; -use Illuminate\Support\Facades\DB; use Modules\WhiteLabel\Helpers\VersionHelper; if (VersionHelper::checkAppVersion('<', '2.0.0')) { @@ -14,8 +13,6 @@ VersionHelper::aliasClass('InvoiceShelf\Models\CompanySetting', 'App\Models\CompanySetting'); } - - class WhiteLabelDatabaseSeeder extends Seeder { /** @@ -32,11 +29,11 @@ public function run() /** * check if customer portal page title entry exists */ - if (!CompanySetting::getSetting('customer_portal_page_title', $company_id)) { - CompanySetting::setSettings( - ['customer_portal_page_title' => ''], - $company_id - ); + if (! CompanySetting::getSetting('customer_portal_page_title', $company_id)) { + CompanySetting::setSettings( + ['customer_portal_page_title' => ''], + $company_id + ); } } diff --git a/Helpers/VersionHelper.php b/Helpers/VersionHelper.php index 421cbd8..bb7acd8 100644 --- a/Helpers/VersionHelper.php +++ b/Helpers/VersionHelper.php @@ -1,4 +1,5 @@ * @copyright 2024 Rihards Simanovics * @license GNU GPLv3 + * * @version GIT: + * * @link https://invoiceshelf.com */ @@ -33,9 +36,8 @@ class VersionHelper * This method checks the application version against a specified version using a comparison operator. * It temporarily aliases the Setting class to access the version information. * - * @param string $operator The comparison operator (e.g., '<', '>='). - * @param string $version The version to compare against. - * + * @param string $operator The comparison operator (e.g., '<', '>='). + * @param string $version The version to compare against. * @return bool True if the comparison is valid, false otherwise. */ public static function checkAppVersion($operator, $version) @@ -49,12 +51,12 @@ public static function checkAppVersion($operator, $version) /** * Alias old namespace classes to new ones if necessary. * - * @param string $oldClass The old class name with namespace. - * @param string $newClass The new class name with namespace. + * @param string $oldClass The old class name with namespace. + * @param string $newClass The new class name with namespace. */ public static function aliasClass($newClass, $oldClass) { - if (!class_exists($oldClass) && class_exists($newClass)) { + if (! class_exists($oldClass) && class_exists($newClass)) { class_alias($newClass, $oldClass); } } diff --git a/Http/Controllers/UploadLogoController.php b/Http/Controllers/UploadLogoController.php index 1af2c10..7aa9135 100644 --- a/Http/Controllers/UploadLogoController.php +++ b/Http/Controllers/UploadLogoController.php @@ -28,7 +28,7 @@ public function uploadLogos(Request $request) $customerPortalLogoUrl = 'whitelabel/customer_portal_logo/'.$imageName; $settings = [ - 'customer_portal_logo' => $customerPortalLogoUrl + 'customer_portal_logo' => $customerPortalLogoUrl, ]; CompanySetting::setSettings($settings, $request->header('company')); @@ -56,7 +56,7 @@ public function uploadLogos(Request $request) 'success' => true, 'customerPortalLogoUrl' => $customerPortalLogoUrl, 'adminPortalLogoUrl' => $adminPortalLogoUrl, - 'loginPageLogoUrl' => $loginPageLogoUrl + 'loginPageLogoUrl' => $loginPageLogoUrl, ], 200); } } diff --git a/Http/Controllers/WhiteLabelController.php b/Http/Controllers/WhiteLabelController.php index 79ff3bd..7ab0df6 100644 --- a/Http/Controllers/WhiteLabelController.php +++ b/Http/Controllers/WhiteLabelController.php @@ -10,6 +10,7 @@ class WhiteLabelController extends Controller { /** * Display a listing of the resource. + * * @return Renderable */ public function index() @@ -19,6 +20,7 @@ public function index() /** * Show the form for creating a new resource. + * * @return Renderable */ public function create() @@ -28,7 +30,7 @@ public function create() /** * Store a newly created resource in storage. - * @param Request $request + * * @return Renderable */ public function store(Request $request) @@ -38,7 +40,8 @@ public function store(Request $request) /** * Show the specified resource. - * @param int $id + * + * @param int $id * @return Renderable */ public function show($id) @@ -48,7 +51,8 @@ public function show($id) /** * Show the form for editing the specified resource. - * @param int $id + * + * @param int $id * @return Renderable */ public function edit($id) @@ -58,8 +62,8 @@ public function edit($id) /** * Update the specified resource in storage. - * @param Request $request - * @param int $id + * + * @param int $id * @return Renderable */ public function update(Request $request, $id) @@ -69,7 +73,8 @@ public function update(Request $request, $id) /** * Remove the specified resource from storage. - * @param int $id + * + * @param int $id * @return Renderable */ public function destroy($id) diff --git a/Listeners/ModuleDisabledListener.php b/Listeners/ModuleDisabledListener.php index a87022b..db66e00 100644 --- a/Listeners/ModuleDisabledListener.php +++ b/Listeners/ModuleDisabledListener.php @@ -28,7 +28,6 @@ public function __construct() /** * Handle the event. * - * @param ModuleDisabledEvent $event * @return void */ public function handle(ModuleDisabledEvent $event) diff --git a/Providers/WhiteLabelServiceProvider.php b/Providers/WhiteLabelServiceProvider.php index 5a016f7..3295f8f 100644 --- a/Providers/WhiteLabelServiceProvider.php +++ b/Providers/WhiteLabelServiceProvider.php @@ -5,8 +5,8 @@ use App\Events\ModuleDisabledEvent; use App\Services\Module\ModuleFacade; use Illuminate\Support\ServiceProvider; -use Modules\WhiteLabel\Listeners\ModuleDisabledListener; use Modules\WhiteLabel\Helpers\VersionHelper; +use Modules\WhiteLabel\Listeners\ModuleDisabledListener; if (VersionHelper::checkAppVersion('<', '2.0.0')) { VersionHelper::aliasClass('InvoiceShelf\Events\ModuleDisabledEvent', 'App\Events\ModuleDisabledEvent'); @@ -80,7 +80,7 @@ public function registerViews() $sourcePath = module_path($this->moduleName, 'Resources/views'); $this->publishes([ - $sourcePath => $viewPath + $sourcePath => $viewPath, ], ['views', $this->moduleNameLower.'-module-views']); $this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower); @@ -134,7 +134,7 @@ public function registerMenu() 'icon' => 'TagIcon', 'owner_only' => true, 'ability' => '', - 'model' => '' + 'model' => '', ]; \Menu::make('setting_menu', function ($menu) use ($data) { diff --git a/README.md b/README.md index daa40b1..aee377b 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,17 @@ Adds ability to customise your InvoiceShelf instance with logo and brand color. +> [!IMPORTANT] +> This module is for **InvoiceShelf 2.x only**. On 2.3.0 and later it needs version 1.1.4 or newer; +> 1.1.3 and older show a blank settings page there. It does not run on InvoiceShelf 3.x. + ![Preview of Invoice Shelf, White Label Settings page](./preview.png) ## Table of Contents - [Invoice Shelf - White Label Module](#invoice-shelf---white-label-module) - [Table of Contents](#table-of-contents) + - [Compatibility](#compatibility) - [Installation](#installation) - [Update](#update) - [Hard Stops](#hard-stops) @@ -17,25 +22,36 @@ Adds ability to customise your InvoiceShelf instance with logo and brand color. - [Troubleshooting](#troubleshooting) - [Copyright](#copyright) +## Compatibility + +| InvoiceShelf | White Label module | +| --- | --- | +| 2.3.0 and later | 1.1.4 or newer | +| 1.3.0 to 2.2.x | 1.1.0 to 1.1.3 | +| 3.x | not supported | + ## Installation 1. Download the zip with pre-built module from the [latest release](https://github.com/InvoiceShelf/module-whitelabel/releases/latest) in this repo. Alternatively you can build from source, for that follow the steps in the [development](#development) section. 2. Create `/Modules/` dir in your server InvoiceShelf project root. **NOTE:** make sure it's capitalised like in example, it's not a typo. 3. Upload the `WhiteLabel.zip` into the newly created `/Modules/` dir. 4. Unzip it. -5. In your server InvoiceShelf project `/` root dir, run `php artisan install:module WhiteLabel ` e.g. `php artisan install:module WhiteLabel 1.1.1`, please consult with `package.json` for correct release version number inside the release artifact. -6. (optional) If you have any issues with your installed module, try clearing your browser's `cache`, `cookies`, and/or `site data`. +5. In your server InvoiceShelf project `/` root dir, run `php artisan install:module WhiteLabel ` e.g. `php artisan install:module WhiteLabel 1.1.4`, please consult with `package.json` for correct release version number inside the release artifact. +6. Run `php artisan optimize:clear`, or restart the container if you run InvoiceShelf in Docker. The + Docker image caches its routes when it starts, so the module's pages return 404 until then. +7. (optional) If you have any issues with your installed module, try clearing your browser's `cache`, `cookies`, and/or `site data`. ## Update 1. Download the zip with pre-built module from the [latest release](https://github.com/InvoiceShelf/module-whitelabel/releases/latest) in this repo. Alternatively you can build from source, for that follow the steps in the [development](#development) section. -2. Upload the `WhiteLabel.zip` into the newly created `/Modules/` dir. -3. Remove old `WhiteLabel/` module folder. -4. Unzip it and visit the site. +2. Upload the `WhiteLabel.zip` into the `/Modules/` dir. +3. Remove the old `WhiteLabel/` module folder. +4. Unzip it, run `php artisan optimize:clear` (or restart the container in Docker) and visit the site. ### Hard Stops - InvoiceShelf >= 1.3.0 (upgrade this module to 1.1.0) +- InvoiceShelf >= 2.3.0 (upgrade this module to 1.1.4) ## Development @@ -44,15 +60,15 @@ This is a step by step guide on how to get started, with development. ### Prerequisites 1. nvm/fnm (optional) -2. Node JS: `20 LTS` -3. `yarn` +2. Node JS: `24` (what InvoiceShelf 2.x requires) +3. `pnpm` for InvoiceShelf and `yarn` for this module ### Steps -1. Clone the [InvoiceShelf repo](https://github.com/InvoiceShelf/InvoiceShelf) - needed for the admin components. In the future it's likely to be just a node package and you wont need this step. +1. Clone the [InvoiceShelf repo](https://github.com/InvoiceShelf/InvoiceShelf) and check out the `2.x` branch - needed for the admin components. In the future it's likely to be just a node package and you wont need this step. 2. Create `Modules/` dir, in the root dir. 3. Clone this repo into `WhiteLabel/` dir inside `/Modules/`. -4. Initialise `node_modules` by running `yarn` inside `/` of the InvoiceShelf repo. +4. Initialise `node_modules` by running `pnpm install` inside `/` of the InvoiceShelf repo. 5. Initialise `node_modules` by running `yarn` inside `/Modules/WhiteLabel/` of this repo. 6. Make the changes you wish to make. 7. Run `yarn build`, new `/Modules/WhiteLabel/dist/` dir will be created with built `css` and `js` bundles. diff --git a/Resources/sass/themes.scss b/Resources/sass/themes.scss index 014d5cd..1847fb7 100644 --- a/Resources/sass/themes.scss +++ b/Resources/sass/themes.scss @@ -1,233 +1,235 @@ +// Full colours, not bare r, g, b triplets: InvoiceShelf 2.3.0 moved to Tailwind 4, +// which reads these variables as colours directly. .theme-invoiceShelf { - --color-primary-50: 247, 246, 253; - --color-primary-100: 238, 238, 251; - --color-primary-200: 213, 212, 245; - --color-primary-300: 188, 185, 239; - --color-primary-400: 138, 133, 228; - --color-primary-500: 88, 81, 216; - --color-primary-600: 79, 73, 194; - --color-primary-700: 53, 49, 130; - --color-primary-800: 40, 36, 97; - --color-primary-900: 26, 24, 65; + --color-primary-50: rgb(247, 246, 253); + --color-primary-100: rgb(238, 238, 251); + --color-primary-200: rgb(213, 212, 245); + --color-primary-300: rgb(188, 185, 239); + --color-primary-400: rgb(138, 133, 228); + --color-primary-500: rgb(88, 81, 216); + --color-primary-600: rgb(79, 73, 194); + --color-primary-700: rgb(53, 49, 130); + --color-primary-800: rgb(40, 36, 97); + --color-primary-900: rgb(26, 24, 65); } .theme-red { - --color-primary-50: 254, 242, 242; - --color-primary-100: 254, 226, 226; - --color-primary-200: 254, 202, 202; - --color-primary-300: 252, 165, 165; - --color-primary-400: 248, 113, 113; - --color-primary-500: 239, 68, 68; - --color-primary-600: 220, 38, 38; - --color-primary-700: 185, 28, 28; - --color-primary-800: 153, 27, 27; - --color-primary-900: 127, 29, 29; + --color-primary-50: rgb(254, 242, 242); + --color-primary-100: rgb(254, 226, 226); + --color-primary-200: rgb(254, 202, 202); + --color-primary-300: rgb(252, 165, 165); + --color-primary-400: rgb(248, 113, 113); + --color-primary-500: rgb(239, 68, 68); + --color-primary-600: rgb(220, 38, 38); + --color-primary-700: rgb(185, 28, 28); + --color-primary-800: rgb(153, 27, 27); + --color-primary-900: rgb(127, 29, 29); } .theme-orange { - --color-primary-50: 255, 247, 237; - --color-primary-100: 255, 237, 213; - --color-primary-200: 254, 215, 170; - --color-primary-300: 253, 186, 116; - --color-primary-400: 251, 146, 60; - --color-primary-500: 249, 115, 22; - --color-primary-600: 234, 88, 12; - --color-primary-700: 194, 65, 12; - --color-primary-800: 154, 52, 18; - --color-primary-900: 124, 45, 18; + --color-primary-50: rgb(255, 247, 237); + --color-primary-100: rgb(255, 237, 213); + --color-primary-200: rgb(254, 215, 170); + --color-primary-300: rgb(253, 186, 116); + --color-primary-400: rgb(251, 146, 60); + --color-primary-500: rgb(249, 115, 22); + --color-primary-600: rgb(234, 88, 12); + --color-primary-700: rgb(194, 65, 12); + --color-primary-800: rgb(154, 52, 18); + --color-primary-900: rgb(124, 45, 18); } .theme-amber { - --color-primary-50: 255, 251, 235; - --color-primary-100: 254, 243, 199; - --color-primary-200: 253, 230, 138; - --color-primary-300: 252, 211, 77; - --color-primary-400: 251, 191, 36; - --color-primary-500: 245, 158, 11; - --color-primary-600: 217, 119, 6; - --color-primary-700: 180, 83, 9; - --color-primary-800: 146, 64, 14; - --color-primary-900: 120, 53, 15; + --color-primary-50: rgb(255, 251, 235); + --color-primary-100: rgb(254, 243, 199); + --color-primary-200: rgb(253, 230, 138); + --color-primary-300: rgb(252, 211, 77); + --color-primary-400: rgb(251, 191, 36); + --color-primary-500: rgb(245, 158, 11); + --color-primary-600: rgb(217, 119, 6); + --color-primary-700: rgb(180, 83, 9); + --color-primary-800: rgb(146, 64, 14); + --color-primary-900: rgb(120, 53, 15); } .theme-yellow { - --color-primary-50: 254, 252, 232; - --color-primary-100: 254, 249, 195; - --color-primary-200: 254, 240, 138; - --color-primary-300: 253, 224, 71; - --color-primary-400: 250, 204, 21; - --color-primary-500: 234, 179, 8; - --color-primary-600: 202, 138, 4; - --color-primary-700: 161, 98, 7; - --color-primary-800: 133, 77, 14; - --color-primary-900: 113, 63, 18; + --color-primary-50: rgb(254, 252, 232); + --color-primary-100: rgb(254, 249, 195); + --color-primary-200: rgb(254, 240, 138); + --color-primary-300: rgb(253, 224, 71); + --color-primary-400: rgb(250, 204, 21); + --color-primary-500: rgb(234, 179, 8); + --color-primary-600: rgb(202, 138, 4); + --color-primary-700: rgb(161, 98, 7); + --color-primary-800: rgb(133, 77, 14); + --color-primary-900: rgb(113, 63, 18); } // .theme-lime { -// --color-primary-50: 247, 254, 231; -// --color-primary-100: 236, 252, 203; -// --color-primary-200: 217, 249, 157; -// --color-primary-300: 190, 242, 100; -// --color-primary-400: 163, 230, 53; -// --color-primary-500: 132, 204, 22; -// --color-primary-600: 101, 163, 13; -// --color-primary-700: 77, 124, 15; -// --color-primary-800: 63, 98, 18; -// --color-primary-900: 54, 83, 20; +// --color-primary-50: rgb(247, 254, 231); +// --color-primary-100: rgb(236, 252, 203); +// --color-primary-200: rgb(217, 249, 157); +// --color-primary-300: rgb(190, 242, 100); +// --color-primary-400: rgb(163, 230, 53); +// --color-primary-500: rgb(132, 204, 22); +// --color-primary-600: rgb(101, 163, 13); +// --color-primary-700: rgb(77, 124, 15); +// --color-primary-800: rgb(63, 98, 18); +// --color-primary-900: rgb(54, 83, 20); // } .theme-green { - --color-primary-50: 240, 253, 244; - --color-primary-100: 220, 252, 231; - --color-primary-200: 187, 247, 208; - --color-primary-300: 134, 239, 172; - --color-primary-400: 74, 222, 128; - --color-primary-500: 34, 197, 94; - --color-primary-600: 22, 163, 74; - --color-primary-700: 21, 128, 61; - --color-primary-800: 22, 101, 52; - --color-primary-900: 20, 83, 45; + --color-primary-50: rgb(240, 253, 244); + --color-primary-100: rgb(220, 252, 231); + --color-primary-200: rgb(187, 247, 208); + --color-primary-300: rgb(134, 239, 172); + --color-primary-400: rgb(74, 222, 128); + --color-primary-500: rgb(34, 197, 94); + --color-primary-600: rgb(22, 163, 74); + --color-primary-700: rgb(21, 128, 61); + --color-primary-800: rgb(22, 101, 52); + --color-primary-900: rgb(20, 83, 45); } .theme-emerald { - --color-primary-50: 236, 253, 245; - --color-primary-100: 209, 250, 229; - --color-primary-200: 167, 243, 208; - --color-primary-300: 110, 231, 183; - --color-primary-400: 52, 211, 153; - --color-primary-500: 16, 185, 129; - --color-primary-600: 5, 150, 105; - --color-primary-700: 4, 120, 87; - --color-primary-800: 6, 95, 70; - --color-primary-900: 6, 78, 59; + --color-primary-50: rgb(236, 253, 245); + --color-primary-100: rgb(209, 250, 229); + --color-primary-200: rgb(167, 243, 208); + --color-primary-300: rgb(110, 231, 183); + --color-primary-400: rgb(52, 211, 153); + --color-primary-500: rgb(16, 185, 129); + --color-primary-600: rgb(5, 150, 105); + --color-primary-700: rgb(4, 120, 87); + --color-primary-800: rgb(6, 95, 70); + --color-primary-900: rgb(6, 78, 59); } .theme-teal { - --color-primary-50: 240, 253, 250; - --color-primary-100: 204, 251, 241; - --color-primary-200: 153, 246, 228; - --color-primary-300: 94, 234, 212; - --color-primary-400: 45, 212, 191; - --color-primary-500: 20, 184, 166; - --color-primary-600: 13, 148, 136; - --color-primary-700: 15, 118, 110; - --color-primary-800: 17, 94, 89; - --color-primary-900: 19, 78, 74; + --color-primary-50: rgb(240, 253, 250); + --color-primary-100: rgb(204, 251, 241); + --color-primary-200: rgb(153, 246, 228); + --color-primary-300: rgb(94, 234, 212); + --color-primary-400: rgb(45, 212, 191); + --color-primary-500: rgb(20, 184, 166); + --color-primary-600: rgb(13, 148, 136); + --color-primary-700: rgb(15, 118, 110); + --color-primary-800: rgb(17, 94, 89); + --color-primary-900: rgb(19, 78, 74); } .theme-cyan { - --color-primary-50: 236, 254, 255; - --color-primary-100: 207, 250, 254; - --color-primary-200: 165, 243, 252; - --color-primary-300: 103, 232, 249; - --color-primary-400: 34, 211, 238; - --color-primary-500: 6, 182, 212; - --color-primary-600: 8, 145, 178; - --color-primary-700: 14, 116, 144; - --color-primary-800: 21, 94, 117; - --color-primary-900: 22, 78, 99; + --color-primary-50: rgb(236, 254, 255); + --color-primary-100: rgb(207, 250, 254); + --color-primary-200: rgb(165, 243, 252); + --color-primary-300: rgb(103, 232, 249); + --color-primary-400: rgb(34, 211, 238); + --color-primary-500: rgb(6, 182, 212); + --color-primary-600: rgb(8, 145, 178); + --color-primary-700: rgb(14, 116, 144); + --color-primary-800: rgb(21, 94, 117); + --color-primary-900: rgb(22, 78, 99); } .theme-sky { - --color-primary-50: 240, 249, 255; - --color-primary-100: 224, 242, 254; - --color-primary-200: 186, 230, 253; - --color-primary-300: 125, 211, 252; - --color-primary-400: 56, 189, 248; - --color-primary-500: 14, 165, 233; - --color-primary-600: 2, 132, 199; - --color-primary-700: 3, 105, 161; - --color-primary-800: 7, 89, 133; - --color-primary-900: 12, 74, 110; + --color-primary-50: rgb(240, 249, 255); + --color-primary-100: rgb(224, 242, 254); + --color-primary-200: rgb(186, 230, 253); + --color-primary-300: rgb(125, 211, 252); + --color-primary-400: rgb(56, 189, 248); + --color-primary-500: rgb(14, 165, 233); + --color-primary-600: rgb(2, 132, 199); + --color-primary-700: rgb(3, 105, 161); + --color-primary-800: rgb(7, 89, 133); + --color-primary-900: rgb(12, 74, 110); } .theme-blue { - --color-primary-50: 239, 246, 255; - --color-primary-100: 219, 234, 254; - --color-primary-200: 191, 219, 254; - --color-primary-300: 147, 197, 253; - --color-primary-400: 96, 165, 250; - --color-primary-500: 59, 130, 246; - --color-primary-600: 37, 99, 235; - --color-primary-700: 29, 78, 216; - --color-primary-800: 30, 64, 175; - --color-primary-900: 30, 58, 138; + --color-primary-50: rgb(239, 246, 255); + --color-primary-100: rgb(219, 234, 254); + --color-primary-200: rgb(191, 219, 254); + --color-primary-300: rgb(147, 197, 253); + --color-primary-400: rgb(96, 165, 250); + --color-primary-500: rgb(59, 130, 246); + --color-primary-600: rgb(37, 99, 235); + --color-primary-700: rgb(29, 78, 216); + --color-primary-800: rgb(30, 64, 175); + --color-primary-900: rgb(30, 58, 138); } // .theme-indigo { -// --color-primary-50: 238, 242, 255; -// --color-primary-100: 224, 231, 255; -// --color-primary-200: 199, 210, 254; -// --color-primary-300: 165, 180, 252; -// --color-primary-400: 129, 140, 248; -// --color-primary-500: 99, 102, 241; -// --color-primary-600: 79, 70, 229; -// --color-primary-700: 67, 56, 202; -// --color-primary-800: 55, 48, 163; -// --color-primary-900: 49, 46, 129; +// --color-primary-50: rgb(238, 242, 255); +// --color-primary-100: rgb(224, 231, 255); +// --color-primary-200: rgb(199, 210, 254); +// --color-primary-300: rgb(165, 180, 252); +// --color-primary-400: rgb(129, 140, 248); +// --color-primary-500: rgb(99, 102, 241); +// --color-primary-600: rgb(79, 70, 229); +// --color-primary-700: rgb(67, 56, 202); +// --color-primary-800: rgb(55, 48, 163); +// --color-primary-900: rgb(49, 46, 129); // } .theme-violet { - --color-primary-50: 245, 243, 255; - --color-primary-100: 237, 233, 254; - --color-primary-200: 221, 214, 254; - --color-primary-300: 196, 181, 253; - --color-primary-400: 167, 139, 250; - --color-primary-500: 139, 92, 246; - --color-primary-600: 124, 58, 237; - --color-primary-700: 109, 40, 217; - --color-primary-800: 91, 33, 182; - --color-primary-900: 76, 29, 149; + --color-primary-50: rgb(245, 243, 255); + --color-primary-100: rgb(237, 233, 254); + --color-primary-200: rgb(221, 214, 254); + --color-primary-300: rgb(196, 181, 253); + --color-primary-400: rgb(167, 139, 250); + --color-primary-500: rgb(139, 92, 246); + --color-primary-600: rgb(124, 58, 237); + --color-primary-700: rgb(109, 40, 217); + --color-primary-800: rgb(91, 33, 182); + --color-primary-900: rgb(76, 29, 149); } .theme-purple { - --color-primary-50: 250, 245, 255; - --color-primary-100: 243, 232, 255; - --color-primary-200: 233, 213, 255; - --color-primary-300: 216, 180, 254; - --color-primary-400: 192, 132, 252; - --color-primary-500: 168, 85, 247; - --color-primary-600: 147, 51, 234; - --color-primary-700: 126, 34, 206; - --color-primary-800: 107, 33, 168; + --color-primary-50: rgb(250, 245, 255); + --color-primary-100: rgb(243, 232, 255); + --color-primary-200: rgb(233, 213, 255); + --color-primary-300: rgb(216, 180, 254); + --color-primary-400: rgb(192, 132, 252); + --color-primary-500: rgb(168, 85, 247); + --color-primary-600: rgb(147, 51, 234); + --color-primary-700: rgb(126, 34, 206); + --color-primary-800: rgb(107, 33, 168); --color-primary-900: 88, 28 135; } .theme-fuchsia { - --color-primary-50: 253, 244, 255; - --color-primary-100: 250, 232, 255; - --color-primary-200: 245, 208, 254; - --color-primary-300: 240, 171, 252; - --color-primary-400: 232, 121, 249; - --color-primary-500: 217, 70, 239; - --color-primary-600: 192, 38, 211; - --color-primary-700: 162, 28, 175; - --color-primary-800: 134, 25, 143; - --color-primary-900: 112, 26, 117; + --color-primary-50: rgb(253, 244, 255); + --color-primary-100: rgb(250, 232, 255); + --color-primary-200: rgb(245, 208, 254); + --color-primary-300: rgb(240, 171, 252); + --color-primary-400: rgb(232, 121, 249); + --color-primary-500: rgb(217, 70, 239); + --color-primary-600: rgb(192, 38, 211); + --color-primary-700: rgb(162, 28, 175); + --color-primary-800: rgb(134, 25, 143); + --color-primary-900: rgb(112, 26, 117); } .theme-pink { - --color-primary-50: 253, 242, 248; - --color-primary-100: 252, 231, 243; - --color-primary-200: 251, 207, 232; - --color-primary-300: 249, 168, 212; - --color-primary-400: 244, 114, 182; - --color-primary-500: 236, 72, 153; - --color-primary-600: 219, 39, 119; - --color-primary-700: 190, 24, 93; - --color-primary-800: 157, 23, 77; - --color-primary-900: 131, 24, 67; + --color-primary-50: rgb(253, 242, 248); + --color-primary-100: rgb(252, 231, 243); + --color-primary-200: rgb(251, 207, 232); + --color-primary-300: rgb(249, 168, 212); + --color-primary-400: rgb(244, 114, 182); + --color-primary-500: rgb(236, 72, 153); + --color-primary-600: rgb(219, 39, 119); + --color-primary-700: rgb(190, 24, 93); + --color-primary-800: rgb(157, 23, 77); + --color-primary-900: rgb(131, 24, 67); } .theme-rose { - --color-primary-50: 255, 241, 242; - --color-primary-100: 255, 228, 230; - --color-primary-200: 254, 205, 211; - --color-primary-300: 253, 164, 175; - --color-primary-400: 251, 113, 133; - --color-primary-500: 244, 63, 94; - --color-primary-600: 225, 29, 72; - --color-primary-700: 190, 18, 60; - --color-primary-800: 159, 18, 57; - --color-primary-900: 136, 19, 55; + --color-primary-50: rgb(255, 241, 242); + --color-primary-100: rgb(255, 228, 230); + --color-primary-200: rgb(254, 205, 211); + --color-primary-300: rgb(253, 164, 175); + --color-primary-400: rgb(251, 113, 133); + --color-primary-500: rgb(244, 63, 94); + --color-primary-600: rgb(225, 29, 72); + --color-primary-700: rgb(190, 18, 60); + --color-primary-800: rgb(159, 18, 57); + --color-primary-900: rgb(136, 19, 55); } diff --git a/Resources/scripts/stores/white-label.js b/Resources/scripts/stores/white-label.js index a463ceb..8deab23 100644 --- a/Resources/scripts/stores/white-label.js +++ b/Resources/scripts/stores/white-label.js @@ -1,14 +1,17 @@ -// import axios from 'axios' import { useNotificationStore } from '@/scripts/stores/notification' +// InvoiceShelf 2.3.0 stopped exposing window.axios; its HTTP client (auth +// token, company header, credentials) is bundled from the host instead. +import http from '@/scripts/http' const { defineStore } = window.pinia -export const useWhiteLabelStore = defineStore({ - id: 'white-label', +// The id is the first argument: Pinia 3, which InvoiceShelf ships from 2.3.0, +// dropped the defineStore({ id, ... }) form. +export const useWhiteLabelStore = defineStore('white-label', { actions: { updateLogo(data) { const notificationStore = useNotificationStore(true) return new Promise((resolve, reject) => { - window.axios + http .post('/api/m/white-label/upload-logos', data) .then((response) => { resolve(response) diff --git a/Resources/scripts/views/WhiteLabelSetting.vue b/Resources/scripts/views/WhiteLabelSetting.vue index e8ec5d3..d7ccf40 100644 --- a/Resources/scripts/views/WhiteLabelSetting.vue +++ b/Resources/scripts/views/WhiteLabelSetting.vue @@ -262,7 +262,11 @@ async function saveCustomerPortalSettings() { data: { settings: { ...customerPortalSettings, - customer_portal_page_title: customerPortalTitle.value + // Company settings cannot be empty (the host stores '' as null into a + // NOT NULL column), so a blank title is left out rather than sent. + ...(customerPortalTitle.value + ? { customer_portal_page_title: customerPortalTitle.value } + : {}), }, }, message: 'settings.preferences.updated_message', diff --git a/package.json b/package.json index 8371bca..7ed5823 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "1.1.3", + "version": "1.1.4", "scripts": { "dev": "vite", "build": "vite build", diff --git a/vite.config.js b/vite.config.js index 8ba702a..7b36453 100644 --- a/vite.config.js +++ b/vite.config.js @@ -4,6 +4,28 @@ const { defineConfig } = require('vite') import vue from '@vitejs/plugin-vue' import { viteExternalsPlugin } from 'vite-plugin-externals' +// InvoiceShelf 2.3.0 and later style the app with Tailwind 4, which keeps its +// rules in cascade layers, and CSS outside any layer beats every layered rule. +// Left unlayered, this module's utilities (.hidden, .flex, ...) overrode the +// app's responsive ones and hid the sidebar. The built stylesheet goes into the +// app's `utilities` layer instead, declared in the app's order first, so the +// app's own rule wins wherever both define a class. Hosts before 2.3.0 have no +// layers, and their rules keep winning there too. +const inHostUtilitiesLayer = () => ({ + name: 'in-host-utilities-layer', + closeBundle() { + const fs = require('fs') + const file = path.resolve(__dirname, 'dist/style.css') + + if (!fs.existsSync(file)) { + return + } + + const css = fs.readFileSync(file, 'utf8').replace(/^@charset "[^"]*";\s*/, '') + fs.writeFileSync(file, `@layer theme, base, components, utilities;\n@layer utilities {\n${css}\n}\n`) + }, +}) + module.exports = defineConfig({ build: { lib: { @@ -24,5 +46,6 @@ module.exports = defineConfig({ viteExternalsPlugin({ vue: 'Vue', }), + inHostUtilitiesLayer(), ], })