create-nextjs-cms 0.5.21 → 0.5.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -6
- package/templates/default/_gitignore +1 -1
- package/templates/default/app/(auth)/auth/login/LoginPage.tsx +5 -5
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/LICENSE +191 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/README.md +118 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/install/build.js +38 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/install/check.js +14 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/lib/channel.js +177 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/lib/colour.js +195 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/lib/composite.js +212 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/lib/constructor.js +499 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/lib/index.d.ts +1971 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/lib/index.js +16 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/lib/input.js +809 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/lib/is.js +143 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/lib/libvips.js +207 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/lib/operation.js +1016 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/lib/output.js +1666 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/lib/resize.js +595 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/lib/sharp.js +121 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/lib/utility.js +291 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/package.json +202 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/src/binding.gyp +298 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/src/common.cc +1130 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/src/common.h +402 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/src/metadata.cc +346 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/src/metadata.h +90 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/src/operations.cc +499 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/src/operations.h +137 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/src/pipeline.cc +1814 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/src/pipeline.h +408 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/src/sharp.cc +43 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/src/stats.cc +186 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/src/stats.h +62 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/src/utilities.cc +288 -0
- package/templates/default/apps/cms/node_modules/next/node_modules/sharp/src/utilities.h +22 -0
- package/templates/default/apps/cms/node_modules/sharp/LICENSE +191 -0
- package/templates/default/apps/cms/node_modules/sharp/README.md +118 -0
- package/templates/default/apps/cms/node_modules/sharp/install/check.js +41 -0
- package/templates/default/apps/cms/node_modules/sharp/lib/channel.js +174 -0
- package/templates/default/apps/cms/node_modules/sharp/lib/colour.js +180 -0
- package/templates/default/apps/cms/node_modules/sharp/lib/composite.js +210 -0
- package/templates/default/apps/cms/node_modules/sharp/lib/constructor.js +452 -0
- package/templates/default/apps/cms/node_modules/sharp/lib/index.d.ts +1754 -0
- package/templates/default/apps/cms/node_modules/sharp/lib/index.js +16 -0
- package/templates/default/apps/cms/node_modules/sharp/lib/input.js +658 -0
- package/templates/default/apps/cms/node_modules/sharp/lib/is.js +169 -0
- package/templates/default/apps/cms/node_modules/sharp/lib/libvips.js +203 -0
- package/templates/default/apps/cms/node_modules/sharp/lib/operation.js +958 -0
- package/templates/default/apps/cms/node_modules/sharp/lib/output.js +1587 -0
- package/templates/default/apps/cms/node_modules/sharp/lib/resize.js +587 -0
- package/templates/default/apps/cms/node_modules/sharp/lib/sharp.js +114 -0
- package/templates/default/apps/cms/node_modules/sharp/lib/utility.js +296 -0
- package/templates/default/apps/cms/node_modules/sharp/package.json +222 -0
- package/templates/default/apps/cms/node_modules/sharp/src/binding.gyp +280 -0
- package/templates/default/apps/cms/node_modules/sharp/src/common.cc +1091 -0
- package/templates/default/apps/cms/node_modules/sharp/src/common.h +393 -0
- package/templates/default/apps/cms/node_modules/sharp/src/metadata.cc +320 -0
- package/templates/default/apps/cms/node_modules/sharp/src/metadata.h +85 -0
- package/templates/default/apps/cms/node_modules/sharp/src/operations.cc +475 -0
- package/templates/default/apps/cms/node_modules/sharp/src/operations.h +125 -0
- package/templates/default/apps/cms/node_modules/sharp/src/pipeline.cc +1758 -0
- package/templates/default/apps/cms/node_modules/sharp/src/pipeline.h +393 -0
- package/templates/default/apps/cms/node_modules/sharp/src/sharp.cc +40 -0
- package/templates/default/apps/cms/node_modules/sharp/src/stats.cc +183 -0
- package/templates/default/apps/cms/node_modules/sharp/src/stats.h +59 -0
- package/templates/default/apps/cms/node_modules/sharp/src/utilities.cc +269 -0
- package/templates/default/apps/cms/node_modules/sharp/src/utilities.h +19 -0
- package/templates/default/components/AdminCard.tsx +1 -1
- package/templates/default/components/AdminsPage.tsx +1 -1
- package/templates/default/components/AdvancedSettingsPage.tsx +1 -1
- package/templates/default/components/AnalyticsPage.tsx +1 -1
- package/templates/default/components/BrowsePage.tsx +2 -2
- package/templates/default/components/CategorizedSectionPage.tsx +3 -3
- package/templates/default/components/CategoryDeleteConfirmPage.tsx +4 -4
- package/templates/default/components/CategorySectionSelectInput.tsx +1 -1
- package/templates/default/components/ContainerBox.tsx +1 -1
- package/templates/default/components/DashboardPage.tsx +1 -1
- package/templates/default/components/EmailCard.tsx +1 -1
- package/templates/default/components/EmailPasswordForm.tsx +2 -2
- package/templates/default/components/EmailQuotaForm.tsx +1 -1
- package/templates/default/components/EmailsPage.tsx +1 -1
- package/templates/default/components/GalleryPhoto.tsx +1 -1
- package/templates/default/components/ItemEditPage.tsx +2 -2
- package/templates/default/components/Layout.tsx +1 -1
- package/templates/default/components/LogPage.tsx +1 -1
- package/templates/default/components/Navbar.tsx +2 -2
- package/templates/default/components/NavbarAlt.tsx +6 -6
- package/templates/default/components/NewAdminForm.tsx +2 -2
- package/templates/default/components/NewEmailForm.tsx +3 -3
- package/templates/default/components/NewPage.tsx +2 -2
- package/templates/default/components/NewVariantComponent.tsx +1 -1
- package/templates/default/components/SectionItemCard.tsx +1 -1
- package/templates/default/components/SectionItemStatusBadge.tsx +1 -1
- package/templates/default/components/SectionPage.tsx +2 -2
- package/templates/default/components/SelectBox.tsx +2 -2
- package/templates/default/components/SettingsPage.tsx +1 -1
- package/templates/default/components/Sidebar.tsx +3 -3
- package/templates/default/components/VariantEditPage.tsx +2 -2
- package/templates/default/components/form/Form.tsx +1 -1
- package/templates/default/components/form/FormInputElement.tsx +1 -1
- package/templates/default/components/form/helpers/{_section-hot-reload.ts → _section-hot-reload.js} +1 -1
- package/templates/default/components/form/helpers/util.ts +1 -1
- package/templates/default/components/form/inputs/ColorFormInput.tsx +1 -1
- package/templates/default/components/form/inputs/DateFormInput.tsx +1 -1
- package/templates/default/components/form/inputs/DocumentFormInput.tsx +3 -3
- package/templates/default/components/form/inputs/NumberFormInput.tsx +1 -1
- package/templates/default/components/form/inputs/PasswordFormInput.tsx +1 -1
- package/templates/default/components/form/inputs/PhotoFormInput.tsx +4 -4
- package/templates/default/components/form/inputs/SelectFormInput.tsx +1 -1
- package/templates/default/components/form/inputs/TagsFormInput.tsx +1 -1
- package/templates/default/components/form/inputs/TextFormInput.tsx +1 -1
- package/templates/default/components/form/inputs/TextareaFormInput.tsx +1 -1
- package/templates/default/components/form/inputs/VideoFormInput.tsx +3 -3
- package/templates/default/components/ui/badge.tsx +6 -6
- package/templates/default/components/ui/button.tsx +5 -5
- package/templates/default/components/ui/card.tsx +1 -1
- package/templates/default/components/ui/checkbox.tsx +1 -1
- package/templates/default/components/ui/dropdown-menu.tsx +6 -6
- package/templates/default/components/ui/input.tsx +1 -1
- package/templates/default/components/ui/popover.tsx +1 -1
- package/templates/default/components/ui/scroll-area.tsx +2 -2
- package/templates/default/components/ui/select.tsx +4 -4
- package/templates/default/components/ui/sheet.tsx +1 -1
- package/templates/default/components/ui/switch.tsx +1 -1
- package/templates/default/components/ui/table.tsx +3 -3
- package/templates/default/components/ui/tabs.tsx +2 -2
- package/templates/default/components/ui/toast.tsx +4 -4
- package/templates/default/eslint.config.mjs +38 -0
- package/templates/default/next-env.d.ts +1 -1
- package/templates/default/package.json +24 -33
- package/templates/default/postcss.config.mjs +7 -0
- package/templates/default/{middleware.ts → proxy.ts} +2 -3
- package/templates/default/styles/globals.css +107 -4
- package/templates/default/tsconfig.json +45 -44
- package/templates/default/postcss.config.js +0 -6
- package/templates/default/tailwind.config.js +0 -95
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
// Copyright 2013 Lovell Fuller and others.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
#include <cmath>
|
|
5
|
+
#include <string>
|
|
6
|
+
#include <cstdio>
|
|
7
|
+
|
|
8
|
+
#include <napi.h>
|
|
9
|
+
#include <vips/vips8>
|
|
10
|
+
#include <vips/vector.h>
|
|
11
|
+
|
|
12
|
+
#include "common.h"
|
|
13
|
+
#include "operations.h"
|
|
14
|
+
#include "utilities.h"
|
|
15
|
+
|
|
16
|
+
/*
|
|
17
|
+
Get and set cache limits
|
|
18
|
+
*/
|
|
19
|
+
Napi::Value cache(const Napi::CallbackInfo& info) {
|
|
20
|
+
Napi::Env env = info.Env();
|
|
21
|
+
|
|
22
|
+
// Set memory limit
|
|
23
|
+
if (info[size_t(0)].IsNumber()) {
|
|
24
|
+
vips_cache_set_max_mem(info[size_t(0)].As<Napi::Number>().Int32Value() * 1048576);
|
|
25
|
+
}
|
|
26
|
+
// Set file limit
|
|
27
|
+
if (info[size_t(1)].IsNumber()) {
|
|
28
|
+
vips_cache_set_max_files(info[size_t(1)].As<Napi::Number>().Int32Value());
|
|
29
|
+
}
|
|
30
|
+
// Set items limit
|
|
31
|
+
if (info[size_t(2)].IsNumber()) {
|
|
32
|
+
vips_cache_set_max(info[size_t(2)].As<Napi::Number>().Int32Value());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Get memory stats
|
|
36
|
+
Napi::Object memory = Napi::Object::New(env);
|
|
37
|
+
memory.Set("current", round(vips_tracked_get_mem() / 1048576));
|
|
38
|
+
memory.Set("high", round(vips_tracked_get_mem_highwater() / 1048576));
|
|
39
|
+
memory.Set("max", round(vips_cache_get_max_mem() / 1048576));
|
|
40
|
+
// Get file stats
|
|
41
|
+
Napi::Object files = Napi::Object::New(env);
|
|
42
|
+
files.Set("current", vips_tracked_get_files());
|
|
43
|
+
files.Set("max", vips_cache_get_max_files());
|
|
44
|
+
|
|
45
|
+
// Get item stats
|
|
46
|
+
Napi::Object items = Napi::Object::New(env);
|
|
47
|
+
items.Set("current", vips_cache_get_size());
|
|
48
|
+
items.Set("max", vips_cache_get_max());
|
|
49
|
+
|
|
50
|
+
Napi::Object cache = Napi::Object::New(env);
|
|
51
|
+
cache.Set("memory", memory);
|
|
52
|
+
cache.Set("files", files);
|
|
53
|
+
cache.Set("items", items);
|
|
54
|
+
return cache;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/*
|
|
58
|
+
Get and set size of thread pool
|
|
59
|
+
*/
|
|
60
|
+
Napi::Value concurrency(const Napi::CallbackInfo& info) {
|
|
61
|
+
// Set concurrency
|
|
62
|
+
if (info[size_t(0)].IsNumber()) {
|
|
63
|
+
vips_concurrency_set(info[size_t(0)].As<Napi::Number>().Int32Value());
|
|
64
|
+
}
|
|
65
|
+
// Get concurrency
|
|
66
|
+
return Napi::Number::New(info.Env(), vips_concurrency_get());
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/*
|
|
70
|
+
Get internal counters (queued tasks, processing tasks)
|
|
71
|
+
*/
|
|
72
|
+
Napi::Value counters(const Napi::CallbackInfo& info) {
|
|
73
|
+
Napi::Object counters = Napi::Object::New(info.Env());
|
|
74
|
+
counters.Set("queue", static_cast<int>(sharp::counterQueue));
|
|
75
|
+
counters.Set("process", static_cast<int>(sharp::counterProcess));
|
|
76
|
+
return counters;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/*
|
|
80
|
+
Get and set use of SIMD vector unit instructions
|
|
81
|
+
*/
|
|
82
|
+
Napi::Value simd(const Napi::CallbackInfo& info) {
|
|
83
|
+
// Set state
|
|
84
|
+
if (info[size_t(0)].IsBoolean()) {
|
|
85
|
+
vips_vector_set_enabled(info[size_t(0)].As<Napi::Boolean>().Value());
|
|
86
|
+
}
|
|
87
|
+
// Get state
|
|
88
|
+
return Napi::Boolean::New(info.Env(), vips_vector_isenabled());
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/*
|
|
92
|
+
Get libvips version
|
|
93
|
+
*/
|
|
94
|
+
Napi::Value libvipsVersion(const Napi::CallbackInfo& info) {
|
|
95
|
+
Napi::Env env = info.Env();
|
|
96
|
+
Napi::Object version = Napi::Object::New(env);
|
|
97
|
+
|
|
98
|
+
char semver[9];
|
|
99
|
+
std::snprintf(semver, sizeof(semver), "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
|
|
100
|
+
version.Set("semver", Napi::String::New(env, semver));
|
|
101
|
+
#ifdef SHARP_USE_GLOBAL_LIBVIPS
|
|
102
|
+
version.Set("isGlobal", Napi::Boolean::New(env, true));
|
|
103
|
+
#else
|
|
104
|
+
version.Set("isGlobal", Napi::Boolean::New(env, false));
|
|
105
|
+
#endif
|
|
106
|
+
#ifdef __EMSCRIPTEN__
|
|
107
|
+
version.Set("isWasm", Napi::Boolean::New(env, true));
|
|
108
|
+
#else
|
|
109
|
+
version.Set("isWasm", Napi::Boolean::New(env, false));
|
|
110
|
+
#endif
|
|
111
|
+
return version;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/*
|
|
115
|
+
Get available input/output file/buffer/stream formats
|
|
116
|
+
*/
|
|
117
|
+
Napi::Value format(const Napi::CallbackInfo& info) {
|
|
118
|
+
Napi::Env env = info.Env();
|
|
119
|
+
Napi::Object format = Napi::Object::New(env);
|
|
120
|
+
for (std::string const f : {
|
|
121
|
+
"jpeg", "png", "webp", "tiff", "magick", "openslide", "dz",
|
|
122
|
+
"ppm", "fits", "gif", "svg", "heif", "pdf", "vips", "jp2k", "jxl"
|
|
123
|
+
}) {
|
|
124
|
+
// Input
|
|
125
|
+
const VipsObjectClass *oc = vips_class_find("VipsOperation", (f + "load").c_str());
|
|
126
|
+
Napi::Boolean hasInputFile = Napi::Boolean::New(env, oc);
|
|
127
|
+
Napi::Boolean hasInputBuffer =
|
|
128
|
+
Napi::Boolean::New(env, vips_type_find("VipsOperation", (f + "load_buffer").c_str()));
|
|
129
|
+
Napi::Object input = Napi::Object::New(env);
|
|
130
|
+
input.Set("file", hasInputFile);
|
|
131
|
+
input.Set("buffer", hasInputBuffer);
|
|
132
|
+
input.Set("stream", hasInputBuffer);
|
|
133
|
+
if (hasInputFile) {
|
|
134
|
+
const VipsForeignClass *fc = VIPS_FOREIGN_CLASS(oc);
|
|
135
|
+
if (fc->suffs) {
|
|
136
|
+
Napi::Array fileSuffix = Napi::Array::New(env);
|
|
137
|
+
const char **suffix = fc->suffs;
|
|
138
|
+
for (int i = 0; *suffix; i++, suffix++) {
|
|
139
|
+
fileSuffix.Set(i, Napi::String::New(env, *suffix));
|
|
140
|
+
}
|
|
141
|
+
input.Set("fileSuffix", fileSuffix);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Output
|
|
145
|
+
Napi::Boolean hasOutputFile =
|
|
146
|
+
Napi::Boolean::New(env, vips_type_find("VipsOperation", (f + "save").c_str()));
|
|
147
|
+
Napi::Boolean hasOutputBuffer =
|
|
148
|
+
Napi::Boolean::New(env, vips_type_find("VipsOperation", (f + "save_buffer").c_str()));
|
|
149
|
+
Napi::Object output = Napi::Object::New(env);
|
|
150
|
+
output.Set("file", hasOutputFile);
|
|
151
|
+
output.Set("buffer", hasOutputBuffer);
|
|
152
|
+
output.Set("stream", hasOutputBuffer);
|
|
153
|
+
// Other attributes
|
|
154
|
+
Napi::Object container = Napi::Object::New(env);
|
|
155
|
+
container.Set("id", f);
|
|
156
|
+
container.Set("input", input);
|
|
157
|
+
container.Set("output", output);
|
|
158
|
+
// Add to set of formats
|
|
159
|
+
format.Set(f, container);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Raw, uncompressed data
|
|
163
|
+
Napi::Boolean supported = Napi::Boolean::New(env, true);
|
|
164
|
+
Napi::Boolean unsupported = Napi::Boolean::New(env, false);
|
|
165
|
+
Napi::Object rawInput = Napi::Object::New(env);
|
|
166
|
+
rawInput.Set("file", unsupported);
|
|
167
|
+
rawInput.Set("buffer", supported);
|
|
168
|
+
rawInput.Set("stream", supported);
|
|
169
|
+
Napi::Object rawOutput = Napi::Object::New(env);
|
|
170
|
+
rawOutput.Set("file", unsupported);
|
|
171
|
+
rawOutput.Set("buffer", supported);
|
|
172
|
+
rawOutput.Set("stream", supported);
|
|
173
|
+
Napi::Object raw = Napi::Object::New(env);
|
|
174
|
+
raw.Set("id", "raw");
|
|
175
|
+
raw.Set("input", rawInput);
|
|
176
|
+
raw.Set("output", rawOutput);
|
|
177
|
+
format.Set("raw", raw);
|
|
178
|
+
|
|
179
|
+
return format;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/*
|
|
183
|
+
(Un)block libvips operations at runtime.
|
|
184
|
+
*/
|
|
185
|
+
void block(const Napi::CallbackInfo& info) {
|
|
186
|
+
Napi::Array ops = info[size_t(0)].As<Napi::Array>();
|
|
187
|
+
bool const state = info[size_t(1)].As<Napi::Boolean>().Value();
|
|
188
|
+
for (unsigned int i = 0; i < ops.Length(); i++) {
|
|
189
|
+
vips_operation_block_set(ops.Get(i).As<Napi::String>().Utf8Value().c_str(), state);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/*
|
|
194
|
+
Synchronous, internal-only method used by some of the functional tests.
|
|
195
|
+
Calculates the maximum colour distance using the DE2000 algorithm
|
|
196
|
+
between two images of the same dimensions and number of channels.
|
|
197
|
+
*/
|
|
198
|
+
Napi::Value _maxColourDistance(const Napi::CallbackInfo& info) {
|
|
199
|
+
Napi::Env env = info.Env();
|
|
200
|
+
|
|
201
|
+
// Open input files
|
|
202
|
+
VImage image1;
|
|
203
|
+
sharp::ImageType imageType1 = sharp::DetermineImageType(info[size_t(0)].As<Napi::String>().Utf8Value().data());
|
|
204
|
+
if (imageType1 != sharp::ImageType::UNKNOWN) {
|
|
205
|
+
try {
|
|
206
|
+
image1 = VImage::new_from_file(info[size_t(0)].As<Napi::String>().Utf8Value().c_str());
|
|
207
|
+
} catch (...) {
|
|
208
|
+
throw Napi::Error::New(env, "Input file 1 has corrupt header");
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
throw Napi::Error::New(env, "Input file 1 is of an unsupported image format");
|
|
212
|
+
}
|
|
213
|
+
VImage image2;
|
|
214
|
+
sharp::ImageType imageType2 = sharp::DetermineImageType(info[size_t(1)].As<Napi::String>().Utf8Value().data());
|
|
215
|
+
if (imageType2 != sharp::ImageType::UNKNOWN) {
|
|
216
|
+
try {
|
|
217
|
+
image2 = VImage::new_from_file(info[size_t(1)].As<Napi::String>().Utf8Value().c_str());
|
|
218
|
+
} catch (...) {
|
|
219
|
+
throw Napi::Error::New(env, "Input file 2 has corrupt header");
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
throw Napi::Error::New(env, "Input file 2 is of an unsupported image format");
|
|
223
|
+
}
|
|
224
|
+
// Ensure same number of channels
|
|
225
|
+
if (image1.bands() != image2.bands()) {
|
|
226
|
+
throw Napi::Error::New(env, "mismatchedBands");
|
|
227
|
+
}
|
|
228
|
+
// Ensure same dimensions
|
|
229
|
+
if (image1.width() != image2.width() || image1.height() != image2.height()) {
|
|
230
|
+
throw Napi::Error::New(env, "mismatchedDimensions");
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
double maxColourDistance;
|
|
234
|
+
try {
|
|
235
|
+
// Premultiply and remove alpha
|
|
236
|
+
if (sharp::HasAlpha(image1)) {
|
|
237
|
+
image1 = image1.premultiply().extract_band(1, VImage::option()->set("n", image1.bands() - 1));
|
|
238
|
+
}
|
|
239
|
+
if (sharp::HasAlpha(image2)) {
|
|
240
|
+
image2 = image2.premultiply().extract_band(1, VImage::option()->set("n", image2.bands() - 1));
|
|
241
|
+
}
|
|
242
|
+
// Calculate colour distance
|
|
243
|
+
maxColourDistance = image1.dE00(image2).max();
|
|
244
|
+
} catch (vips::VError const &err) {
|
|
245
|
+
throw Napi::Error::New(env, err.what());
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Clean up libvips' per-request data and threads
|
|
249
|
+
vips_error_clear();
|
|
250
|
+
vips_thread_shutdown();
|
|
251
|
+
|
|
252
|
+
return Napi::Number::New(env, maxColourDistance);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
#if defined(__GNUC__)
|
|
256
|
+
// mallctl will be resolved by the runtime linker when jemalloc is being used
|
|
257
|
+
extern "C" {
|
|
258
|
+
int mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) __attribute__((weak));
|
|
259
|
+
}
|
|
260
|
+
Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info) {
|
|
261
|
+
Napi::Env env = info.Env();
|
|
262
|
+
return Napi::Boolean::New(env, mallctl != nullptr);
|
|
263
|
+
}
|
|
264
|
+
#else
|
|
265
|
+
Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info) {
|
|
266
|
+
Napi::Env env = info.Env();
|
|
267
|
+
return Napi::Boolean::New(env, false);
|
|
268
|
+
}
|
|
269
|
+
#endif
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright 2013 Lovell Fuller and others.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
#ifndef SRC_UTILITIES_H_
|
|
5
|
+
#define SRC_UTILITIES_H_
|
|
6
|
+
|
|
7
|
+
#include <napi.h>
|
|
8
|
+
|
|
9
|
+
Napi::Value cache(const Napi::CallbackInfo& info);
|
|
10
|
+
Napi::Value concurrency(const Napi::CallbackInfo& info);
|
|
11
|
+
Napi::Value counters(const Napi::CallbackInfo& info);
|
|
12
|
+
Napi::Value simd(const Napi::CallbackInfo& info);
|
|
13
|
+
Napi::Value libvipsVersion(const Napi::CallbackInfo& info);
|
|
14
|
+
Napi::Value format(const Napi::CallbackInfo& info);
|
|
15
|
+
void block(const Napi::CallbackInfo& info);
|
|
16
|
+
Napi::Value _maxColourDistance(const Napi::CallbackInfo& info);
|
|
17
|
+
Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info);
|
|
18
|
+
|
|
19
|
+
#endif // SRC_UTILITIES_H_
|
|
@@ -56,7 +56,7 @@ export default function AdminCard({
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
return (
|
|
59
|
-
<Card className='flex flex-col justify-between border border-gray-400 shadow-
|
|
59
|
+
<Card className='flex flex-col justify-between border border-gray-400 shadow-xs'>
|
|
60
60
|
<CardHeader>
|
|
61
61
|
<CardTitle>
|
|
62
62
|
<div className='flex flex-row items-center gap-2'>
|
|
@@ -12,7 +12,7 @@ const AdminsPage = () => {
|
|
|
12
12
|
|
|
13
13
|
return (
|
|
14
14
|
<div className='w-full'>
|
|
15
|
-
<div className='bg-
|
|
15
|
+
<div className='bg-linear-to-r from-sky-200 via-emerald-300 to-blue-600 p-8 font-extrabold text-foreground dark:from-blue-800 dark:via-amber-700 dark:to-rose-900'>
|
|
16
16
|
<h1 className='text-3xl'>{getString('admins')}</h1>
|
|
17
17
|
</div>
|
|
18
18
|
|
|
@@ -76,7 +76,7 @@ export default function AdvancedSettingsPage() {
|
|
|
76
76
|
return (
|
|
77
77
|
<div>
|
|
78
78
|
<div className='w-full overflow-hidden bg-background'>
|
|
79
|
-
<div className='bg-
|
|
79
|
+
<div className='bg-linear-to-r from-rose-200 via-rose-400 to-sky-400 p-8 font-extrabold text-black'>
|
|
80
80
|
<h1 className='text-3xl'>{getString('advancedSettings')}</h1>
|
|
81
81
|
</div>
|
|
82
82
|
<div className='flex w-full flex-col'>
|
|
@@ -34,7 +34,7 @@ const AnalyticsPage = () => {
|
|
|
34
34
|
|
|
35
35
|
return (
|
|
36
36
|
<div className='w-full'>
|
|
37
|
-
<div className='bg-
|
|
37
|
+
<div className='bg-linear-to-r from-sky-200 via-emerald-300 to-blue-600 p-8 font-extrabold text-foreground dark:from-blue-800 dark:via-amber-700 dark:to-rose-900'>
|
|
38
38
|
<h1 className='text-3xl'>{getString('analytics')}</h1>
|
|
39
39
|
</div>
|
|
40
40
|
<div className='p-4'>
|
|
@@ -31,8 +31,8 @@ export default function BrowsePage({ section, page }: { section: string; page: s
|
|
|
31
31
|
|
|
32
32
|
return (
|
|
33
33
|
<div>
|
|
34
|
-
<div className='relative z-
|
|
35
|
-
<div className='absolute left-0 top-0 z-
|
|
34
|
+
<div className='relative z-1 border-b-2 p-8 pt-12 font-extrabold text-foreground'>
|
|
35
|
+
<div className='absolute left-0 top-0 z-2 h-4 w-full bg-linear-to-r from-sky-300 via-gray-300 to-blue-400'></div>
|
|
36
36
|
<h1 className='text-3xl'>{data?.section?.title}</h1>
|
|
37
37
|
</div>
|
|
38
38
|
<div className='p-4'>
|
|
@@ -15,12 +15,12 @@ export default function CategorizedSectionPage({ section }: { section: string })
|
|
|
15
15
|
return (
|
|
16
16
|
<div>
|
|
17
17
|
<div className='w-full'>
|
|
18
|
-
<div className='relative z-
|
|
19
|
-
<div className='absolute left-0 top-0 z-
|
|
18
|
+
<div className='relative z-1 border-b-2 p-8 pt-12 font-extrabold text-foreground'>
|
|
19
|
+
<div className='absolute left-0 top-0 z-2 h-4 w-full bg-linear-to-r from-rose-200 via-rose-400 to-sky-400'></div>{' '}
|
|
20
20
|
{data && data.section && <h1 className='text-3xl'>{data?.section?.title.section}</h1>}
|
|
21
21
|
</div>
|
|
22
22
|
<div className='flex w-full flex-col'>
|
|
23
|
-
<div className='rounded-xl p-4 shadow'>
|
|
23
|
+
<div className='rounded-xl p-4 shadow-sm'>
|
|
24
24
|
{isLoading && (
|
|
25
25
|
<div>
|
|
26
26
|
<LoadingSpinners />
|
|
@@ -71,8 +71,8 @@ export default function CategoryDeleteConfirmPage({
|
|
|
71
71
|
return (
|
|
72
72
|
<div className='flex flex-col'>
|
|
73
73
|
<div className='flex flex-col gap-3'>
|
|
74
|
-
<div className='relative z-
|
|
75
|
-
<div className='absolute left-0 top-0 z-
|
|
74
|
+
<div className='relative z-1 border-b-2 p-8 pt-12 font-extrabold text-foreground'>
|
|
75
|
+
<div className='absolute left-0 top-0 z-2 h-4 w-full bg-linear-to-r from-red-300 via-rose-500 to-pink-400'></div>
|
|
76
76
|
<h1 className='pb-4 text-3xl'>{sectionTitle}</h1>
|
|
77
77
|
<span>/{getString('delete')}</span>
|
|
78
78
|
</div>
|
|
@@ -83,7 +83,7 @@ export default function CategoryDeleteConfirmPage({
|
|
|
83
83
|
<LoadingSpinners />
|
|
84
84
|
</div>
|
|
85
85
|
) : null}
|
|
86
|
-
<div className='flex flex-col gap-3 rounded p-2 ring ring-sky-300'>
|
|
86
|
+
<div className='flex flex-col gap-3 rounded p-2 ring-3 ring-sky-300'>
|
|
87
87
|
<InfoCard
|
|
88
88
|
result={{
|
|
89
89
|
key: 'info',
|
|
@@ -93,7 +93,7 @@ export default function CategoryDeleteConfirmPage({
|
|
|
93
93
|
/>
|
|
94
94
|
</div>
|
|
95
95
|
{allowRecursiveDelete ? (
|
|
96
|
-
<div className='flex flex-col gap-3 rounded p-2 ring ring-sky-300'>
|
|
96
|
+
<div className='flex flex-col gap-3 rounded p-2 ring-3 ring-sky-300'>
|
|
97
97
|
<InfoCard
|
|
98
98
|
result={{
|
|
99
99
|
key: 'info',
|
|
@@ -11,7 +11,7 @@ export default function ContainerBox({ children, title }: { children: React.Reac
|
|
|
11
11
|
<CardContent>{children}</CardContent>
|
|
12
12
|
</Card>*/}
|
|
13
13
|
|
|
14
|
-
<div className='relative flex flex-col rounded-lg border border-slate-300 bg-white shadow-
|
|
14
|
+
<div className='relative flex flex-col rounded-lg border border-slate-300 bg-white shadow-xs dark:border-slate-500 dark:bg-slate-900'>
|
|
15
15
|
{title ? (
|
|
16
16
|
<div className='rounded-t-lg px-4 py-1.5 font-bold text-black dark:bg-slate-800 dark:text-white'>
|
|
17
17
|
{title}
|
|
@@ -17,7 +17,7 @@ const DashboardPage = () => {
|
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
19
|
<div className='w-full'>
|
|
20
|
-
<div className='bg-
|
|
20
|
+
<div className='bg-linear-to-r from-sky-200 via-emerald-300 to-blue-600 p-8 font-extrabold text-foreground dark:from-blue-800 dark:via-amber-700 dark:to-rose-900'>
|
|
21
21
|
<h1 className='text-3xl'>{getString('dashboard')}</h1>
|
|
22
22
|
</div>
|
|
23
23
|
<div className='flex flex-col gap-4 p-4'>
|
|
@@ -39,7 +39,7 @@ export default function EmailCard({ email, action }: { email: EmailItem; action:
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
return (
|
|
42
|
-
<Card className='border border-gray-400 shadow-
|
|
42
|
+
<Card className='border border-gray-400 shadow-xs'>
|
|
43
43
|
<CardHeader>
|
|
44
44
|
<CardTitle>
|
|
45
45
|
<div className='flex flex-row items-center'>
|
|
@@ -55,7 +55,7 @@ export default function EmailPasswordForm({ email, action }: { email: string; ac
|
|
|
55
55
|
type='text'
|
|
56
56
|
autoComplete='password'
|
|
57
57
|
required
|
|
58
|
-
className='block w-full rounded-md border-0 bg-input p-2.5 text-foreground shadow-
|
|
58
|
+
className='block w-full rounded-md border-0 bg-input p-2.5 text-foreground shadow-xs outline-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'
|
|
59
59
|
/>
|
|
60
60
|
</div>
|
|
61
61
|
</div>
|
|
@@ -70,7 +70,7 @@ export default function EmailPasswordForm({ email, action }: { email: string; ac
|
|
|
70
70
|
type='text'
|
|
71
71
|
autoComplete='passwordConfirm'
|
|
72
72
|
required
|
|
73
|
-
className='block w-full rounded-md border-0 bg-input p-2.5 text-foreground shadow-
|
|
73
|
+
className='block w-full rounded-md border-0 bg-input p-2.5 text-foreground shadow-xs outline-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'
|
|
74
74
|
/>
|
|
75
75
|
</div>
|
|
76
76
|
</div>
|
|
@@ -55,7 +55,7 @@ export default function EmailQuotaForm({ email, action }: { email: string; actio
|
|
|
55
55
|
type='number'
|
|
56
56
|
autoComplete='quota'
|
|
57
57
|
required
|
|
58
|
-
className='block rounded-md border-0 bg-input p-2.5 text-foreground shadow-
|
|
58
|
+
className='block rounded-md border-0 bg-input p-2.5 text-foreground shadow-xs outline-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'
|
|
59
59
|
/>
|
|
60
60
|
<Badge className='rounded-sm border-muted-foreground text-muted-foreground' variant='secondary'>
|
|
61
61
|
0 = {getString('unlimited')}
|
|
@@ -21,7 +21,7 @@ const EmailsPage = () => {
|
|
|
21
21
|
|
|
22
22
|
return (
|
|
23
23
|
<div className='bg-white dark:bg-slate-900'>
|
|
24
|
-
<div className='bg-
|
|
24
|
+
<div className='bg-linear-to-r from-sky-200 via-emerald-300 to-blue-600 p-8 font-extrabold text-foreground dark:from-blue-800 dark:via-amber-700 dark:to-rose-900'>
|
|
25
25
|
<h1 className='text-3xl'>{getString('email_accounts')}</h1>
|
|
26
26
|
</div>
|
|
27
27
|
|
|
@@ -192,8 +192,8 @@ export default function ItemEditPage({
|
|
|
192
192
|
{isError ? <div>{error?.message}</div> : null}
|
|
193
193
|
{data ? (
|
|
194
194
|
<div className='flex w-full flex-col'>
|
|
195
|
-
<div className='relative z-
|
|
196
|
-
<div className='absolute left-0 top-0 z-
|
|
195
|
+
<div className='relative z-1 border-b-2 p-8 pt-12 font-extrabold text-foreground'>
|
|
196
|
+
<div className='absolute left-0 top-0 z-2 h-4 w-full bg-linear-to-r from-emerald-800 via-emerald-400 to-sky-600'></div>
|
|
197
197
|
<h1 className='pb-4 text-4xl'>{data.section?.title.section}</h1>
|
|
198
198
|
<span>
|
|
199
199
|
/{getString('edit')} {data.section?.title.singular}
|
|
@@ -38,7 +38,7 @@ function Layout({ children }: { children: React.ReactNode }) {
|
|
|
38
38
|
{showMobileSidebar && (
|
|
39
39
|
// Display a black transparent div to close the sidebar when clicked outside
|
|
40
40
|
<div
|
|
41
|
-
className='fixed left-0 top-0 z-
|
|
41
|
+
className='fixed left-0 top-0 z-15 h-full w-full bg-black/80 md:hidden'
|
|
42
42
|
onClick={() => setShowMobileSidebar(false)}
|
|
43
43
|
></div>
|
|
44
44
|
)}
|
|
@@ -6,7 +6,7 @@ import React from 'react'
|
|
|
6
6
|
export default function LogPage() {
|
|
7
7
|
return (
|
|
8
8
|
<div className='w-full'>
|
|
9
|
-
<div className='bg-
|
|
9
|
+
<div className='bg-linear-to-r from-sky-200 via-emerald-300 to-blue-600 p-8 font-extrabold text-foreground dark:from-blue-800 dark:via-amber-700 dark:to-rose-900'>
|
|
10
10
|
<h1 className='text-3xl'>{getString('logs')}</h1>
|
|
11
11
|
</div>
|
|
12
12
|
|
|
@@ -14,11 +14,11 @@ const Navbar = (props: Props) => {
|
|
|
14
14
|
className={classNames({
|
|
15
15
|
'bg-white text-zinc-500': true, // colors
|
|
16
16
|
'flex items-center': true, // layout
|
|
17
|
-
'w-full md:w-full sticky z-10 px-4 shadow-
|
|
17
|
+
'w-full md:w-full sticky z-10 px-4 shadow-xs h-[73px] top-0 ': true, //positioning & styling
|
|
18
18
|
})}
|
|
19
19
|
>
|
|
20
20
|
<div className='font-bold text-lg'>Admin Panel</div>
|
|
21
|
-
<div className='
|
|
21
|
+
<div className='grow'></div>
|
|
22
22
|
<button className='md:hidden' onClick={props.onMenuButtonClick}>
|
|
23
23
|
<HamburgerMenuIcon className='h-6 w-6' />
|
|
24
24
|
</button>
|
|
@@ -50,19 +50,19 @@ export default function Navbar(props: Props) {
|
|
|
50
50
|
<>
|
|
51
51
|
<nav
|
|
52
52
|
className={classNames({
|
|
53
|
-
'sticky top-0 h-[65px] bg-white text-zinc-500 drop-shadow dark:bg-slate-800': true, // colors
|
|
54
|
-
'top-0 z-10 w-full px-4 shadow-
|
|
53
|
+
'sticky top-0 h-[65px] bg-white text-zinc-500 drop-shadow-sm dark:bg-slate-800': true, // colors
|
|
54
|
+
'top-0 z-10 w-full px-4 shadow-xs md:w-full': true, //positioning & styling
|
|
55
55
|
})}
|
|
56
56
|
>
|
|
57
57
|
<div className='mx-auto px-0 lg:px-2'>
|
|
58
58
|
<div className='flex h-16 items-center justify-between'>
|
|
59
59
|
<div className='flex items-center'>
|
|
60
|
-
<div className='
|
|
60
|
+
<div className='shrink-0'>
|
|
61
61
|
<div className='flex md:hidden'>
|
|
62
62
|
{/* Mobile menu button */}
|
|
63
63
|
<button
|
|
64
64
|
onClick={props.onMenuButtonClick}
|
|
65
|
-
className='relative inline-flex items-center justify-center rounded-md border border-foreground p-2 text-foreground hover:text-foreground/90 focus:outline-
|
|
65
|
+
className='relative inline-flex items-center justify-center rounded-md border border-foreground p-2 text-foreground hover:text-foreground/90 focus:outline-hidden focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800'
|
|
66
66
|
>
|
|
67
67
|
<span className='absolute -inset-0.5' />
|
|
68
68
|
<span className='sr-only'>Open main menu</span>
|
|
@@ -109,7 +109,7 @@ export default function Navbar(props: Props) {
|
|
|
109
109
|
setTheme(theme === 'dark' ? 'light' : 'dark')
|
|
110
110
|
}}
|
|
111
111
|
type='button'
|
|
112
|
-
className='relative rounded-full p-1 text-foreground hover:text-foreground/90 focus:outline-
|
|
112
|
+
className='relative rounded-full p-1 text-foreground hover:text-foreground/90 focus:outline-hidden'
|
|
113
113
|
>
|
|
114
114
|
<span className='absolute -inset-1.5' />
|
|
115
115
|
<span className='sr-only'>Theme</span>
|
|
@@ -123,7 +123,7 @@ export default function Navbar(props: Props) {
|
|
|
123
123
|
<DropdownMenu>
|
|
124
124
|
<DropdownMenuTrigger
|
|
125
125
|
asChild
|
|
126
|
-
className='relative ms-2 flex max-w-xs cursor-pointer items-center rounded-full bg-gray-800 text-sm hover:ring focus:outline-
|
|
126
|
+
className='relative ms-2 flex max-w-xs cursor-pointer items-center rounded-full bg-gray-800 text-sm hover:ring-3 focus:outline-hidden focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800'
|
|
127
127
|
>
|
|
128
128
|
<div>
|
|
129
129
|
<span className='absolute -inset-1.5' />
|
|
@@ -106,7 +106,7 @@ export default function NewAdminForm({
|
|
|
106
106
|
name='username'
|
|
107
107
|
type='text'
|
|
108
108
|
// required
|
|
109
|
-
className='block w-full rounded-md border-0 bg-input p-3 text-foreground shadow-
|
|
109
|
+
className='block w-full rounded-md border-0 bg-input p-3 text-foreground shadow-xs outline-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'
|
|
110
110
|
/>
|
|
111
111
|
</div>
|
|
112
112
|
</div>
|
|
@@ -122,7 +122,7 @@ export default function NewAdminForm({
|
|
|
122
122
|
name='password'
|
|
123
123
|
type='text'
|
|
124
124
|
// required
|
|
125
|
-
className='block w-full rounded-md border-0 bg-input p-3 text-foreground shadow-
|
|
125
|
+
className='block w-full rounded-md border-0 bg-input p-3 text-foreground shadow-xs outline-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'
|
|
126
126
|
/>
|
|
127
127
|
</div>
|
|
128
128
|
</div>
|
|
@@ -85,7 +85,7 @@ export default function NewEmailForm({ action }: { action: any }) {
|
|
|
85
85
|
type='text'
|
|
86
86
|
autoComplete='username'
|
|
87
87
|
required
|
|
88
|
-
className='block w-full rounded-md border-0 bg-input p-2.5 text-foreground shadow-
|
|
88
|
+
className='block w-full rounded-md border-0 bg-input p-2.5 text-foreground shadow-xs outline-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'
|
|
89
89
|
/>
|
|
90
90
|
</div>
|
|
91
91
|
</div>
|
|
@@ -101,7 +101,7 @@ export default function NewEmailForm({ action }: { action: any }) {
|
|
|
101
101
|
type='text'
|
|
102
102
|
autoComplete='password'
|
|
103
103
|
required
|
|
104
|
-
className='block w-full rounded-md border-0 bg-input p-2.5 text-foreground shadow-
|
|
104
|
+
className='block w-full rounded-md border-0 bg-input p-2.5 text-foreground shadow-xs outline-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'
|
|
105
105
|
/>
|
|
106
106
|
</div>
|
|
107
107
|
</div>
|
|
@@ -116,7 +116,7 @@ export default function NewEmailForm({ action }: { action: any }) {
|
|
|
116
116
|
type='number'
|
|
117
117
|
autoComplete='quota'
|
|
118
118
|
required
|
|
119
|
-
className='block rounded-md border-0 bg-input p-2.5 text-foreground shadow-
|
|
119
|
+
className='block rounded-md border-0 bg-input p-2.5 text-foreground shadow-xs outline-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6'
|
|
120
120
|
/>
|
|
121
121
|
<Badge className='rounded-sm border-muted-foreground text-muted-foreground' variant='secondary'>
|
|
122
122
|
0 = {getString('unlimited')}
|
|
@@ -181,8 +181,8 @@ export default function NewPage({
|
|
|
181
181
|
{isError ? <div>{error?.message}</div> : null}
|
|
182
182
|
{data ? (
|
|
183
183
|
<div className='flex w-full flex-col'>
|
|
184
|
-
<div className='relative z-
|
|
185
|
-
<div className='absolute left-0 top-0 z-
|
|
184
|
+
<div className='relative z-1 border-b-2 p-8 pt-12 font-extrabold text-foreground'>
|
|
185
|
+
<div className='absolute left-0 top-0 z-2 h-4 w-full bg-linear-to-r from-emerald-800 via-emerald-400 to-sky-600'></div>
|
|
186
186
|
<h1 className='pb-4 text-4xl'>{data.section?.title.section}</h1>
|
|
187
187
|
<span>
|
|
188
188
|
/{getString('new')} {data.section?.title.singular}
|
|
@@ -196,7 +196,7 @@ function NewVariantComponent(
|
|
|
196
196
|
<div className='mt-5'>
|
|
197
197
|
<button
|
|
198
198
|
className={classNames({
|
|
199
|
-
'w-full rounded bg-
|
|
199
|
+
'w-full rounded bg-linear-to-r p-2 font-bold text-white drop-shadow-sm':
|
|
200
200
|
true,
|
|
201
201
|
'from-emerald-700 via-green-700 to-green-500 dark:from-blue-800 dark:via-sky-800 dark:to-slate-500':
|
|
202
202
|
!isSubmitting,
|