diff --git a/extend.php b/extend.php index 48564dc..ee25804 100644 --- a/extend.php +++ b/extend.php @@ -28,6 +28,7 @@ (new Extend\Frontend('admin')) ->js(__DIR__.'/js/dist/admin.js') + ->css(__DIR__.'/resources/less/admin.less') ->content(function (Document $document) { $document->payload['fof-geoip.services'] = array_keys(GeoIP::$services); }), diff --git a/js/admin.js b/js/admin.ts similarity index 100% rename from js/admin.js rename to js/admin.ts diff --git a/js/forum.js b/js/forum.ts similarity index 100% rename from js/forum.js rename to js/forum.ts diff --git a/js/package.json b/js/package.json index 31d2a6a..e94a2cf 100644 --- a/js/package.json +++ b/js/package.json @@ -9,7 +9,7 @@ "external-load": "^1.0.0", "flarum-tsconfig": "^1.0.2", "flarum-webpack-config": "^2.0.0", - "linkify-lite": "^1.0.0", + "linkify-lite": "^2.0.0", "twemoji-basename": "^1.0.0", "webpack": "^5.94.0" }, diff --git a/js/src/admin/components/ExtensionSettingsPage.js b/js/src/admin/components/ExtensionSettingsPage.js deleted file mode 100644 index 732cacd..0000000 --- a/js/src/admin/components/ExtensionSettingsPage.js +++ /dev/null @@ -1,76 +0,0 @@ -import app from 'flarum/admin/app'; -import Alert from 'flarum/common/components/Alert'; -import ExtensionPage from 'flarum/admin/components/ExtensionPage'; -import humanTime from 'flarum/common/helpers/humanTime'; -import extractText from 'flarum/common/utils/extractText'; -import linkify from 'linkify-lite'; - -export default class GeoipSettingsPage extends ExtensionPage { - oninit(vnode) { - super.oninit(vnode); - } - - content() { - const service = this.setting('fof-geoip.service')(); - const errorTime = Number(app.data.settings[`fof-geoip.services.${service}.last_error_time`]) * 1000; - let error = app.data.settings[`fof-geoip.services.${service}.error`]; - - if (error) error = linkify(error); - - return [ -
-
-
- {this.buildSettingComponent({ - type: 'select', - setting: 'fof-geoip.service', - label: app.translator.trans('fof-geoip.admin.settings.service_label'), - options: app.data['fof-geoip.services'].reduce((o, p) => { - o[p] = app.translator.trans(`fof-geoip.admin.settings.service_${p}_label`); - return o; - }, {}), - required: true, - help: service && m.trust(linkify(extractText(app.translator.trans(`fof-geoip.admin.settings.service_${service}_description`)))), - })} -
- {error - ? Alert.component( - { - className: 'Form-group', - dismissible: false, - }, - [{humanTime(errorTime)}, m.trust(error)] - ) - : ''} - - {['ipdata', 'ipapi-pro', 'ipsevenex'].includes(service) - ? [ - this.buildSettingComponent({ - type: 'string', - setting: `fof-geoip.services.${service}.access_key`, - label: app.translator.trans('fof-geoip.admin.settings.access_key_label'), - required: true, - }), - ] - : []} - {service === 'ipdata' - ? this.buildSettingComponent({ - type: 'number', - setting: 'fof-geoip.services.ipdata.quota', - label: app.translator.trans('fof-geoip.admin.settings.quota_label'), - min: 1500, - placeholder: 1500, - }) - : []} - {this.buildSettingComponent({ - setting: 'fof-geoip.showFlag', - type: 'boolean', - label: app.translator.trans('fof-geoip.admin.settings.show_flag_label'), - help: app.translator.trans('fof-geoip.admin.settings.show_flag_help'), - })} - {this.submitButton()} -
-
, - ]; - } -} diff --git a/js/src/admin/components/GeoipSettingsPage.tsx b/js/src/admin/components/GeoipSettingsPage.tsx new file mode 100644 index 0000000..9bb26e4 --- /dev/null +++ b/js/src/admin/components/GeoipSettingsPage.tsx @@ -0,0 +1,121 @@ +import app from 'flarum/admin/app'; +import Alert from 'flarum/common/components/Alert'; +import ExtensionPage from 'flarum/admin/components/ExtensionPage'; +import humanTime from 'flarum/common/helpers/humanTime'; +import extractText from 'flarum/common/utils/extractText'; +import Mithril from 'mithril'; +import ItemList from 'flarum/common/utils/ItemList'; +// @ts-expect-error +import linkify from 'linkify-lite'; + +export default class GeoipSettingsPage extends ExtensionPage { + content() { + const service = this.setting('fof-geoip.service')(); + const errorTime = Number(app.data.settings[`fof-geoip.services.${service}.last_error_time`]) * 1000; + const error = app.data.settings[`fof-geoip.services.${service}.error`] as string | undefined; + + return ( +
+
+
+
+ {error && ( + + {humanTime(new Date(errorTime))} + {error} + + )} + {this.settingsItems().toArray()} +
{this.submitButton()}
+
+
+
+
+ ); + } + + settingsItems(): ItemList { + const items = new ItemList(); + + items.add( + 'general', +
+

{app.translator.trans('fof-geoip.admin.settings.general.heading')}

+

{app.translator.trans('fof-geoip.admin.settings.general.help')}

+ {this.generalItems().toArray()} +
+ ); + + items.add( + 'providers', +
+

{app.translator.trans('fof-geoip.admin.settings.providers.heading')}

+

{app.translator.trans('fof-geoip.admin.settings.providers.help')}

+ {this.providerItems().toArray()} +
+ ); + + return items; + } + + generalItems(): ItemList { + const items = new ItemList(); + + items.add( + 'show-flags', + this.buildSettingComponent({ + setting: 'fof-geoip.showFlag', + type: 'boolean', + label: app.translator.trans('fof-geoip.admin.settings.show_flag_label'), + help: app.translator.trans('fof-geoip.admin.settings.show_flag_help'), + }) + ); + + return items; + } + + providerItems(): ItemList { + const items = new ItemList(); + const service = this.setting('fof-geoip.service')(); + + items.add( + 'service', + this.buildSettingComponent({ + type: 'select', + setting: 'fof-geoip.service', + label: app.translator.trans('fof-geoip.admin.settings.service_label'), + options: (app.data['fof-geoip.services'] as string[]).reduce((o: { [x: string]: string }, p: string) => { + o[p] = extractText(app.translator.trans(`fof-geoip.admin.settings.service_${p}_label`)); + return o; + }, {}), + required: true, + help: service && m.trust(linkify(extractText(app.translator.trans(`fof-geoip.admin.settings.service_${service}_description`)))), + }) + ); + + ['ipdata', 'ipapi-pro', 'ipsevenex'].includes(service) && + items.add( + 'api-key', + this.buildSettingComponent({ + type: 'string', + setting: `fof-geoip.services.${service}.access_key`, + label: app.translator.trans('fof-geoip.admin.settings.access_key_label'), + required: true, + }) + ); + + service === 'ipdata' && + items.add( + 'ipdata-quota', + this.buildSettingComponent({ + type: 'number', + setting: 'fof-geoip.services.ipdata.quota', + label: app.translator.trans('fof-geoip.admin.settings.quota_label'), + min: 1500, + placeholder: 1500, + }) + ); + + return items; + } +} diff --git a/js/src/admin/components/index.ts b/js/src/admin/components/index.ts new file mode 100644 index 0000000..d907a75 --- /dev/null +++ b/js/src/admin/components/index.ts @@ -0,0 +1,5 @@ +import GeoipSettingsPage from './GeoipSettingsPage'; + +export const components = { + GeoipSettingsPage, +}; diff --git a/js/src/admin/index.js b/js/src/admin/index.ts similarity index 80% rename from js/src/admin/index.js rename to js/src/admin/index.ts index 5279d24..fb17e2b 100644 --- a/js/src/admin/index.js +++ b/js/src/admin/index.ts @@ -1,5 +1,7 @@ import app from 'flarum/admin/app'; -import GeoipSettingsPage from './components/ExtensionSettingsPage'; +import GeoipSettingsPage from './components/GeoipSettingsPage'; + +export * from './components'; app.initializers.add('fof/geoip', () => { app.extensionData diff --git a/js/yarn.lock b/js/yarn.lock index 2b2fc0b..6bc29ee 100644 --- a/js/yarn.lock +++ b/js/yarn.lock @@ -1791,10 +1791,10 @@ kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -linkify-lite@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/linkify-lite/-/linkify-lite-1.0.0.tgz#04b122280128475cacef01f8ca1f5e9d2b9c8213" - integrity sha512-ZCvbdDUcvM+d9uiPS772ESSYwL42yu4yWjB20DpZfQGvbhyKOMX5+Gq5iH6IiSxzv8qJ6kQYJDtyATfgqRgJ8w== +linkify-lite@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/linkify-lite/-/linkify-lite-2.0.1.tgz#8a84253f0e7a5603e9cd8f57f8548be918344c4e" + integrity sha512-/VYMIfkN+rCuSGQnXM8TriPfs7cKXf6Rrbu5orHvrENbh6paR2r1DF42wQwtPRkGV4Zjd1DGFsFNcQdmusRtYQ== loader-runner@^4.2.0: version "4.3.0" diff --git a/resources/less/admin.less b/resources/less/admin.less new file mode 100644 index 0000000..d2a3ff0 --- /dev/null +++ b/resources/less/admin.less @@ -0,0 +1,49 @@ +.GeoipSettingsPage { + padding-top: 20px; + + .Button { + margin-right: 10px; + margin-bottom: 10px; + } + + .GeoipSettingsTabPage { + background: @control-bg; + padding: 20px; + border-radius: @border-radius; + box-shadow: 0 2px 4px @shadow-color; + + h3 { + color: @primary-color; + margin-bottom: 10px; + } + + .Section { + background: @body-bg; + border-radius: @border-radius; + box-shadow: 0 1px 3px @shadow-color; + padding: 15px; + margin-bottom: 20px; + } + + .Form { + .control { + background: @body-bg; + border: 1px solid @muted-color; + color: @text-color; + padding: 6px 12px; + border-radius: @border-radius; + } + input { + max-width: 300px; + } + } + } + + &--settings { + margin: 0 auto; + + @media @desktop-up { + margin: 0; + } + } +} diff --git a/resources/locale/en.yml b/resources/locale/en.yml index 76fa433..f882e79 100644 --- a/resources/locale/en.yml +++ b/resources/locale/en.yml @@ -3,8 +3,12 @@ fof-geoip: permissions: see_country: Always display the country of the IP address settings: - title: FriendsOfFlarum GeoIP - + general: + heading: General Settings + help: "These settings control the general behavior of the extension." + providers: + heading: IP Lookup Service + help: "Choose a service to use for IP lookups. Some services have rate limits, so be sure to check the service's documentation for more information." service_label: Service service_ipdata_label: IPData