+ {{#if this.mayHaveRolls}}
+
+ {{#if this.hasRolls}}
+ {{icon "rollmaster-dices" class="svg-roll"}}
+ {{#if this.errors.length}}
+ {{icon "triangle-exclamation" class="roll__invalid"}}
+ {{/if}}
+ {{/if}}
+
+ {{#if this.loading}}
+ {{icon "spinner" class="rollmaster-spinner"}}
+ {{/if}}
+
+ {{/if}}
+
+}
diff --git a/assets/javascripts/discourse/initializers/preview.js b/assets/javascripts/discourse/initializers/preview.js
new file mode 100644
index 0000000..e4e4eaf
--- /dev/null
+++ b/assets/javascripts/discourse/initializers/preview.js
@@ -0,0 +1,18 @@
+import { withPluginApi } from "discourse/lib/plugin-api";
+import ComposerValidRoll from "../components/composer-valid-roll";
+
+function initializeRollmasterPreview(api) {
+ const siteSettings = api.container.lookup("service:site-settings");
+ if (!siteSettings.rollmaster_enabled) {
+ return;
+ }
+
+ api.renderInOutlet("after-d-editor", ComposerValidRoll);
+}
+
+export default {
+ name: "rollmaster-composer-preview",
+ initialize() {
+ withPluginApi("2.0.0", initializeRollmasterPreview);
+ },
+};
diff --git a/assets/javascripts/lib/discourse-markdown/bbcode.js b/assets/javascripts/lib/discourse-markdown/bbcode.js
new file mode 100644
index 0000000..4afe472
--- /dev/null
+++ b/assets/javascripts/lib/discourse-markdown/bbcode.js
@@ -0,0 +1,53 @@
+import { i18n } from "discourse-i18n";
+
+const ROLL_CLASS = "bb-rollmaster";
+const DATA_DICE = "data-notation";
+
+function applyRollAttrs(state, token, attrs, content) {
+ token.attrs = [
+ ["class", ROLL_CLASS],
+ [DATA_DICE, content],
+ ];
+
+ if (content) {
+ token = state.push("text", "", 0);
+ token.content = i18n("rollmaster.bbcode.placeholder") + content;
+ }
+}
+
+const blockRule = {
+ tag: "roll",
+ replace(state, tagInfo, content) {
+ let token = state.push("roll_open", "div", 1);
+
+ applyRollAttrs(state, token, tagInfo.attrs, content);
+
+ state.push("roll_close", "div", -1);
+ return true;
+ },
+};
+
+const inlineRule = {
+ tag: "roll",
+ replace(state, tagInfo, content) {
+ let token = state.push("roll_open", "span", 1);
+
+ applyRollAttrs(state, token, tagInfo.attrs, content);
+
+ state.push("roll_close", "span", -1);
+ return true;
+ },
+};
+
+export function setup(helper) {
+ helper.allowList(["div.bb-rollmaster", "span.bb-rollmaster"]);
+
+ helper.registerOptions((opts) => {
+ opts.features["rollmaster"] = true;
+ });
+
+ helper.registerPlugin((md) => {
+ md.inline.bbcode.ruler.push("inline-roll", inlineRule);
+ md.block.bbcode.ruler.push("block-roll", blockRule);
+ });
+}
diff --git a/assets/stylesheets/.gitkeep b/assets/stylesheets/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/assets/stylesheets/common/index.scss b/assets/stylesheets/common/index.scss
new file mode 100644
index 0000000..999aa47
--- /dev/null
+++ b/assets/stylesheets/common/index.scss
@@ -0,0 +1,32 @@
+.rollmaster-valid-composer {
+ display: block;
+ position: absolute;
+ right: 0.125em;
+ bottom: 0em;
+ padding: 0.125em;
+
+ svg.svg-roll {
+ --success-mild: color-mix(
+ in srgb,
+ var(--success-medium),
+ rgb(140, 140, 140)
+ );
+ color: var(--success-mild, --success-medium);
+ &:has(~ .rollmaster-spinner) {
+ color: var(--primary-low-mid);
+ }
+
+ &:has(+ .roll__invalid) {
+ color: var(--danger);
+ }
+ }
+
+ svg.roll__invalid {
+ color: var(--danger);
+ }
+}
+
+.rollmaster-spinner {
+ animation: rotate-forever 1s infinite linear;
+ color: var(--primary-low-mid);
+}
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index e86bb19..d976371 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -6,4 +6,9 @@ en:
rollmaster: "Rollmaster"
js:
rollmaster:
- placeholder: placeholder
+ bbcode:
+ placeholder: "Rolling: "
+ validator:
+ loading: "validating roll notation..."
+ success: "all roll notations valid"
+ error: "invalid roll notation found"
diff --git a/plugin.rb b/plugin.rb
index 9a5e274..bad6c33 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -10,6 +10,8 @@
enabled_site_setting :rollmaster_enabled
+register_asset "stylesheets/common/index.scss"
+
module ::Rollmaster
PLUGIN_NAME = "rollmaster"
end
@@ -18,6 +20,9 @@ module ::Rollmaster
after_initialize do
# Code which should run after Rails has finished booting
+
+ register_svg_icon "rollmaster-dices"
+
# I don't think this is needed, but it doesn't hurt to be safe
::Rollmaster::DiceEngine.reset_context
diff --git a/svg-icons/sprites.svg b/svg-icons/sprites.svg
new file mode 100644
index 0000000..152b2de
--- /dev/null
+++ b/svg-icons/sprites.svg
@@ -0,0 +1,8 @@
+
+
+