├── .emoji-test.txt ├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── _locales ├── cs │ └── messages.json ├── de │ └── messages.json ├── en │ └── messages.json ├── es │ └── messages.json ├── fr │ └── messages.json ├── it │ └── messages.json ├── ja │ └── messages.json ├── ru │ └── messages.json └── vi │ └── messages.json ├── default.css ├── default.js ├── icons ├── icon128.png ├── icon16.png ├── icon24.png └── icon48.png ├── manifest.json ├── mods.js ├── mods ├── advanced-formatting.css ├── advanced-formatting.js ├── compact-posts.css ├── header-scroll.css ├── notification-icons.css ├── signature-mod.css ├── square-avatars.css ├── theme-preview.js └── userID.css ├── options ├── localisation.js ├── options.css ├── options.html ├── options.js └── theme-machine.js ├── serviceworker.js ├── theme.js └── themes ├── custom.css ├── vivaldi-dark.css └── vivaldi-light.css /.emoji-test.txt: -------------------------------------------------------------------------------- 1 | Smileys 2 | 😀 😁 😂 🤣 😃 😄 😅 😆 😉 😊 😋 😎 😍 😘 🥰 😗 😙 😚 ☺️ 🙂 🤗 🤩 🤔 🤨 😐 😑 😶 🙄 😏 😣 😥 😮 🤐 😯 😪 😫 😴 😌 😛 😜 😝 🤤 😒 😓 😔 😕 🙃 🤑 😲 ☹️ 🙁 😖 😞 😟 😤 😢 😭 😦 😧 😨 😩 🤯 😬 😰 😱 🥵 🥶 😳 🤪 😵 😡 😠 🤬 😷 🤒 🤕 🤢 🤮 🤧 😇 🤠 🤡 🥳 🥴 🥺 🤥 🤫 🤭 🧐 🤓 😈 👿 👹 👺 💀 👻 👽 🤖 💩 😺 😸 😹 😻 😼 😽 🙀 😿 😾 3 | 4 | People and Fantasy 5 | 👶 👧 🧒 👦 👩 🧑 👨 👵 🧓 👴 👲 👳‍♀️ 👳‍♂️ 🧕 🧔 👱‍♂️ 👱‍♀️ 👨‍🦰 👩‍🦰 👨‍🦱 👩‍🦱 👨‍🦲 👩‍🦲 👨‍🦳 👩‍🦳 🦸‍♀️ 🦸‍♂️ 🦹‍♀️ 🦹‍♂️ 👮‍♀️ 👮‍♂️ 👷‍♀️ 👷‍♂️ 💂‍♀️ 💂‍♂️ 🕵️‍♀️ 🕵️‍♂️ 👩‍⚕️ 👨‍⚕️ 👩‍🌾 👨‍🌾 👩‍🍳 👨‍🍳 👩‍🎓 👨‍🎓 👩‍🎤 👨‍🎤 👩‍🏫 👨‍🏫 👩‍🏭 👨‍🏭 👩‍💻 👨‍💻 👩‍💼 👨‍💼 👩‍🔧 👨‍🔧 👩‍🔬 👨‍🔬 👩‍🎨 👨‍🎨 👩‍🚒 👨‍🚒 👩‍✈️ 👨‍✈️ 👩‍🚀 👨‍🚀 👩‍⚖️ 👨‍⚖️ 👰 🤵 👸 🤴 🤶 🎅 🧙‍♀️ 🧙‍♂️ 🧝‍♀️ 🧝‍♂️ 🧛‍♀️ 🧛‍♂️ 🧟‍♀️ 🧟‍♂️ 🧞‍♀️ 🧞‍♂️ 🧜‍♀️ 🧜‍♂️ 🧚‍♀️ 🧚‍♂️ 👼 🤰 🤱 🙇‍♀️ 🙇‍♂️ 💁‍♀️ 💁‍♂️ 🙅‍♀️ 🙅‍♂️ 🙆‍♀️ 🙆‍♂️ 🙋‍♀️ 🙋‍♂️ 🤦‍♀️ 🤦‍♂️ 🤷‍♀️ 🤷‍♂️ 🙎‍♀️ 🙎‍♂️ 🙍‍♀️ 🙍‍♂️ 💇‍♀️ 💇‍♂️ 💆‍♀️ 💆‍♂️ 🧖‍♀️ 🧖‍♂️ 💅 🤳 💃 🕺 👯‍♀️ 👯‍♂️ 🕴 🚶‍♀️ 🚶‍♂️ 🏃‍♀️ 🏃‍♂️ 👫 👭 👬 💑 👩‍❤️‍👩 👨‍❤️‍👨 💏 👩‍❤️‍💋‍👩 👨‍❤️‍💋‍👨 👪 👨‍👩‍👧 👨‍👩‍👧‍👦 👨‍👩‍👦‍👦 👨‍👩‍👧‍👧 👩‍👩‍👦 👩‍👩‍👧 👩‍👩‍👧‍👦 👩‍👩‍👦‍👦 👩‍👩‍👧‍👧 👨‍👨‍👦 👨‍👨‍👧 👨‍👨‍👧‍👦 👨‍👨‍👦‍👦 👨‍👨‍👧‍👧 👩‍👦 👩‍👧 👩‍👧‍👦 👩‍👦‍👦 👩‍👧‍👧 👨‍👦 👨‍👧 👨‍👧‍👦 👨‍👦‍👦 👨‍👧‍👧 🤲 👐 🙌 👏 🤝 👍 👎 👊 ✊ 🤛 🤜 🤞 ✌️ 🤟 🤘 👌 👈 👉 👆 👇 ☝️ ✋ 🤚 🖐 🖖 👋 🤙 💪 🦵 🦶 🖕 ✍️ 🙏 💍 💄 💋 👄 👅 👂 👃 👣 👁 👀 🧠 🦴 🦷 🗣 👤 👥 6 | 7 | Clothing and Accessories 8 | 🧥 👚 👕 👖 👔 👗 👙 👘 👠 👡 👢 👞 👟 🥾 🥿 🧦 🧤 🧣 🎩 🧢 👒 🎓 ⛑ 👑 👝 👛 👜 💼 🎒 👓 🕶 🥽 🥼 🌂 🧵 🧶 9 | 10 | Pale Emojis 11 | 👶🏻 👦🏻 👧🏻 👨🏻 👩🏻 👱🏻‍♀️ 👱🏻 👴🏻 👵🏻 👲🏻 👳🏻‍♀️ 👳🏻 👮🏻‍♀️ 👮🏻 👷🏻‍♀️ 👷🏻 💂🏻‍♀️ 💂🏻 🕵🏻‍♀️ 🕵🏻 👩🏻‍⚕️ 👨🏻‍⚕️ 👩🏻‍🌾 👨🏻‍🌾 👩🏻‍🍳 👨🏻‍🍳 👩🏻‍🎓 👨🏻‍🎓 👩🏻‍🎤 👨🏻‍🎤 👩🏻‍🏫 👨🏻‍🏫 👩🏻‍🏭 👨🏻‍🏭 👩🏻‍💻 👨🏻‍💻 👩🏻‍💼 👨🏻‍💼 👩🏻‍🔧 👨🏻‍🔧 👩🏻‍🔬 👨🏻‍🔬 👩🏻‍🎨 👨🏻‍🎨 👩🏻‍🚒 👨🏻‍🚒 👩🏻‍✈️ 👨🏻‍✈️ 👩🏻‍🚀 👨🏻‍🚀 👩🏻‍⚖️ 👨🏻‍⚖️ 🤶🏻 🎅🏻 👸🏻 🤴🏻 👰🏻 🤵🏻 👼🏻 🤰🏻 🙇🏻‍♀️ 🙇🏻 💁🏻 💁🏻‍♂️ 🙅🏻 🙅🏻‍♂️ 🙆🏻 🙆🏻‍♂️ 🙋🏻 🙋🏻‍♂️ 🤦🏻‍♀️ 🤦🏻‍♂️ 🤷🏻‍♀️ 🤷🏻‍♂️ 🙎🏻 🙎🏻‍♂️ 🙍🏻 🙍🏻‍♂️ 💇🏻 💇🏻‍♂️ 💆🏻 💆🏻‍♂️ 🕴🏻 💃🏻 🕺🏻 🚶🏻‍♀️ 🚶🏻 🏃🏻‍♀️ 🏃🏻 🤲🏻 👐🏻 🙌🏻 👏🏻 🙏🏻 👍🏻 👎🏻 👊🏻 ✊🏻 🤛🏻 🤜🏻 🤞🏻 ✌🏻 🤟🏻 🤘🏻 👌🏻 👈🏻 👉🏻 👆🏻 👇🏻 ☝🏻 ✋🏻 🤚🏻 🖐🏻 🖖🏻 👋🏻 🤙🏻 💪🏻 🖕🏻 ✍🏻 🤳🏻 💅🏻 👂🏻 👃🏻 12 | 13 | Cream White Emojis 14 | 👶🏼 👦🏼 👧🏼 👨🏼 👩🏼 👱🏼‍♀️ 👱🏼 👴🏼 👵🏼 👲🏼 👳🏼‍♀️ 👳🏼 👮🏼‍♀️ 👮🏼 👷🏼‍♀️ 👷🏼 💂🏼‍♀️ 💂🏼 🕵🏼‍♀️ 🕵🏼 👩🏼‍⚕️ 👨🏼‍⚕️ 👩🏼‍🌾 👨🏼‍🌾 👩🏼‍🍳 👨🏼‍🍳 👩🏼‍🎓 👨🏼‍🎓 👩🏼‍🎤 👨🏼‍🎤 👩🏼‍🏫 👨🏼‍🏫 👩🏼‍🏭 👨🏼‍🏭 👩🏼‍💻 👨🏼‍💻 👩🏼‍💼 👨🏼‍💼 👩🏼‍🔧 👨🏼‍🔧 👩🏼‍🔬 👨🏼‍🔬 👩🏼‍🎨 👨🏼‍🎨 👩🏼‍🚒 👨🏼‍🚒 👩🏼‍✈️ 👨🏼‍✈️ 👩🏼‍🚀 👨🏼‍🚀 👩🏼‍⚖️ 👨🏼‍⚖️ 🤶🏼 🎅🏼 👸🏼 🤴🏼 👰🏼 🤵🏼 👼🏼 🤰🏼 🙇🏼‍♀️ 🙇🏼 💁🏼 💁🏼‍♂️ 🙅🏼 🙅🏼‍♂️ 🙆🏼 🙆🏼‍♂️ 🙋🏼 🙋🏼‍♂️ 🤦🏼‍♀️ 🤦🏼‍♂️ 🤷🏼‍♀️ 🤷🏼‍♂️ 🙎🏼 🙎🏼‍♂️ 🙍🏼 🙍🏼‍♂️ 💇🏼 💇🏼‍♂️ 💆🏼 💆🏼‍♂️ 🕴🏼 💃🏼 🕺🏼 🚶🏼‍♀️ 🚶🏼 🏃🏼‍♀️ 🏃🏼 🤲🏼 👐🏼 🙌🏼 👏🏼 🙏🏼 👍🏼 👎🏼 👊🏼 ✊🏼 🤛🏼 🤜🏼 🤞🏼 ✌🏼 🤟🏼 🤘🏼 👌🏼 👈🏼 👉🏼 👆🏼 👇🏼 ☝🏼 ✋🏼 🤚🏼 🖐🏼 🖖🏼 👋🏼 🤙🏼 💪🏼 🖕🏼 ✍🏼 🤳🏼 💅🏼 👂🏼 👃🏼 15 | 16 | Moderate Brown Emojis 17 | 👶🏽 👦🏽 👧🏽 👨🏽 👩🏽 👱🏽‍♀️ 👱🏽 👴🏽 👵🏽 👲🏽 👳🏽‍♀️ 👳🏽 👮🏽‍♀️ 👮🏽 👷🏽‍♀️ 👷🏽 💂🏽‍♀️ 💂🏽 🕵🏽‍♀️ 🕵🏽 👩🏽‍⚕️ 👨🏽‍⚕️ 👩🏽‍🌾 👨🏽‍🌾 👩🏽‍🍳 👨🏽‍🍳 👩🏽‍🎓 👨🏽‍🎓 👩🏽‍🎤 👨🏽‍🎤 👩🏽‍🏫 👨🏽‍🏫 👩🏽‍🏭 👨🏽‍🏭 👩🏽‍💻 👨🏽‍💻 👩🏽‍💼 👨🏽‍💼 👩🏽‍🔧 👨🏽‍🔧 👩🏽‍🔬 👨🏽‍🔬 👩🏽‍🎨 👨🏽‍🎨 👩🏽‍🚒 👨🏽‍🚒 👩🏽‍✈️ 👨🏽‍✈️ 👩🏽‍🚀 👨🏽‍🚀 👩🏽‍⚖️ 👨🏽‍⚖️ 🤶🏽 🎅🏽 👸🏽 🤴🏽 👰🏽 🤵🏽 👼🏽 🤰🏽 🙇🏽‍♀️ 🙇🏽 💁🏽 💁🏽‍♂️ 🙅🏽 🙅🏽‍♂️ 🙆🏽 🙆🏽‍♂️ 🙋🏽 🙋🏽‍♂️ 🤦🏽‍♀️ 🤦🏽‍♂️ 🤷🏽‍♀️ 🤷🏽‍♂️ 🙎🏽 🙎🏽‍♂️ 🙍🏽 🙍🏽‍♂️ 💇🏽 💇🏽‍♂️ 💆🏽 💆🏽‍♂️ 🕴🏼 💃🏽 🕺🏽 🚶🏽‍♀️ 🚶🏽 🏃🏽‍♀️ 🏃🏽 🤲🏽 👐🏽 🙌🏽 👏🏽 🙏🏽 👍🏽 👎🏽 👊🏽 ✊🏽 🤛🏽 🤜🏽 🤞🏽 ✌🏽 🤟🏽 🤘🏽 👌🏽 👈🏽 👉🏽 👆🏽 👇🏽 ☝🏽 ✋🏽 🤚🏽 🖐🏽 🖖🏽 👋🏽 🤙🏽 💪🏽 🖕🏽 ✍🏽 🤳🏽 💅🏽 👂🏽 👃🏽 18 | 19 | Dark Brown Emojis 20 | 👶🏾 👦🏾 👧🏾 👨🏾 👩🏾 👱🏾‍♀️ 👱🏾 👴🏾 👵🏾 👲🏾 👳🏾‍♀️ 👳🏾 👮🏾‍♀️ 👮🏾 👷🏾‍♀️ 👷🏾 💂🏾‍♀️ 💂🏾 🕵🏾‍♀️ 🕵🏾 👩🏾‍⚕️ 👨🏾‍⚕️ 👩🏾‍🌾 👨🏾‍🌾 👩🏾‍🍳 👨🏾‍🍳 👩🏾‍🎓 👨🏾‍🎓 👩🏾‍🎤 👨🏾‍🎤 👩🏾‍🏫 👨🏾‍🏫 👩🏾‍🏭 👨🏾‍🏭 👩🏾‍💻 👨🏾‍💻 👩🏾‍💼 👨🏾‍💼 👩🏾‍🔧 👨🏾‍🔧 👩🏾‍🔬 👨🏾‍🔬 👩🏾‍🎨 👨🏾‍🎨 👩🏾‍🚒 👨🏾‍🚒 👩🏾‍✈️ 👨🏾‍✈️ 👩🏾‍🚀 👨🏾‍🚀 👩🏾‍⚖️ 👨🏾‍⚖️ 🤶🏾 🎅🏾 👸🏾 🤴🏾 👰🏾 🤵🏾 👼🏾 🤰🏾 🙇🏾‍♀️ 🙇🏾 💁🏾 💁🏾‍♂️ 🙅🏾 🙅🏾‍♂️ 🙆🏾 🙆🏾‍♂️ 🙋🏾 🙋🏾‍♂️ 🤦🏾‍♀️ 🤦🏾‍♂️ 🤷🏾‍♀️ 🤷🏾‍♂️ 🙎🏾 🙎🏾‍♂️ 🙍🏾 🙍🏾‍♂️ 💇🏾 💇🏾‍♂️ 💆🏾 💆🏾‍♂️ 🕴🏾 💃🏾 🕺🏾 🚶🏾‍♀️ 🚶🏾 🏃🏾‍♀️ 🏃🏾 🤲🏾 👐🏾 🙌🏾 👏🏾 🙏🏾 👍🏾 👎🏾 👊🏾 ✊🏾 🤛🏾 🤜🏾 🤞🏾 ✌🏾 🤟🏾 🤘🏾 👌🏾 👈🏾 👉🏾 👆🏾 👇🏾 ☝🏾 ✋🏾 🤚🏾 🖐🏾 🖖🏾 👋🏾 🤙🏾 💪🏾 🖕🏾 ✍🏾 🤳🏾 💅🏾 👂🏾 👃🏾 21 | 22 | Black Emojis 23 | 👶🏿 👦🏿 👧🏿 👨🏿 👩🏿 👱🏿‍♀️ 👱🏿 👴🏿 👵🏿 👲🏿 👳🏿‍♀️ 👳🏿 👮🏿‍♀️ 👮🏿 👷🏿‍♀️ 👷🏿 💂🏿‍♀️ 💂🏿 🕵🏿‍♀️ 🕵🏿 👩🏿‍⚕️ 👨🏿‍⚕️ 👩🏿‍🌾 👨🏿‍🌾 👩🏿‍🍳 👨🏿‍🍳 👩🏿‍🎓 👨🏿‍🎓 👩🏿‍🎤 👨🏿‍🎤 👩🏿‍🏫 👨🏿‍🏫 👩🏿‍🏭 👨🏿‍🏭 👩🏿‍💻 👨🏿‍💻 👩🏿‍💼 👨🏿‍💼 👩🏿‍🔧 👨🏿‍🔧 👩🏿‍🔬 👨🏿‍🔬 👩🏿‍🎨 👨🏿‍🎨 👩🏿‍🚒 👨🏿‍🚒 👩🏿‍✈️ 👨🏿‍✈️ 👩🏿‍🚀 👨🏿‍🚀 👩🏿‍⚖️ 👨🏿‍⚖️ 🤶🏿 🎅🏿 👸🏿 🤴🏿 👰🏿 🤵🏿 👼🏿 🤰🏿 🙇🏿‍♀️ 🙇🏿 💁🏿 💁🏿‍♂️ 🙅🏿 🙅🏿‍♂️ 🙆🏿 🙆🏿‍♂️ 🙋🏿 🙋🏿‍♂️ 🤦🏿‍♀️ 🤦🏿‍♂️ 🤷🏿‍♀️ 🤷🏿‍♂️ 🙎🏿 🙎🏿‍♂️ 🙍🏿 🙍🏿‍♂️ 💇🏿 💇🏿‍♂️ 💆🏿 💆🏿‍♂️ 🕴🏿 💃🏿 🕺🏿 🚶🏿‍♀️ 🚶🏿 🏃🏿‍♀️ 🏃🏿 🤲🏿 👐🏿 🙌🏿 👏🏿 🙏🏿 👍🏿 👎🏿 👊🏿 ✊🏿 🤛🏿 🤜🏿 🤞🏿 ✌🏿 🤟🏿 🤘🏿 👌🏿 👈🏿 👉🏿 👆🏿 👇🏿 ☝🏿 ✋🏿 🤚🏿 🖐🏿 🖖🏿 👋🏿 🤙🏿 💪🏿 🖕🏿 ✍🏿 🤳🏿 💅🏿 👂🏿 👃🏿 24 | 25 | Animals & Nature 26 | 🐶 🐱 🐭 🐹 🐰 🦊 🦝 🐻 🐼 🦘 🦡 🐨 🐯 🦁 🐮 🐷 🐽 🐸 🐵 🙈 🙉 🙊 🐒 🐔 🐧 🐦 🐤 🐣 🐥 🦆 🦢 🦅 🦉 🦚 🦜 🦇 🐺 🐗 🐴 🦄 🐝 🐛 🦋 🐌 🐚 🐞 🐜 🦗 🕷 🕸 🦂 🦟 🦠 🐢 🐍 🦎 🦖 🦕 🐙 🦑 🦐 🦀 🐡 🐠 🐟 🐬 🐳 🐋 🦈 🐊 🐅 🐆 🦓 🦍 🐘 🦏 🦛 🐪 🐫 🦙 🦒 🐃 🐂 🐄 🐎 🐖 🐏 🐑 🐐 🦌 🐕 🐩 🐈 🐓 🦃 🕊 🐇 🐁 🐀 🐿 🦔 🐾 🐉 🐲 🌵 🎄 🌲 🌳 🌴 🌱 🌿 ☘️ 🍀 🎍 🎋 🍃 🍂 🍁 🍄 🌾 💐 🌷 🌹 🥀 🌺 🌸 🌼 🌻 🌞 🌝 🌛 🌜 🌚 🌕 🌖 🌗 🌘 🌑 🌒 🌓 🌔 🌙 🌎 🌍 🌏 💫 ⭐️ 🌟 ✨ ⚡️ ☄️ 💥 🔥 🌪 🌈 ☀️ 🌤 ⛅️ 🌥 ☁️ 🌦 🌧 ⛈ 🌩 🌨 ❄️ ☃️ ⛄️ 🌬 💨 💧 💦 ☔️ ☂️ 🌊 🌫 27 | 28 | Food & Drink 29 | 🍏 🍎 🍐 🍊 🍋 🍌 🍉 🍇 🍓 🍈 🍒 🍑 🍍 🥭 🥥 🥝 🍅 🍆 🥑 🥦 🥒 🥬 🌶 🌽 🥕 🥔 🍠 🥐 🍞 🥖 🥨 🥯 🧀 🥚 🍳 🥞 🥓 🥩 🍗 🍖 🌭 🍔 🍟 🍕 🥪 🥙 🌮 🌯 🥗 🥘 🥫 🍝 🍜 🍲 🍛 🍣 🍱 🥟 🍤 🍙 🍚 🍘 🍥 🥮 🥠 🍢 🍡 🍧 🍨 🍦 🥧 🍰 🎂 🍮 🍭 🍬 🍫 🍿 🧂 🍩 🍪 🌰 🥜 🍯 🥛 🍼 ☕️ 🍵 🥤 🍶 🍺 🍻 🥂 🍷 🥃 🍸 🍹 🍾 🥄 🍴 🍽 🥣 🥡 🥢 30 | 31 | Activity and Sports 32 | ⚽️ 🏀 🏈 ⚾️ 🥎 🏐 🏉 🎾 🥏 🎱 🏓 🏸 🥅 🏒 🏑 🥍 🏏 ⛳️ 🏹 🎣 🥊 🥋 🎽 ⛸ 🥌 🛷 🛹 🎿 ⛷ 🏂 🏋️‍♀️ 🏋🏻‍♀️ 🏋🏼‍♀️ 🏋🏽‍♀️ 🏋🏾‍♀️ 🏋🏿‍♀️ 🏋️‍♂️ 🏋🏻‍♂️ 🏋🏼‍♂️ 🏋🏽‍♂️ 🏋🏾‍♂️ 🏋🏿‍♂️ 🤼‍♀️ 🤼‍♂️ 🤸‍♀️ 🤸🏻‍♀️ 🤸🏼‍♀️ 🤸🏽‍♀️ 🤸🏾‍♀️ 🤸🏿‍♀️ 🤸‍♂️ 🤸🏻‍♂️ 🤸🏼‍♂️ 🤸🏽‍♂️ 🤸🏾‍♂️ 🤸🏿‍♂️ ⛹️‍♀️ ⛹🏻‍♀️ ⛹🏼‍♀️ ⛹🏽‍♀️ ⛹🏾‍♀️ ⛹🏿‍♀️ ⛹️‍♂️ ⛹🏻‍♂️ ⛹🏼‍♂️ ⛹🏽‍♂️ ⛹🏾‍♂️ ⛹🏿‍♂️ 🤺 🤾‍♀️ 🤾🏻‍♀️ 🤾🏼‍♀️ 🤾🏾‍♀️ 🤾🏾‍♀️ 🤾🏿‍♀️ 🤾‍♂️ 🤾🏻‍♂️ 🤾🏼‍♂️ 🤾🏽‍♂️ 🤾🏾‍♂️ 🤾🏿‍♂️ 🏌️‍♀️ 🏌🏻‍♀️ 🏌🏼‍♀️ 🏌🏽‍♀️ 🏌🏾‍♀️ 🏌🏿‍♀️ 🏌️‍♂️ 🏌🏻‍♂️ 🏌🏼‍♂️ 🏌🏽‍♂️ 🏌🏾‍♂️ 🏌🏿‍♂️ 🏇 🏇🏻 🏇🏼 🏇🏽 🏇🏾 🏇🏿 🧘‍♀️ 🧘🏻‍♀️ 🧘🏼‍♀️ 🧘🏽‍♀️ 🧘🏾‍♀️ 🧘🏿‍♀️ 🧘‍♂️ 🧘🏻‍♂️ 🧘🏼‍♂️ 🧘🏽‍♂️ 🧘🏾‍♂️ 🧘🏿‍♂️ 🏄‍♀️ 🏄🏻‍♀️ 🏄🏼‍♀️ 🏄🏽‍♀️ 🏄🏾‍♀️ 🏄🏿‍♀️ 🏄‍♂️ 🏄🏻‍♂️ 🏄🏼‍♂️ 🏄🏽‍♂️ 🏄🏾‍♂️ 🏄🏿‍♂️ 🏊‍♀️ 🏊🏻‍♀️ 🏊🏼‍♀️ 🏊🏽‍♀️ 🏊🏾‍♀️ 🏊🏿‍♀️ 🏊‍♂️ 🏊🏻‍♂️ 🏊🏼‍♂️ 🏊🏽‍♂️ 🏊🏾‍♂️ 🏊🏿‍♂️ 🤽‍♀️ 🤽🏻‍♀️ 🤽🏼‍♀️ 🤽🏽‍♀️ 🤽🏾‍♀️ 🤽🏿‍♀️ 🤽‍♂️ 🤽🏻‍♂️ 🤽🏼‍♂️ 🤽🏽‍♂️ 🤽🏾‍♂️ 🤽🏿‍♂️ 🚣‍♀️ 🚣🏻‍♀️ 🚣🏼‍♀️ 🚣🏽‍♀️ 🚣🏾‍♀️ 🚣🏿‍♀️ 🚣‍♂️ 🚣🏻‍♂️ 🚣🏼‍♂️ 🚣🏽‍♂️ 🚣🏾‍♂️ 🚣🏿‍♂️ 🧗‍♀️ 🧗🏻‍♀️ 🧗🏼‍♀️ 🧗🏽‍♀️ 🧗🏾‍♀️ 🧗🏿‍♀️ 🧗‍♂️ 🧗🏻‍♂️ 🧗🏼‍♂️ 🧗🏽‍♂️ 🧗🏾‍♂️ 🧗🏿‍♂️ 🚵‍♀️ 🚵🏻‍♀️ 🚵🏼‍♀️ 🚵🏽‍♀️ 🚵🏾‍♀️ 🚵🏿‍♀️ 🚵‍♂️ 🚵🏻‍♂️ 🚵🏼‍♂️ 🚵🏽‍♂️ 🚵🏾‍♂️ 🚵🏿‍♂️ 🚴‍♀️ 🚴🏻‍♀️ 🚴🏼‍♀️ 🚴🏽‍♀️ 🚴🏾‍♀️ 🚴🏿‍♀️ 🚴‍♂️ 🚴🏻‍♂️ 🚴🏼‍♂️ 🚴🏽‍♂️ 🚴🏾‍♂️ 🚴🏿‍♂️ 🏆 🥇 🥈 🥉 🏅 🎖 🏵 🎗 🎫 🎟 🎪 🤹‍♀️ 🤹🏻‍♀️ 🤹🏼‍♀️ 🤹🏽‍♀️ 🤹🏾‍♀️ 🤹🏿‍♀️ 🤹‍♂️ 🤹🏻‍♂️ 🤹🏼‍♂️ 🤹🏽‍♂️ 🤹🏾‍♂️ 🤹🏿‍♂️ 🎭 🎨 🎬 🎤 🎧 🎼 🎹 🥁 🎷 🎺 🎸 🎻 🎲 🧩 ♟ 🎯 🎳 🎮 🎰 33 | 34 | Travel & Places 35 | 🚗 🚕 🚙 🚌 🚎 🏎 🚓 🚑 🚒 🚐 🚚 🚛 🚜 🛴 🚲 🛵 🏍 🚨 🚔 🚍 🚘 🚖 🚡 🚠 🚟 🚃 🚋 🚞 🚝 🚄 🚅 🚈 🚂 🚆 🚇 🚊 🚉 ✈️ 🛫 🛬 🛩 💺 🛰 🚀 🛸 🚁 🛶 ⛵️ 🚤 🛥 🛳 ⛴ 🚢 ⚓️ ⛽️ 🚧 🚦 🚥 🚏 🗺 🗿 🗽 🗼 🏰 🏯 🏟 🎡 🎢 🎠 ⛲️ ⛱ 🏖 🏝 🏜 🌋 ⛰ 🏔 🗻 🏕 ⛺️ 🏠 🏡 🏘 🏚 🏗 🏭 🏢 🏬 🏣 🏤 🏥 🏦 🏨 🏪 🏫 🏩 💒 🏛 ⛪️ 🕌 🕍 🕋 ⛩ 🛤 🛣 🗾 🎑 🏞 🌅 🌄 🌠 🎇 🎆 🌇 🌆 🏙 🌃 🌌 🌉 🌁 36 | 37 | Objects 38 | 39 | ⌚️ 📱 📲 💻 ⌨️ 🖥 🖨 🖱 🖲 🕹 🗜 💽 💾 💿 📀 📼 📷 📸 📹 🎥 📽 🎞 📞 ☎️ 📟 📠 📺 📻 🎙 🎚 🎛 ⏱ ⏲ ⏰ 🕰 ⌛️ ⏳ 📡 🔋 🔌 💡 🔦 🕯 🗑 🛢 💸 💵 💴 💶 💷 💰 💳 🧾 💎 ⚖️ 🔧 🔨 ⚒ 🛠 ⛏ 🔩 ⚙️ ⛓ 🔫 💣 🔪 🗡 ⚔️ 🛡 🚬 ⚰️ ⚱️ 🏺 🧭 🧱 🔮 🧿 🧸 📿 💈 ⚗️ 🔭 🧰 🧲 🧪 🧫 🧬 🧯 🔬 🕳 💊 💉 🌡 🚽 🚰 🚿 🛁 🛀 🛀🏻 🛀🏼 🛀🏽 🛀🏾 🛀🏿 🧴 🧵 🧶 🧷 🧹 🧺 🧻 🧼 🧽 🛎 🔑 🗝 🚪 🛋 🛏 🛌 🖼 🛍 🧳 🛒 🎁 🎈 🎏 🎀 🎊 🎉 🧨 🎎 🏮 🎐 🧧 ✉️ 📩 📨 📧 💌 📥 📤 📦 🏷 📪 📫 📬 📭 📮 📯 📜 📃 📄 📑 📊 📈 📉 🗒 🗓 📆 📅 📇 🗃 🗳 🗄 📋 📁 📂 🗂 🗞 📰 📓 📔 📒 📕 📗 📘 📙 📚 📖 🔖 🔗 📎 🖇 📐 📏 📌 📍 ✂️ 🖊 🖋 ✒️ 🖌 🖍 📝 ✏️ 🔍 🔎 🔏 🔐 🔒 🔓 40 | 41 | Symbols 42 | ❤️ 🧡 💛 💚 💙 💜 🖤 💔 ❣️ 💕 💞 💓 💗 💖 💘 💝 💟 ☮️ ✝️ ☪️ 🕉 ☸️ ✡️ 🔯 🕎 ☯️ ☦️ 🛐 ⛎ ♈️ ♉️ ♊️ ♋️ ♌️ ♍️ ♎️ ♏️ ♐️ ♑️ ♒️ ♓️ 🆔 ⚛️ 🉑 ☢️ ☣️ 📴 📳 🈶 🈚️ 🈸 🈺 🈷️ ✴️ 🆚 💮 🉐 ㊙️ ㊗️ 🈴 🈵 🈹 🈲 🅰️ 🅱️ 🆎 🆑 🅾️ 🆘 ❌ ⭕️ 🛑 ⛔️ 📛 🚫 💯 💢 ♨️ 🚷 🚯 🚳 🚱 🔞 📵 🚭 ❗️ ❕ ❓ ❔ ‼️ ⁉️ 🔅 🔆 〽️ ⚠️ 🚸 🔱 ⚜️ 🔰 ♻️ ✅ 🈯️ 💹 ❇️ ✳️ ❎ 🌐 💠 Ⓜ️ 🌀 💤 🏧 🚾 ♿️ 🅿️ 🈳 🈂️ 🛂 🛃 🛄 🛅 🚹 🚺 🚼 🚻 🚮 🎦 📶 🈁 🔣 ℹ️ 🔤 🔡 🔠 🆖 🆗 🆙 🆒 🆕 🆓 0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 🔢 #️⃣ *️⃣ ⏏️ ▶️ ⏸ ⏯ ⏹ ⏺ ⏭ ⏮ ⏩ ⏪ ⏫ ⏬ ◀️ 🔼 🔽 ➡️ ⬅️ ⬆️ ⬇️ ↗️ ↘️ ↙️ ↖️ ↕️ ↔️ ↪️ ↩️ ⤴️ ⤵️ 🔀 🔁 🔂 🔄 🔃 🎵 🎶 ➕ ➖ ➗ ✖️ ♾ 💲 💱 ™️ ©️ ®️ 〰️ ➰ ➿ 🔚 🔙 🔛 🔝 🔜 ✔️ ☑️ 🔘 ⚪️ ⚫️ 🔴 🔵 🔺 🔻 🔸 🔹 🔶 🔷 🔳 🔲 ▪️ ▫️ ◾️ ◽️ ◼️ ◻️ ⬛️ ⬜️ 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢 👁‍🗨 💬 💭 🗯 ♠️ ♣️ ♥️ ♦️ 🃏 🎴 🀄️ 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛 🕜 🕝 🕞 🕟 🕠 🕡 🕢 🕣 🕤 🕥 🕦 🕧 43 | 44 | Flags 45 | 46 | 🏳️ 🏴 🏁 🚩 🏳️‍🌈 🏴‍☠️ 🇦🇫 🇦🇽 🇦🇱 🇩🇿 🇦🇸 🇦🇩 🇦🇴 🇦🇮 🇦🇶 🇦🇬 🇦🇷 🇦🇲 🇦🇼 🇦🇺 🇦🇹 🇦🇿 🇧🇸 🇧🇭 🇧🇩 🇧🇧 🇧🇾 🇧🇪 🇧🇿 🇧🇯 🇧🇲 🇧🇹 🇧🇴 🇧🇦 🇧🇼 🇧🇷 🇮🇴 🇻🇬 🇧🇳 🇧🇬 🇧🇫 🇧🇮 🇰🇭 🇨🇲 🇨🇦 🇮🇨 🇨🇻 🇧🇶 🇰🇾 🇨🇫 🇹🇩 🇨🇱 🇨🇳 🇨🇽 🇨🇨 🇨🇴 🇰🇲 🇨🇬 🇨🇩 🇨🇰 🇨🇷 🇨🇮 🇭🇷 🇨🇺 🇨🇼 🇨🇾 🇨🇿 🇩🇰 🇩🇯 🇩🇲 🇩🇴 🇪🇨 🇪🇬 🇸🇻 🇬🇶 🇪🇷 🇪🇪 🇪🇹 🇪🇺 🇫🇰 🇫🇴 🇫🇯 🇫🇮 🇫🇷 🇬🇫 🇵🇫 🇹🇫 🇬🇦 🇬🇲 🇬🇪 🇩🇪 🇬🇭 🇬🇮 🇬🇷 🇬🇱 🇬🇩 🇬🇵 🇬🇺 🇬🇹 🇬🇬 🇬🇳 🇬🇼 🇬🇾 🇭🇹 🇭🇳 🇭🇰 🇭🇺 🇮🇸 🇮🇳 🇮🇩 🇮🇷 🇮🇶 🇮🇪 🇮🇲 🇮🇱 🇮🇹 🇯🇲 🇯🇵 🎌 🇯🇪 🇯🇴 🇰🇿 🇰🇪 🇰🇮 🇽🇰 🇰🇼 🇰🇬 🇱🇦 🇱🇻 🇱🇧 🇱🇸 🇱🇷 🇱🇾 🇱🇮 🇱🇹 🇱🇺 🇲🇴 🇲🇰 🇲🇬 🇲🇼 🇲🇾 🇲🇻 🇲🇱 🇲🇹 🇲🇭 🇲🇶 🇲🇷 🇲🇺 🇾🇹 🇲🇽 🇫🇲 🇲🇩 🇲🇨 🇲🇳 🇲🇪 🇲🇸 🇲🇦 🇲🇿 🇲🇲 🇳🇦 🇳🇷 🇳🇵 🇳🇱 🇳🇨 🇳🇿 🇳🇮 🇳🇪 🇳🇬 🇳🇺 🇳🇫 🇰🇵 🇲🇵 🇳🇴 🇴🇲 🇵🇰 🇵🇼 🇵🇸 🇵🇦 🇵🇬 🇵🇾 🇵🇪 🇵🇭 🇵🇳 🇵🇱 🇵🇹 🇵🇷 🇶🇦 🇷🇪 🇷🇴 🇷🇺 🇷🇼 🇼🇸 🇸🇲 🇸🇦 🇸🇳 🇷🇸 🇸🇨 🇸🇱 🇸🇬 🇸🇽 🇸🇰 🇸🇮 🇬🇸 🇸🇧 🇸🇴 🇿🇦 🇰🇷 🇸🇸 🇪🇸 🇱🇰 🇧🇱 🇸🇭 🇰🇳 🇱🇨 🇵🇲 🇻🇨 🇸🇩 🇸🇷 🇸🇿 🇸🇪 🇨🇭 🇸🇾 🇹🇼 🇹🇯 🇹🇿 🇹🇭 🇹🇱 🇹🇬 🇹🇰 🇹🇴 🇹🇹 🇹🇳 🇹🇷 🇹🇲 🇹🇨 🇹🇻 🇻🇮 🇺🇬 🇺🇦 🇦🇪 🇬🇧 🏴󠁧󠁢󠁥󠁮󠁧󠁿 🏴󠁧󠁢󠁳󠁣󠁴󠁿 🏴󠁧󠁢󠁷󠁬󠁳󠁿 🇺🇳 🇺🇸 🇺🇾 🇺🇿 🇻🇺 🇻🇦 🇻🇪 🇻🇳 🇼🇫 🇪🇭 🇾🇪 🇿🇲 🇿🇼 47 | 48 | New Emojis 49 | 50 | 🥰 🥵 🥶 🥳 🥴 🥺 👨‍🦰 👩‍🦰 👨‍🦱 👩‍🦱 👨‍🦲 👩‍🦲 👨‍🦳 👩‍🦳 🦸 🦸‍♀️ 🦸‍♂️ 🦹 🦹‍♀️ 🦹‍♂️ 🦵 🦶 🦴 🦷 🥽 🥼 🥾 🥿 🦝 🦙 🦛 🦘 🦡 🦢 🦚 🦜 🦞 🦟 🦠 🥭 🥬 🥯 🧂 🥮 🧁 🧭 🧱 🛹 🧳 🧨 🧧 🥎 🥏 🥍 🧿 🧩 🧸 ♟ 🧮 🧾 🧰 🧲 🧪 🧫 🧬 🧯 🧴 🧵 🧶 🧷 🧹 🧺 🧻 🧼 🧽 ♾ 🏴‍☠️ -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .archive/ 2 | tags 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 luetage 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vivaldi Forum mod 2 | 3 | ![vfm](/icons/icon48.png) 4 | 5 | Open source extension. Dedicated to improving your experience browsing Vivaldi Forum. 6 | 7 | [Available on chrome web store](https://chrome.google.com/webstore/detail/vivaldi-forum-mod/hipnollokpifchndpfhnlfjbdnkhiigg?hl=en-US). 8 | 9 | ## Features 10 | 11 | * Theme machine 12 | * Scheduled theming 13 | * User CSS 14 | * Modifications 15 | * Fixes 16 | * Enhanced functionality 17 | 18 | For a detailed rundown and explanation of features, please see the [support site on Vivaldi Forum](https://forum.vivaldi.net/topic/19728/vivaldi-forum-mod). 19 | 20 | ## Contribute 21 | 22 | Vivaldi Forum mod is a community project driven by the ideas and needs of its users. Without users, there's no reason for development. Thus the most straightforward way to help out is installing and using the extension, providing feedback and spotlighting issues. 23 | 24 | ### Themes 25 | 26 | Have you created a beautiful theme with help of the Theme Machine? Great! Please share it by using the **Export** button on the options page, which will copy the theme code to your clipboard. Afterwards simply paste the theme code in a reply to the [feedback topic](https://forum.vivaldi.net/topic/19728/vivaldi-forum-mod) on Vivaldi Forum. Did you introduce additional changes with User CSS? – Copy the code and paste it alongside your theme. 27 | 28 | Create your own theme: 29 | 30 | * Download or clone the repository. 31 | * On Vivaldi's extensions page enable developer mode, click **Load unpacked** and select the Vivaldi Forum mod directory. 32 | * Select **Standard** theme in options, open `standard.css` (located in `vivaldi_forum_mod/themes`) in a text editor and start designing your new theme. 33 | 34 | ### Translations 35 | 36 | Vivaldi Forum mod 2.0 introduces translations. Following languages are currently being worked on: 37 | 38 | * Czech 39 | * French 40 | * German 41 | * Italian 42 | * Japanese 43 | * Russian 44 | * Spanish 45 | * Vietnamese 46 | 47 | You can help out by improving these translations, or by introducing a new translation. Here's a quick **how to**: 48 | 49 | * Please make sure the language you want to translate to is [supported](https://developer.chrome.com/webstore/i18n?csw=1#localeTable). 50 | * Clone or download the [repository](https://github.com/luetage/vivaldi_forum_mod/). 51 | * On Vivaldi's extensions page enable developer mode, click **Load unpacked** and select the Vivaldi Forum mod directory. 52 | * In Vivaldi browser settings, go to **Startup** and select your desired target language. Restart the browser. 53 | * In Vivaldi Forum settings pick your target language, hit **Save** and reload the tab. 54 | * Create a new directory in `vivaldi_forum_mod/_locales` and rename it (locale code). 55 | * Make a copy of the English translation file (`vivaldi_forum_mod/_locales/en/messages.json`) and paste it into your newly created translation directory. 56 | * Open the `messages.json` file in a text editor and start translating. 57 | 58 | Each entry in the file has a **message** and a **description** part. Only translate the message to your target language, leave everything else untouched. Descriptions which start with the word **Options** are translations for Vivaldi Forum mod's options page, anything else appears on Vivaldi Forum directly. Make sure to check out existing translations on Vivaldi Forum and to enable the different modifications to see your translations in action. If you should have any question about this procedure, or if you need help of any kind, please write a post in the feedback topic or send a [message](https://forum.vivaldi.net/user/luetage). Each translation should at least be checked by one other contributor to assure its accuracy. Finished translations will be released as soon as you submit them. Either make a pull request on Github directly, or submit the `messages.json` file by pasting its contents online (e.g. [pastebin](https://pastebin.com/)) and sharing the link. 59 | -------------------------------------------------------------------------------- /_locales/cs/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "bookmarks": { 3 | "message": "Záložky", 4 | "description": "Link to bookmarks page from navigation bar" 5 | }, 6 | "signature": { 7 | "message": "Podpis", 8 | "description": "Signature toggle for forum posts" 9 | }, 10 | "copyCode": { 11 | "message": "kopírovat kód", 12 | "description": "Copy all code button for code markdown" 13 | }, 14 | "lastModified": { 15 | "message": "Naposled upraveno", 16 | "description": "Text before last edit timestamp in forum posts" 17 | }, 18 | "optionsLink": { 19 | "message": "Nastavení rozšíření", 20 | "description": "Link to options page in user dropdown menu. Probably no translation needed? Decide depending on language" 21 | }, 22 | "dismiss": { 23 | "message": "Zavřít", 24 | "description": "Dismisses community notifications" 25 | }, 26 | "emoticons": { 27 | "message": "Další emoji", 28 | "description": "Title of formatting item for emote picker" 29 | }, 30 | "header": { 31 | "message": "Nadpis", 32 | "description": "Title of formatting item header 1" 33 | }, 34 | "horizontal_line": { 35 | "message": "Vodorovná čára", 36 | "description": "Title of formatting item horizontal rule" 37 | }, 38 | "block_quote": { 39 | "message": "Citace", 40 | "description": "Title of formatting item quote" 41 | }, 42 | "inline_code": { 43 | "message": "Zdrojový kód (na stejném řádku)", 44 | "description": "Title of formatting item fixed width font" 45 | }, 46 | "table": { 47 | "message": "Tabulka", 48 | "description": "Title of formatting item table" 49 | }, 50 | "number_list": { 51 | "message": "Číslovaný seznam", 52 | "description": "Title of formatting item numbered list" 53 | }, 54 | "spoiler": { 55 | "message": "Skrytý text", 56 | "description": "Title of formatting item spoiler" 57 | }, 58 | "customToolbarTitle": { 59 | "message": "Upravit tlačítka", 60 | "description": "Title of custom toolbar editor" 61 | }, 62 | "dragText": { 63 | "message": "Pro přesunutí této nabídky klepněte na její záhlaví a přetáhněte ji", 64 | "description": "Hover text when on a draggable area" 65 | }, 66 | "themes": { 67 | "message": "Motivy", 68 | "description": "Options: Title of themes section" 69 | }, 70 | "modifications": { 71 | "message": "Úpravy", 72 | "description": "Options: Title of modifications section" 73 | }, 74 | "info": { 75 | "message": "Info", 76 | "description": "Options: Title of info section" 77 | }, 78 | "feedback": { 79 | "message": "Zpětná vazba", 80 | "description": "Options: Feedback link in navigation" 81 | }, 82 | "schedule": { 83 | "message": "Plánované změny motivu", 84 | "description": "Options: Schedule headline" 85 | }, 86 | "themeMachine": { 87 | "message": "Motivy", 88 | "description": "Options: Theme machine headline" 89 | }, 90 | "background": { 91 | "message": "Pozadí", 92 | "description": "Options: Theme machine edit background" 93 | }, 94 | "foreground": { 95 | "message": "Písmo", 96 | "description": "Options: Theme machine edit foreground" 97 | }, 98 | "highlight": { 99 | "message": "Zvýraznění", 100 | "description": "Options: Theme machine edit highlight" 101 | }, 102 | "accent": { 103 | "message": "Důraz", 104 | "description": "Options: Theme machine edit accent" 105 | }, 106 | "link": { 107 | "message": "Odkaz", 108 | "description": "Options: Theme machine edit link" 109 | }, 110 | "code": { 111 | "message": "Kód", 112 | "description": "Options: Theme machine edit code" 113 | }, 114 | "dropdown": { 115 | "message": "Rozbalovací nabídka", 116 | "description": "Options: Theme machine edit dropdown" 117 | }, 118 | "selectModifications": { 119 | "message": "Vyberte úpravy", 120 | "description": "Options: Modifications headline" 121 | }, 122 | "advancedFormatting": { 123 | "message": "Rozšířené formátování", 124 | "description": "Options: Title of advanced formatting mod" 125 | }, 126 | "advancedFormattingDesc": { 127 | "message": "Přidá další emoji a formátovací tlačítka. Umožňuje přetáhnout, odstranit či přidat formátovací tlačítka pro psaní příspěvků na fóru.", 128 | "description": "Options: Description of the advanced formatting mod" 129 | }, 130 | "hideHeader": { 131 | "message": "Automaticky schovávat hlavičku", 132 | "description": "Options: Title of auto-hide header on scroll mod" 133 | }, 134 | "hideHeaderDesc": { 135 | "message": "Při posunutí stránku dolů schová hlavičku. Při posunutí stránky nahoru ukáže hlavičku.", 136 | "description": "Options: Description of auto-hide header on scroll mod" 137 | }, 138 | "navbookmarks": { 139 | "message": "Záložky v navigaci", 140 | "description": "Options: Title of bookmarks in navigation mod" 141 | }, 142 | "navbookmarksDesc": { 143 | "message": "Pro zrychlení přístupu zobrazí v navigaci odkaz na vaše záložky ve fóru.", 144 | "description": "Options: Description of bookmarks in navigation mod" 145 | }, 146 | "compactPosts": { 147 | "message": "Kompaktní příspěvky", 148 | "description": "Options: Title of compact posts mod" 149 | }, 150 | "compactPostsDesc": { 151 | "message": "Odstraní mezeru mezi jménem autora a textem. Může způsobit špatné rozmístění některých prvků na stránce.", 152 | "description": "Options: Description of compact posts mod" 153 | }, 154 | "customNotification": { 155 | "message": "Ikony upozornění", 156 | "description": "Options: Title of custom notification icons mod" 157 | }, 158 | "customNotificationDesc": { 159 | "message": "Pro lepší rozeznání přidá k upozorněním ikony.", 160 | "description": "Options: Description of custom notification icons mod" 161 | }, 162 | "showUID": { 163 | "message": "Zobrazit ID uživatelů", 164 | "description": "Options: Title of show user IDs mod" 165 | }, 166 | "showUIDDesc": { 167 | "message": "Když myší najedete na jméno uživatele na začátku příspěvku či profilu, zobrazí jeho ID.", 168 | "description": "Options: Description of show user IDs mod" 169 | }, 170 | "systemEmoji": { 171 | "message": "Systémová emoji", 172 | "description": "Options: Title of use system emoji mod" 173 | }, 174 | "systemEmojiDesc": { 175 | "message": "Nahradí emoji tak, aby používala systémový font.", 176 | "description": "Options: Description of use system emoji mod" 177 | }, 178 | "signatureMod": { 179 | "message": "Schovat podpisy", 180 | "description": "Options: Title of signature mod" 181 | }, 182 | "signatureModDesc": { 183 | "message": "Schová všechny podpisy. Zobrazit je můžete tlačítkem na jejich původním místě.", 184 | "description": "Options: Description of signature mod" 185 | }, 186 | "squareAvatars": { 187 | "message": "Čtvercové profilové fotky", 188 | "description": "Options: Title of square avatars mod" 189 | }, 190 | "squareAvatarsDesc": { 191 | "message": "Čtvercové profilové fotky!", 192 | "description": "Options: Description of square avatars mod" 193 | }, 194 | "userCSS": { 195 | "message": "Uživatelské CSS", 196 | "description": "Options: User CSS headline" 197 | }, 198 | "userCSSDesc": { 199 | "message": "Vkládejte pouze CSS kód! Přepínačem jej povolte či zakažte. Po provedení změn klikněte na ULOŽIT. Pokud chcete používat vlastní motiv vzhledu, doporučujeme v nastavení motivů vybrat Standard.", 200 | "description": "Options: User CSS placeholder/description" 201 | }, 202 | "changelog": { 203 | "message": "Historie změn", 204 | "description": "Options: Changelog headline" 205 | }, 206 | "credits": { 207 | "message": "Poděkování", 208 | "description": "Options: Credits headline" 209 | }, 210 | "save": { 211 | "message": "Uložit", 212 | "description": "Options: Text to show on a button that performs some sort of save operation" 213 | }, 214 | "edit": { 215 | "message": "Upravit", 216 | "description": "Options: Text to show on a button that performs some sort of edit operation" 217 | }, 218 | "backup": { 219 | "message": "Zálohovat", 220 | "description": "Options: Text to show on a button that performs some sort of backup operation" 221 | }, 222 | "import": { 223 | "message": "Vložit kód", 224 | "description": "Options: Text to show on a button that performs some sort of import operation" 225 | }, 226 | "cancel": { 227 | "message": "Zrušit", 228 | "description": "Options: Text to show on a button that performs some sort of cancel operation" 229 | }, 230 | "export": { 231 | "message": "Kopírovat kód", 232 | "description": "Options: Text to show on a button that performs some sort of export operation." 233 | }, 234 | "reset": { 235 | "message": "Vymazat nastavení", 236 | "description": "Options: Text to show on a button that performs some sort of reset operation" 237 | }, 238 | "confirmReset": { 239 | "message": "Vymazat nastavení rozšíření? Pro potvrzení klikněte ještě jednou", 240 | "description": "Options: Status message to confirm reset" 241 | }, 242 | "cancelReset": { 243 | "message": "Nastavení nebude vymazáno", 244 | "description": "Options: Status message after cancelled reset" 245 | }, 246 | "cancelImport": { 247 | "message": "Import zrušen", 248 | "description": "Options: Status message after cancelled import" 249 | }, 250 | "optionsReset": { 251 | "message": "Nastavení a paměť vymazány", 252 | "description": "Options: Status message after reset" 253 | }, 254 | "activateSchedule": { 255 | "message": "Plánovaná změna spuštěna", 256 | "description": "Options: Status message for Schedule activation" 257 | }, 258 | "deactivateSchedule": { 259 | "message": "Plánovaná změna zrušena", 260 | "description": "Options: Status message for Schedule deactivation" 261 | }, 262 | "activateUserCSS": { 263 | "message": "Uživatelské CSS povoleno", 264 | "description": "Options: Status message for User CSS activation" 265 | }, 266 | "deactivateUserCSS": { 267 | "message": "Uživatelské CSS zakázáno", 268 | "description": "Options: Status message for User CSS deactivation" 269 | }, 270 | "saveUserCSS": { 271 | "message": "Uživatelské CSS uloženo do paměti", 272 | "description": "Options: Status message for saving User CSS to storage" 273 | }, 274 | "saveTheme": { 275 | "message": "Barevný motiv uložen a použit", 276 | "description": "Options: Status message for theme activation" 277 | }, 278 | "exportTheme": { 279 | "message": "Kód motivu zkopírován do schránky", 280 | "description": "Options: Status message for exporting theme" 281 | }, 282 | "importThemeDesc": { 283 | "message": "Vložte nebo přetáhněte kód motivu do pole pro import", 284 | "description": "Options: Status message describing theme import" 285 | }, 286 | "importTheme": { 287 | "message": "Motiv importován. Nezapomeňte jej uložit", 288 | "description": "Options: Status message confirming theme import" 289 | }, 290 | "statusThemes": { 291 | "message": "Vyberte či vytvořte barevné motivy a naplánujte jejich změny", 292 | "description": "Options: Status message themes" 293 | }, 294 | "statusModifications": { 295 | "message": "Pro zobrazení popisu najeďte myší na název úpravy", 296 | "description": "Options: Status message modifications" 297 | }, 298 | "statusInfo": { 299 | "message": "Vřelé díky všem přispěvatelům a uživatelům!", 300 | "description": "Options: Status message info" 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /_locales/de/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "bookmarks": { 3 | "message": "Lesezeichen", 4 | "description": "Link to bookmarks page from navigation bar" 5 | }, 6 | "signature": { 7 | "message": "Signatur", 8 | "description": "Signature toggle for forum posts" 9 | }, 10 | "copyCode": { 11 | "message": "Code kopieren", 12 | "description": "Copy all code button for code markdown" 13 | }, 14 | "lastModified": { 15 | "message": "Zuletzt geändert", 16 | "description": "Text before last edit timestamp in forum posts" 17 | }, 18 | "optionsLink": { 19 | "message": "Forum mod", 20 | "description": "Link to options page in user dropdown menu. Probably no translation needed? Decide depending on language" 21 | }, 22 | "dismiss": { 23 | "message": "Ausblenden", 24 | "description": "Dismisses community notifications" 25 | }, 26 | "emoticons": { 27 | "message": "Emojis", 28 | "description": "Title of formatting item for emote picker" 29 | }, 30 | "header": { 31 | "message": "Überschrift", 32 | "description": "Title of formatting item header 1" 33 | }, 34 | "horizontal_line": { 35 | "message": "Horizontale Linie", 36 | "description": "Title of formatting item horizontal rule" 37 | }, 38 | "block_quote": { 39 | "message": "Zitat", 40 | "description": "Title of formatting item quote" 41 | }, 42 | "inline_code": { 43 | "message": "Inline-Code", 44 | "description": "Title of formatting item inline code" 45 | }, 46 | "table": { 47 | "message": "Tabelle", 48 | "description": "Title of formatting item table" 49 | }, 50 | "number_list": { 51 | "message": "Numerierte Liste", 52 | "description": "Title of formatting item numbered list" 53 | }, 54 | "spoiler": { 55 | "message": "Spoiler", 56 | "description": "Title of formatting item spoiler" 57 | }, 58 | "customToolbarTitle": { 59 | "message": "Werkzeugleiste ändern", 60 | "description": "Title of custom toolbar editor" 61 | }, 62 | "dragText": { 63 | "message": "Klicken und ziehen um zu verschieben", 64 | "description": "Hover text when on a draggable area" 65 | }, 66 | "themes": { 67 | "message": "Themen", 68 | "description": "Options: Title of themes section" 69 | }, 70 | "modifications": { 71 | "message": "Modifikationen", 72 | "description": "Options: Title of modifications section" 73 | }, 74 | "info": { 75 | "message": "Info", 76 | "description": "Options: Title of info section" 77 | }, 78 | "feedback": { 79 | "message": "Feedback", 80 | "description": "Options: Feedback link in navigation" 81 | }, 82 | "schedule": { 83 | "message": "Zeitplan", 84 | "description": "Options: Schedule headline" 85 | }, 86 | "themeMachine": { 87 | "message": "Themen Maschine", 88 | "description": "Options: Theme machine headline" 89 | }, 90 | "background": { 91 | "message": "Hintergrund", 92 | "description": "Options: Theme machine edit background" 93 | }, 94 | "foreground": { 95 | "message": "Vordergrund", 96 | "description": "Options: Theme machine edit foreground" 97 | }, 98 | "highlight": { 99 | "message": "Hervorhebungen", 100 | "description": "Options: Theme machine edit highlight" 101 | }, 102 | "accent": { 103 | "message": "Akzent", 104 | "description": "Options: Theme machine edit accent" 105 | }, 106 | "link": { 107 | "message": "Link", 108 | "description": "Options: Theme machine edit link" 109 | }, 110 | "code": { 111 | "message": "Code", 112 | "description": "Options: Theme machine edit code" 113 | }, 114 | "dropdown": { 115 | "message": "Dropdown", 116 | "description": "Options: Theme machine edit dropdown" 117 | }, 118 | "selectModifications": { 119 | "message": "Modifikationen Auswählen", 120 | "description": "Options: Modifications headline" 121 | }, 122 | "advancedFormatting": { 123 | "message": "Erweitertes Formatieren", 124 | "description": "Options: Title of advanced formatting mod" 125 | }, 126 | "advancedFormattingDesc": { 127 | "message": "Fügt Emojis und weitere Werkzeuge für die Bearbeitung von Beiträgen hinzu. Ermöglicht es Werkzeuge zu entfernen/hinzuzufügen und zu sortieren.", 128 | "description": "Options: Description of advanced formatting mod" 129 | }, 130 | "hideHeader": { 131 | "message": "Ausblenden des Headers beim Scrollen", 132 | "description": "Options: Title of auto-hide header on scroll mod" 133 | }, 134 | "hideHeaderDesc": { 135 | "message": "Nach unten scrollen verbirgt den Header, nach oben scrollen zeigt ihn wieder an.", 136 | "description": "Options: Description of auto-hide header on scroll mod" 137 | }, 138 | "navbookmarks": { 139 | "message": "Lesezeichen in Navigation", 140 | "description": "Options: Title of bookmarks in navigation mod" 141 | }, 142 | "navbookmarksDesc": { 143 | "message": "Zeigt einen Link zu den Lesezeichen in der Navigationsleiste an.", 144 | "description": "Options: Description of bookmarks in navigation mod" 145 | }, 146 | "compactPosts": { 147 | "message": "Kompakte Beiträge", 148 | "description": "Options: Title of compact posts mod" 149 | }, 150 | "compactPostsDesc": { 151 | "message": "Entfernt Abstand zwischen Nutzernamen und Inhalt eines Beitrags. Kann Fehler im Layout verursachen. w", 152 | "description": "Options: Description of compact posts mod" 153 | }, 154 | "customNotification": { 155 | "message": "Symbole für Benachrichtigungen", 156 | "description": "Options: Title of custom notification icons mod" 157 | }, 158 | "customNotificationDesc": { 159 | "message": "Zeigt Symbole in der Dropdown-Liste des Headers an, um Benachrichtigungen besser voneinander zu unterscheiden.", 160 | "description": "Options: Description of custom notification icons mod" 161 | }, 162 | "showUID": { 163 | "message": "User ID anzeigen", 164 | "description": "Options: Title of show user IDs mod" 165 | }, 166 | "showUIDDesc": { 167 | "message": "Zeigt UIDs an, wenn man den Mauszeiger über dem Nutzernamen eines Beitrags, oder über dem Nutzerbild auf einem Profil, positioniert.", 168 | "description": "Options: Description of show user IDs mod" 169 | }, 170 | "systemEmoji": { 171 | "message": "Systemeigene Emoji", 172 | "description": "Options: Title of use system emoji mod" 173 | }, 174 | "systemEmojiDesc": { 175 | "message": "Verwende Betriebssystem Emoji anstelle von Vivaldi Forum Emoji.", 176 | "description": "Options: Description of use system emoji mod" 177 | }, 178 | "signatureMod": { 179 | "message": "Signatur Mod", 180 | "description": "Options: Title of signature mod" 181 | }, 182 | "signatureModDesc": { 183 | "message": "Verbirgt alle Signaturen und zeigt anstelle jeder einen Schalter an. Das Betätigen des Schalters (Signatur) zeigt die individuelle Signatur wieder an.", 184 | "description": "Options: Description of signature mod" 185 | }, 186 | "squareAvatars": { 187 | "message": "Quadratische Nutzerbilder", 188 | "description": "Options: Title of square avatars mod" 189 | }, 190 | "squareAvatarsDesc": { 191 | "message": "Quadratische anstatt runde Nutzerbilder.", 192 | "description": "Options: Description of square avatars mod" 193 | }, 194 | "userCSS": { 195 | "message": "User CSS", 196 | "description": "Options: User CSS headline" 197 | }, 198 | "userCSSDesc": { 199 | "message": "Nur CSS Code eingeben! Aktivieren/deaktivieren mit Toggle. SPEICHERN um zu speichern. Wähle Standard in Themen um ein selbstständiges Thema zu laden.", 200 | "description": "Options: User CSS placeholder/description" 201 | }, 202 | "changelog": { 203 | "message": "Changelog", 204 | "description": "Options: Changelog headline" 205 | }, 206 | "credits": { 207 | "message": "Credits", 208 | "description": "Options: Credits headline" 209 | }, 210 | "save": { 211 | "message": "Speichern", 212 | "description": "Options: Text to show on a button that performs some sort of save operation" 213 | }, 214 | "edit": { 215 | "message": "Ändern", 216 | "description": "Options: Text to show on a button that performs some sort of edit operation" 217 | }, 218 | "import": { 219 | "message": "Importieren", 220 | "description": "Options: Text to show on a button that performs some sort of import operation" 221 | }, 222 | "cancel": { 223 | "message": "Abbrechen", 224 | "description": "Options: Text to show on a button that performs some sort of cancel operation" 225 | }, 226 | "export": { 227 | "message": "Exportieren", 228 | "description": "Options: Text to show on a button that performs some sort of export operation" 229 | }, 230 | "reset": { 231 | "message": "Zurücksetzen", 232 | "description": "Options: Text to show on a button that performs some sort of reset operation" 233 | }, 234 | "confirmReset": { 235 | "message": "Erweiterung zurücksetzen? Klicke erneut um zu bestätigen", 236 | "description": "Options: Status message to confirm reset" 237 | }, 238 | "cancelReset": { 239 | "message": "Vorgang abgebrochen", 240 | "description": "Options: Status message when reset is cancelled" 241 | }, 242 | "cancelImport": { 243 | "message": "Vorgang abgebrochen", 244 | "description": "Options: Status message after cancelled import" 245 | }, 246 | "optionsReset": { 247 | "message": "Einstellungen zurückgesetzt, Speicher bereinigt", 248 | "description": "Options: Status message after reset" 249 | }, 250 | "activateSchedule": { 251 | "message": "Zeitplan aktiviert", 252 | "description": "Options: Status message for Schedule activation" 253 | }, 254 | "deactivateSchedule": { 255 | "message": "Zeitplan deaktiviert", 256 | "description": "Options: Status message for Schedule deactivation" 257 | }, 258 | "activateUserCSS": { 259 | "message": "User CSS aktiviert", 260 | "description": "Options: Status message for User CSS activation" 261 | }, 262 | "deactivateUserCSS": { 263 | "message": "User CSS deaktiviert", 264 | "description": "Options: Status message for User CSS deactivation" 265 | }, 266 | "saveUserCSS": { 267 | "message": "User CSS gespeichert", 268 | "description": "Options: Status message for saving User CSS to storage" 269 | }, 270 | "saveTheme": { 271 | "message": "Thema gespeichert und aktiviert", 272 | "description": "Options: Status message for theme activation" 273 | }, 274 | "exportTheme": { 275 | "message": "Thema in die Zwischenablage kopiert", 276 | "description": "Options: Status message for theme sharing" 277 | }, 278 | "importTheme": { 279 | "message": "Thema importiert. Klicke SPEICHERN um das Thema zu speichern", 280 | "description": "Options: Status message for theme import" 281 | }, 282 | "importThemeDesc": { 283 | "message": "Themencode einfügen oder per Drag&Drop in das Importfeld ziehen", 284 | "description": "Options: Status message describing theme import" 285 | }, 286 | "statusThemes": { 287 | "message": "Wähle ein Thema aus, oder gestalte ein Neues und erstelle einen Zeitplan", 288 | "description": "Options: Status message themes" 289 | }, 290 | "statusModifications": { 291 | "message": "Wähle Modifikationen aus und schreib benutzerdefiniertes CSS", 292 | "description": "Options: Status message modifications" 293 | }, 294 | "statusInfo": { 295 | "message": "Ein Dankeschön an alle Benutzer und Mitwirkende!", 296 | "description": "Options: Status message info" 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "bookmarks": { 3 | "message": "Bookmarks", 4 | "description": "Link to bookmarks page from navigation bar" 5 | }, 6 | "signature": { 7 | "message": "Signature", 8 | "description": "Signature toggle for forum posts" 9 | }, 10 | "copyCode": { 11 | "message": "copy code", 12 | "description": "Copy all code button for code markdown" 13 | }, 14 | "lastModified": { 15 | "message": "Last modified", 16 | "description": "Text before last edit timestamp in forum posts" 17 | }, 18 | "optionsLink": { 19 | "message": "Forum mod", 20 | "description": "Link to options page in user dropdown menu. Probably no translation needed? Decide depending on language" 21 | }, 22 | "dismiss": { 23 | "message": "Dismiss", 24 | "description": "Dismisses community notifications" 25 | }, 26 | "emoticons": { 27 | "message": "Emote Picker", 28 | "description": "Title of formatting item for emote picker" 29 | }, 30 | "header": { 31 | "message": "Header", 32 | "description": "Title of formatting item header 1" 33 | }, 34 | "horizontal_line": { 35 | "message": "Horizontal Rule", 36 | "description": "Title of formatting item horizontal rule" 37 | }, 38 | "block_quote": { 39 | "message": "Quote", 40 | "description": "Title of formatting item quote" 41 | }, 42 | "inline_code": { 43 | "message": "Inline Code", 44 | "description": "Title of formatting item fixed width font" 45 | }, 46 | "table": { 47 | "message": "Table", 48 | "description": "Title of formatting item table" 49 | }, 50 | "number_list": { 51 | "message": "Numbered List", 52 | "description": "Title of formatting item numbered list" 53 | }, 54 | "spoiler": { 55 | "message": "Spoiler", 56 | "description": "Title of formatting item spoiler" 57 | }, 58 | "customToolbarTitle": { 59 | "message": "Edit Custom Toolbar", 60 | "description": "Title of custom toolbar editor" 61 | }, 62 | "dragText": { 63 | "message": "Click and drag to move", 64 | "description": "Hover text when on a draggable area" 65 | }, 66 | "themes": { 67 | "message": "Themes", 68 | "description": "Options: Title of themes section" 69 | }, 70 | "modifications": { 71 | "message": "Modifications", 72 | "description": "Options: Title of modifications section" 73 | }, 74 | "info": { 75 | "message": "Info", 76 | "description": "Options: Title of info section" 77 | }, 78 | "feedback": { 79 | "message": "Feedback", 80 | "description": "Options: Feedback link in navigation" 81 | }, 82 | "schedule": { 83 | "message": "Schedule", 84 | "description": "Options: Schedule headline" 85 | }, 86 | "themeMachine": { 87 | "message": "Theme Machine", 88 | "description": "Options: Theme machine headline" 89 | }, 90 | "background": { 91 | "message": "Background", 92 | "description": "Options: Theme machine edit background" 93 | }, 94 | "foreground": { 95 | "message": "Foreground", 96 | "description": "Options: Theme machine edit foreground" 97 | }, 98 | "highlight": { 99 | "message": "Highlight", 100 | "description": "Options: Theme machine edit highlight" 101 | }, 102 | "accent": { 103 | "message": "Accent", 104 | "description": "Options: Theme machine edit accent" 105 | }, 106 | "link": { 107 | "message": "Link", 108 | "description": "Options: Theme machine edit link" 109 | }, 110 | "code": { 111 | "message": "Code", 112 | "description": "Options: Theme machine edit code" 113 | }, 114 | "dropdown": { 115 | "message": "Dropdown", 116 | "description": "Options: Theme machine edit dropdown" 117 | }, 118 | "selectModifications": { 119 | "message": "Select Modifications", 120 | "description": "Options: Modifications headline" 121 | }, 122 | "advancedFormatting": { 123 | "message": "Advanced Formatting", 124 | "description": "Options: Title of advanced formatting mod" 125 | }, 126 | "advancedFormattingDesc": { 127 | "message": "Adds an emote picker and extra formatting buttons. Allows you to drag to reorder, remove from and add to the formatting toolbar when editing your forum posts.", 128 | "description": "Options: Description of the advanced formatting mod" 129 | }, 130 | "hideHeader": { 131 | "message": "Auto-Hide Header on Scroll", 132 | "description": "Options: Title of auto-hide header on scroll mod" 133 | }, 134 | "hideHeaderDesc": { 135 | "message": "Hides the header when you scroll down, shows it when you scroll up.", 136 | "description": "Options: Description of auto-hide header on scroll mod" 137 | }, 138 | "navbookmarks": { 139 | "message": "Bookmarks in Navigation", 140 | "description": "Options: Title of bookmarks in navigation mod" 141 | }, 142 | "navbookmarksDesc": { 143 | "message": "Displays a link to the bookmarks page in the main navigation for easy access.", 144 | "description": "Options: Description of bookmarks in navigation mod" 145 | }, 146 | "compactPosts": { 147 | "message": "Compact Posts", 148 | "description": "Options: Title of compact posts mod" 149 | }, 150 | "compactPostsDesc": { 151 | "message": "Removes margin between user name and content. May break layout.", 152 | "description": "Options: Description of compact posts mod" 153 | }, 154 | "customNotification": { 155 | "message": "Custom Notification Icons", 156 | "description": "Options: Title of custom notification icons mod" 157 | }, 158 | "customNotificationDesc": { 159 | "message": "Displays font icons in the header's notification dropdown to quickly distinguish one type of notification from another.", 160 | "description": "Options: Description of custom notification icons mod" 161 | }, 162 | "showUID": { 163 | "message": "Show User IDs", 164 | "description": "Options: Title of show user IDs mod" 165 | }, 166 | "showUIDDesc": { 167 | "message": "Shows UIDs when hovering the username at top of a post and when hovering a user's avatar on their profile.", 168 | "description": "Options: Description of show user IDs mod" 169 | }, 170 | "systemEmoji": { 171 | "message": "Use System Emoji", 172 | "description": "Options: Title of use system emoji mod" 173 | }, 174 | "systemEmojiDesc": { 175 | "message": "Use emoji font provided by the operating system instead of Vivaldi Forum emoji.", 176 | "description": "Options: Description of use system emoji mod" 177 | }, 178 | "signatureMod": { 179 | "message": "Signature Mod", 180 | "description": "Options: Title of signature mod" 181 | }, 182 | "signatureModDesc": { 183 | "message": "Hides all signatures and replaces each with a button. When clicked, the signatures of individual posts will be displayed.", 184 | "description": "Options: Description of signature mod" 185 | }, 186 | "squareAvatars": { 187 | "message": "Square Avatars", 188 | "description": "Options: Title of square avatars mod" 189 | }, 190 | "squareAvatarsDesc": { 191 | "message": "Square avatars everywhere!", 192 | "description": "Options: Description of square avatars mod" 193 | }, 194 | "userCSS": { 195 | "message": "User CSS", 196 | "description": "Options: User CSS headline" 197 | }, 198 | "userCSSDesc": { 199 | "message": "Input CSS code only! Click the toggle to activate/deactivate. SAVE to save to storage. Select Standard in Themes, if you want to run your own theme.", 200 | "description": "Options: User CSS placeholder/description" 201 | }, 202 | "changelog": { 203 | "message": "Changelog", 204 | "description": "Options: Changelog headline" 205 | }, 206 | "credits": { 207 | "message": "Credits", 208 | "description": "Options: Credits headline" 209 | }, 210 | "save": { 211 | "message": "Save", 212 | "description": "Options: Text to show on a button that performs some sort of save operation" 213 | }, 214 | "edit": { 215 | "message": "Edit", 216 | "description": "Options: Text to show on a button that performs some sort of edit operation" 217 | }, 218 | "import": { 219 | "message": "Import", 220 | "description": "Options: Text to show on a button that performs some sort of import operation" 221 | }, 222 | "cancel": { 223 | "message": "Cancel", 224 | "description": "Options: Text to show on a button that performs some sort of cancel operation" 225 | }, 226 | "export": { 227 | "message": "Export", 228 | "description": "Options: Text to show on a button that performs some sort of export operation." 229 | }, 230 | "reset": { 231 | "message": "Reset", 232 | "description": "Options: Text to show on a button that performs some sort of reset operation" 233 | }, 234 | "confirmReset": { 235 | "message": "Reset the extension? Click again to confirm", 236 | "description": "Options: Status message to confirm reset" 237 | }, 238 | "cancelReset": { 239 | "message": "Reset cancelled", 240 | "description": "Options: Status message after cancelled reset" 241 | }, 242 | "cancelImport": { 243 | "message": "Import cancelled", 244 | "description": "Options: Status message after cancelled import" 245 | }, 246 | "optionsReset": { 247 | "message": "Options reset, storage cleared", 248 | "description": "Options: Status message after reset" 249 | }, 250 | "activateSchedule": { 251 | "message": "Schedule activated", 252 | "description": "Options: Status message for Schedule activation" 253 | }, 254 | "deactivateSchedule": { 255 | "message": "Schedule deactivated", 256 | "description": "Options: Status message for Schedule deactivation" 257 | }, 258 | "activateUserCSS": { 259 | "message": "User CSS activated", 260 | "description": "Options: Status message for User CSS activation" 261 | }, 262 | "deactivateUserCSS": { 263 | "message": "User CSS deactivated", 264 | "description": "Options: Status message for User CSS deactivation" 265 | }, 266 | "saveUserCSS": { 267 | "message": "User CSS saved to storage", 268 | "description": "Options: Status message for saving User CSS to storage" 269 | }, 270 | "saveTheme": { 271 | "message": "Theme saved and activated", 272 | "description": "Options: Status message for theme activation" 273 | }, 274 | "exportTheme": { 275 | "message": "Theme code copied to clipboard", 276 | "description": "Options: Status message for exporting theme" 277 | }, 278 | "importThemeDesc": { 279 | "message": "Paste or drag and drop theme code into import field", 280 | "description": "Options: Status message describing theme import" 281 | }, 282 | "importTheme": { 283 | "message": "Theme imported. Click SAVE to save the theme", 284 | "description": "Options: Status message confirming theme import" 285 | }, 286 | "statusThemes": { 287 | "message": "Select, create and schedule themes", 288 | "description": "Options: Status message themes" 289 | }, 290 | "statusModifications": { 291 | "message": "Toggle modifications and write custom CSS", 292 | "description": "Options: Status message modifications" 293 | }, 294 | "statusInfo": { 295 | "message": "A big thank you to all contributors and users!", 296 | "description": "Options: Status message info" 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /_locales/es/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "bookmarks": { 3 | "message": "Marcadores", 4 | "description": "Link to bookmarks page from navigation bar" 5 | }, 6 | "signature": { 7 | "message": "Firma", 8 | "description": "Signature toggle for forum posts" 9 | }, 10 | "copyCode": { 11 | "message": "copiar código", 12 | "description": "Copy all code button for code markdown" 13 | }, 14 | "lastModified": { 15 | "message": "Última Modificación", 16 | "description": "Text before last edit timestamp in forum posts" 17 | }, 18 | "optionsLink": { 19 | "message": "Modificación del Foro", 20 | "description": "Link to options page in user dropdown menu. Probably no translation needed? Decide depending on language" 21 | }, 22 | "dismiss": { 23 | "message": "Ocultar", 24 | "description": "Dismisses community notifications" 25 | }, 26 | "emoticons": { 27 | "message": "Selector de Emoticonos", 28 | "description": "Title of formatting item for emote picker" 29 | }, 30 | "header": { 31 | "message": "Título", 32 | "description": "Title of formatting item header 1" 33 | }, 34 | "horizontal_line": { 35 | "message": "Linea horizontal", 36 | "description": "Title of formatting item horizontal rule" 37 | }, 38 | "block_quote": { 39 | "message": "Cita", 40 | "description": "Title of formatting item quote" 41 | }, 42 | "inline_code": { 43 | "message": "Línea de Código", 44 | "description": "Title of formatting item fixed width font" 45 | }, 46 | "table": { 47 | "message": "Tabla", 48 | "description": "Title of formatting item table" 49 | }, 50 | "number_list": { 51 | "message": "Lista Numerada", 52 | "description": "Title of formatting item numbered list" 53 | }, 54 | "spoiler": { 55 | "message": "Contenido oculto", 56 | "description": "Title of formatting item spoiler" 57 | }, 58 | "customToolbarTitle": { 59 | "message": "Modificar Barra de Herramientas", 60 | "description": "Title of custom toolbar editor" 61 | }, 62 | "dragText": { 63 | "message": "Pinchar y arrastrar para reorganizar", 64 | "description": "Hover text when on a draggable area" 65 | }, 66 | "themes": { 67 | "message": "Temas", 68 | "description": "Options: Title of themes section" 69 | }, 70 | "modifications": { 71 | "message": "Modificaciones", 72 | "description": "Options: Title of modifications section" 73 | }, 74 | "info": { 75 | "message": "Información", 76 | "description": "Options: Title of info section" 77 | }, 78 | "feedback": { 79 | "message": "Compartir opinión", 80 | "description": "Options: Feedback link in navigation" 81 | }, 82 | "schedule": { 83 | "message": "Programación", 84 | "description": "Options: Schedule headline" 85 | }, 86 | "themeMachine": { 87 | "message": "Máquina de Temas", 88 | "description": "Options: Theme machine headline" 89 | }, 90 | "background": { 91 | "message": "Fondo", 92 | "description": "Options: Theme machine edit background" 93 | }, 94 | "foreground": { 95 | "message": "Primer plano", 96 | "description": "Options: Theme machine edit foreground" 97 | }, 98 | "highlight": { 99 | "message": "Resaltado", 100 | "description": "Options: Theme machine edit highlight" 101 | }, 102 | "accent": { 103 | "message": "Acentuado", 104 | "description": "Options: Theme machine edit accent" 105 | }, 106 | "link": { 107 | "message": "Enlace", 108 | "description": "Options: Theme machine edit link" 109 | }, 110 | "code": { 111 | "message": "Código", 112 | "description": "Options: Theme machine edit code" 113 | }, 114 | "dropdown": { 115 | "message": "Menú desplegable", 116 | "description": "Options: Theme machine edit dropdown" 117 | }, 118 | "selectModifications": { 119 | "message": "Seleccionar Modificaciones", 120 | "description": "Options: Modifications headline" 121 | }, 122 | "advancedFormatting": { 123 | "message": "Formato avanzado", 124 | "description": "Options: Title of advanced formatting mod" 125 | }, 126 | "advancedFormattingDesc": { 127 | "message": "Añade selector de emoticonos y otros botones de Formato a la Barra de Herramientas para la edición de mensajes en el Foro.", 128 | "description": "Options: Description of the advanced formatting mod" 129 | }, 130 | "hideHeader": { 131 | "message": "Auto ocultar encabezado mientras se desplaza la página", 132 | "description": "Options: Title of auto-hide header on scroll mod" 133 | }, 134 | "hideHeaderDesc": { 135 | "message": "Oculta el encabezado al desplazar hacia abajo, lo muestra al desplazar hacia arriba.", 136 | "description": "Options: Description of auto-hide header on scroll mod" 137 | }, 138 | "navbookmarks": { 139 | "message": "Marcadores en la Navegación", 140 | "description": "Options: Title of bookmarks in navigation mod" 141 | }, 142 | "navbookmarksDesc": { 143 | "message": "Muestra un enlace hacia la página de Marcadores en la Barra de Navegación para un fácil acceso.", 144 | "description": "Options: Description of bookmarks in navigation mod" 145 | }, 146 | "compactPosts": { 147 | "message": "Mensajes compactos", 148 | "description": "Options: Title of compact posts mod" 149 | }, 150 | "compactPostsDesc": { 151 | "message": "Elimina el márgen entre el nombre de usuario y el contenído. Puede romper el diseño de página.", 152 | "description": "Options: Description of compact posts mod" 153 | }, 154 | "customNotification": { 155 | "message": "Símbolos de notificación personalizados", 156 | "description": "Options: Title of custom notification icons mod" 157 | }, 158 | "customNotificationDesc": { 159 | "message": "Muestra símbolos de fuente en el menú desplegable para distinguir fácilmente un tipo de notificación de otra.", 160 | "description": "Options: Description of custom notification icons mod" 161 | }, 162 | "showUID": { 163 | "message": "Mostrar la ID de Usuario", 164 | "description": "Options: Title of show user IDs mod" 165 | }, 166 | "showUIDDesc": { 167 | "message": "Muestra las UIDs, cuando el ratón se halla sobre el nombre de usuario en un comentario o sobre su imagen en el perfil.", 168 | "description": "Options: Description of show user IDs mod" 169 | }, 170 | "systemEmoji": { 171 | "message": "Usar Emojis de Sistema", 172 | "description": "Options: Title of use system emoji mod" 173 | }, 174 | "systemEmojiDesc": { 175 | "message": "Usar Emojis de la Fuente provista por el Sistema Operativo en lugar del Emoji del Foro de Vivaldi.", 176 | "description": "Options: Description of use system emoji mod" 177 | }, 178 | "signatureMod": { 179 | "message": "Modificación de firma", 180 | "description": "Options: Title of signature mod" 181 | }, 182 | "signatureModDesc": { 183 | "message": "Oculta todas las firmas y en su lugar muestra un botón. Cuando se pincha, la firma seleccionada se vuelve a mostrar.", 184 | "description": "Options: Description of signature mod" 185 | }, 186 | "squareAvatars": { 187 | "message": "Imágenes de usuario cuadradas", 188 | "description": "Options: Title of square avatars mod" 189 | }, 190 | "squareAvatarsDesc": { 191 | "message": "Imágenes de usuario cuadradas en todas partes!", 192 | "description": "Options: Description of square avatars mod" 193 | }, 194 | "userCSS": { 195 | "message": "CSS del usuario", 196 | "description": "Options: User CSS headline" 197 | }, 198 | "userCSSDesc": { 199 | "message": "Introduce sólo el código CSS! Pincha el selector para Activar/Desactivar. GUARDAR para salvar en almacén. Selecciona STANDARD en TEMAS para usar tu propio tema.", 200 | "description": "Options: User CSS placeholder/description" 201 | }, 202 | "changelog": { 203 | "message": "Lista de cambios", 204 | "description": "Options: Changelog headline" 205 | }, 206 | "credits": { 207 | "message": "Contribuciones", 208 | "description": "Options: Credits headline" 209 | }, 210 | "save": { 211 | "message": "Guardar", 212 | "description": "Options: Text to show on a button that performs some sort of save operation" 213 | }, 214 | "edit": { 215 | "message": "Editar", 216 | "description": "Options: Text to show on a button that performs some sort of edit operation" 217 | }, 218 | "import": { 219 | "message": "Importar", 220 | "description": "Options: Text to show on a button that performs some sort of import operation" 221 | }, 222 | "cancel": { 223 | "message": "Cancelar", 224 | "description": "Options: Text to show on a button that performs some sort of cancel operation" 225 | }, 226 | "export": { 227 | "message": "Exportar", 228 | "description": "Options: Text to show on a button that performs some sort of export operation." 229 | }, 230 | "reset": { 231 | "message": "Resetear", 232 | "description": "Options: Text to show on a button that performs some sort of reset operation" 233 | }, 234 | "confirmReset": { 235 | "message": "Resetear la extensión? Vuelve a pinchar para confirmar", 236 | "description": "Options: Status message to confirm reset" 237 | }, 238 | "cancelReset": { 239 | "message": "Reseteo cancelado", 240 | "description": "Options: Status message after cancelled reset" 241 | }, 242 | "cancelImport": { 243 | "message": "Importación cancelada", 244 | "description": "Options: Status message after cancelled import" 245 | }, 246 | "optionsReset": { 247 | "message": "Opciones reseteadas, almacenamiento limpiado", 248 | "description": "Options: Status message after reset" 249 | }, 250 | "activateSchedule": { 251 | "message": "Programación activada", 252 | "description": "Options: Status message for Schedule activation" 253 | }, 254 | "deactivateSchedule": { 255 | "message": "Programación desactivada", 256 | "description": "Options: Status message for Schedule deactivation" 257 | }, 258 | "activateUserCSS": { 259 | "message": "CSS del usuario activado", 260 | "description": "Options: Status message for User CSS activation" 261 | }, 262 | "deactivateUserCSS": { 263 | "message": "CSS del usuario desactivado", 264 | "description": "Options: Status message for User CSS deactivation" 265 | }, 266 | "saveUserCSS": { 267 | "message": "CSS del usuario guardado en almacén", 268 | "description": "Options: Status message for saving User CSS to storage" 269 | }, 270 | "saveTheme": { 271 | "message": "Tema guardado y activado", 272 | "description": "Options: Status message for theme activation" 273 | }, 274 | "exportTheme": { 275 | "message": "Código del Tema copiado al portapapeles", 276 | "description": "Options: Status message for exporting theme" 277 | }, 278 | "importThemeDesc": { 279 | "message": "Pegar o Arrastrar y Soltar código del Tema en el campo de Importación", 280 | "description": "Options: Status message describing theme import" 281 | }, 282 | "importTheme": { 283 | "message": "Tema importado. Pincha GUARDAR para guardar el tema", 284 | "description": "Options: Status message confirming theme import" 285 | }, 286 | "statusThemes": { 287 | "message": "Selecciona, Crea y Programa temas", 288 | "description": "Options: Status message themes" 289 | }, 290 | "statusModifications": { 291 | "message": "Selecciona Modificaciones y escribe CSS personalizados", 292 | "description": "Options: Status message modifications" 293 | }, 294 | "statusInfo": { 295 | "message": "Muchísimas gracias a todos los contribuidores y usuarios!", 296 | "description": "Options: Status message info" 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /_locales/fr/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "bookmarks": { 3 | "message": "Marque-pages", 4 | "description": "Link to bookmarks page from navigation bar" 5 | }, 6 | "signature": { 7 | "message": "Signature", 8 | "description": "Signature toggle for forum posts" 9 | }, 10 | "copyCode": { 11 | "message": "copier code", 12 | "description": "Copy all code button for code markdown" 13 | }, 14 | "lastModified": { 15 | "message": "Dernière modification", 16 | "description": "Text before last edit timestamp in forum posts" 17 | }, 18 | "optionsLink": { 19 | "message": "Forum mod", 20 | "description": "Link to options page in user dropdown menu. Probably no translation needed? Decide depending on language" 21 | }, 22 | "dismiss": { 23 | "message": "Supprimer", 24 | "description": "Dismisses community notifications" 25 | }, 26 | "emoticons": { 27 | "message": "Emoticônes", 28 | "description": "Title of formatting item for emote picker" 29 | }, 30 | "header": { 31 | "message": "Titre", 32 | "description": "Title of formatting item header 1" 33 | }, 34 | "horizontal_line": { 35 | "message": "Ligne Horizontale", 36 | "description": "Title of formatting item horizontal rule" 37 | }, 38 | "block_quote": { 39 | "message": "Citation", 40 | "description": "Title of formatting item quote" 41 | }, 42 | "inline_code": { 43 | "message": "Code dans le texte", 44 | "description": "Title of formatting item fixed width font" 45 | }, 46 | "table": { 47 | "message": "Tableau", 48 | "description": "Title of formatting item table" 49 | }, 50 | "number_list": { 51 | "message": "Liste Numérotée", 52 | "description": "Title of formatting item numbered list" 53 | }, 54 | "spoiler": { 55 | "message": "Spoiler", 56 | "description": "Title of formatting item spoiler" 57 | }, 58 | "customToolbarTitle": { 59 | "message": "Personnaliser la barre d'outils", 60 | "description": "Title of custom toolbar editor" 61 | }, 62 | "dragText": { 63 | "message": "Déplacer par glissé/déposé", 64 | "description": "Hover text when on a draggable area" 65 | }, 66 | "themes": { 67 | "message": "Thèmes", 68 | "description": "Options: Title of themes section" 69 | }, 70 | "modifications": { 71 | "message": "Modifications", 72 | "description": "Options: Title of modifications section" 73 | }, 74 | "info": { 75 | "message": "Info", 76 | "description": "Options: Title of info section" 77 | }, 78 | "feedback": { 79 | "message": "Feedback", 80 | "description": "Options: Feedback link in navigation" 81 | }, 82 | "schedule": { 83 | "message": "Planifier les thèmes", 84 | "description": "Options: Schedule headline" 85 | }, 86 | "themeMachine": { 87 | "message": "Theme Machine", 88 | "description": "Options: Theme machine headline" 89 | }, 90 | "background": { 91 | "message": "Fond", 92 | "description": "Options: Theme machine edit background" 93 | }, 94 | "foreground": { 95 | "message": "Texte", 96 | "description": "Options: Theme machine edit foreground" 97 | }, 98 | "highlight": { 99 | "message": "Elément activé", 100 | "description": "Options: Theme machine edit highlight" 101 | }, 102 | "accent": { 103 | "message": "Accentuation", 104 | "description": "Options: Theme machine edit accent" 105 | }, 106 | "link": { 107 | "message": "Lien", 108 | "description": "Options: Theme machine edit link" 109 | }, 110 | "code": { 111 | "message": "Code", 112 | "description": "Options: Theme machine edit code" 113 | }, 114 | "dropdown": { 115 | "message": "Menus déroulants", 116 | "description": "Options: Theme machine edit dropdown" 117 | }, 118 | "selectModifications": { 119 | "message": "Choisir les Modifications", 120 | "description": "Options: Modifications headline" 121 | }, 122 | "advancedFormatting": { 123 | "message": "Formatage avancé", 124 | "description": "Options: Title of advanced formatting mod" 125 | }, 126 | "advancedFormattingDesc": { 127 | "message": "Ajoute des émoticônes et des boutons de formatage. Permet, par glissé/déposé de réordonner, de retirer et d'ajouter des boutons à la barre de formatage lors de l'édition/composition des messages sur le forum.", 128 | "description": "Options: Description of the advanced formatting mod" 129 | }, 130 | "hideHeader": { 131 | "message": "Masquer l'en-tête lors du défilement.", 132 | "description": "Options: Title of auto-hide header on scroll mod" 133 | }, 134 | "hideHeaderDesc": { 135 | "message": "Masque l'en-tête en défilant vers le bas, l'affiche en défilant vers le haut.", 136 | "description": "Options: Description of auto-hide header on scroll mod" 137 | }, 138 | "navbookmarks": { 139 | "message": "Marque-pages dans la barre de navigation", 140 | "description": "Options: Title of bookmarks in navigation mod" 141 | }, 142 | "navbookmarksDesc": { 143 | "message": "Affiche un lien vers les marque-pages dans la barre de navigation.", 144 | "description": "Options: Description of bookmarks in navigation mod" 145 | }, 146 | "compactPosts": { 147 | "message": "Messages compacts", 148 | "description": "Options: Title of compact posts mod" 149 | }, 150 | "compactPostsDesc": { 151 | "message": "Supprime la marge entre le nom d'utilisateur et le corps du message. Peut rompre la mise en page.", 152 | "description": "Options: Description of compact posts mod" 153 | }, 154 | "customNotification": { 155 | "message": "Icônes de notifications", 156 | "description": "Options: Title of custom notification icons mod" 157 | }, 158 | "customNotificationDesc": { 159 | "message": "Affiche les icônes dans l'en-tête du menu déroulant des notifications, pour distinguer facilement les différents types de notifications.", 160 | "description": "Options: Description of custom notification icons mod" 161 | }, 162 | "showUID": { 163 | "message": "Afficher l'ID de l'utilisateur", 164 | "description": "Options: Title of show user IDs mod" 165 | }, 166 | "showUIDDesc": { 167 | "message": "Affiche l'ID au survol du nom de l'utilisateur dans l'en-tête d'un message et au survol de l'avatar dans le profil.", 168 | "description": "Options: Description of show user IDs mod" 169 | }, 170 | "systemEmoji": { 171 | "message": "Utiliser les émoticônes du Système", 172 | "description": "Options: Title of use system emoji mod" 173 | }, 174 | "systemEmojiDesc": { 175 | "message": "Utilisez les émoticônes du système d'exploitation à la place de celles du Forum Vivaldi.", 176 | "description": "Options: Description of use system emoji mod" 177 | }, 178 | "signatureMod": { 179 | "message": "Mod Signature", 180 | "description": "Options: Title of signature mod" 181 | }, 182 | "signatureModDesc": { 183 | "message": "Masque toutes les signatures et les remplace par un bouton. La signature de chaque message est affichée en cliquant le bouton.", 184 | "description": "Options: Description of signature mod" 185 | }, 186 | "squareAvatars": { 187 | "message": "Avatars carrés", 188 | "description": "Options: Title of square avatars mod" 189 | }, 190 | "squareAvatarsDesc": { 191 | "message": "Uniquement des avatars carrés!", 192 | "description": "Options: Description of square avatars mod" 193 | }, 194 | "userCSS": { 195 | "message": "CSS personnalisés", 196 | "description": "Options: User CSS headline" 197 | }, 198 | "userCSSDesc": { 199 | "message": "Code CSS uniquement! Cliquer ACTIVER/DESACTIVER pour activer/désactiver, ENREGISTRER pour enregistrer. Choisissez STANDARD dans les THEMES, si vous voulez utiliser votre propre thème.", 200 | "description": "Options: User CSS placeholder/description" 201 | }, 202 | "changelog": { 203 | "message": "Changelog", 204 | "description": "Options: Changelog headline" 205 | }, 206 | "credits": { 207 | "message": "Credits", 208 | "description": "Options: Credits headline" 209 | }, 210 | "save": { 211 | "message": "Enregistrer", 212 | "description": "Options: Text to show on a button that performs some sort of save operation" 213 | }, 214 | "edit": { 215 | "message": "Modifier", 216 | "description": "Options: Text to show on a button that performs some sort of edit operation" 217 | }, 218 | "import": { 219 | "message": "Importer", 220 | "description": "Options: Text to show on a button that performs some sort of import operation" 221 | }, 222 | "cancel": { 223 | "message": "Annuler", 224 | "description": "Options: Text to show on a button that performs some sort of cancel operation" 225 | }, 226 | "export": { 227 | "message": "Exporter", 228 | "description": "Options: Text to show on a button that performs some sort of export operation." 229 | }, 230 | "reset": { 231 | "message": "Réinitialiser", 232 | "description": "Options: Text to show on a button that performs some sort of reset operation" 233 | }, 234 | "confirmReset": { 235 | "message": "Réinitialiser l'extension? Cliquer de nouveau pour confirmer.", 236 | "description": "Options: Status message to confirm reset" 237 | }, 238 | "cancelReset": { 239 | "message": "Réinitialisation annulée.", 240 | "description": "Options: Status message after cancelled reset" 241 | }, 242 | "cancelImport": { 243 | "message": "Importation annulée.", 244 | "description": "Options: Status message after cancelled import" 245 | }, 246 | "optionsReset": { 247 | "message": "Options réinitialisées, stockage supprimé.", 248 | "description": "Options: Status message after reset" 249 | }, 250 | "activateSchedule": { 251 | "message": "Activer la planification.", 252 | "description": "Options: Status message for Schedule activation" 253 | }, 254 | "deactivateSchedule": { 255 | "message": "Désactiver la planification.", 256 | "description": "Options: Status message for Schedule deactivation" 257 | }, 258 | "activateUserCSS": { 259 | "message": "CSS personnalisés activés.", 260 | "description": "Options: Status message for User CSS activation" 261 | }, 262 | "deactivateUserCSS": { 263 | "message": "CSS personnalisés désactivés.", 264 | "description": "Options: Status message for User CSS deactivation" 265 | }, 266 | "saveUserCSS": { 267 | "message": "CSS personnalisés enregistrés.", 268 | "description": "Options: Status message for saving User CSS to storage" 269 | }, 270 | "saveTheme": { 271 | "message": "Thème enregistré et activé.", 272 | "description": "Options: Status message for theme activation" 273 | }, 274 | "exportTheme": { 275 | "message": "Code du thème copié dans le presse-papiers.", 276 | "description": "Options: Status message for exporting theme" 277 | }, 278 | "importThemeDesc": { 279 | "message": "Collez ou glissez/déposez le code du thème à importer dans le champs.", 280 | "description": "Options: Status message describing theme import" 281 | }, 282 | "importTheme": { 283 | "message": "Thème importé. Cliquer ENREGISTRER pour enregistrer le thème.", 284 | "description": "Options: Status message confirming theme import" 285 | }, 286 | "statusThemes": { 287 | "message": "Choisissez, créez et planifiez les thèmes.", 288 | "description": "Options: Status message themes" 289 | }, 290 | "statusModifications": { 291 | "message": "Activer/Désactiver les modifications et éditeur de CSS personnalisés", 292 | "description": "Options: Status message modifications" 293 | }, 294 | "statusInfo": { 295 | "message": "Un grand MERCI à tous les utilisateurs et contributeurs!", 296 | "description": "Options: Status message info" 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /_locales/it/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "bookmarks": { 3 | "message": "Segnalibri", 4 | "description": "Link to bookmarks page from navigation bar" 5 | }, 6 | "signature": { 7 | "message": "Firma", 8 | "description": "Signature toggle for forum posts" 9 | }, 10 | "copyCode": { 11 | "message": "copia codice", 12 | "description": "Copy all code button for code markdown" 13 | }, 14 | "lastModified": { 15 | "message": "Ultima modifica", 16 | "description": "Text before last edit timestamp in forum posts" 17 | }, 18 | "optionsLink": { 19 | "message": "Opzioni mod", 20 | "description": "Link to options page in user dropdown menu" 21 | }, 22 | "dismiss": { 23 | "message": "Nascondi", 24 | "description": "Dismisses community notifications" 25 | }, 26 | "emoticons": { 27 | "message": "Emote", 28 | "description": "Title of formatting item for emote picker" 29 | }, 30 | "header": { 31 | "message": "Titolo", 32 | "description": "Title of formatting item header 1" 33 | }, 34 | "horizontal_line": { 35 | "message": "Riga orizzontale", 36 | "description": "Title of formatting item horizontal rule" 37 | }, 38 | "block_quote": { 39 | "message": "Citazione", 40 | "description": "Title of formatting item quote" 41 | }, 42 | "inline_code": { 43 | "message": "Riga di codice", 44 | "description": "Title of formatting item fixed width font" 45 | }, 46 | "table": { 47 | "message": "Tabella", 48 | "description": "Title of formatting item table" 49 | }, 50 | "number_list": { 51 | "message": "Elenco numerato", 52 | "description": "Title of formatting item numbered list" 53 | }, 54 | "spoiler": { 55 | "message": "Spoiler", 56 | "description": "Title of formatting item spoiler" 57 | }, 58 | "customToolbarTitle": { 59 | "message": "Barra personalizzata", 60 | "description": "Title of custom toolbar editor" 61 | }, 62 | "dragText": { 63 | "message": "Clicca e trascina per spostare", 64 | "description": "Hover text when on a draggable area" 65 | }, 66 | "themes": { 67 | "message": "Temi", 68 | "description": "Options: Title of themes section" 69 | }, 70 | "modifications": { 71 | "message": "Mod", 72 | "description": "Options: Title of modifications section" 73 | }, 74 | "info": { 75 | "message": "Info", 76 | "description": "Options: Title of info section" 77 | }, 78 | "feedback": { 79 | "message": "Feedback", 80 | "description": "Options: Feedback link in navigation" 81 | }, 82 | "schedule": { 83 | "message": "Pianificazione", 84 | "description": "Options: Schedule headline" 85 | }, 86 | "themeMachine": { 87 | "message": "Macchina dei temi", 88 | "description": "Options: Theme machine headline" 89 | }, 90 | "background": { 91 | "message": "Sfondo", 92 | "description": "Options: Theme machine edit background" 93 | }, 94 | "foreground": { 95 | "message": "Primo piano", 96 | "description": "Options: Theme machine edit foreground" 97 | }, 98 | "highlight": { 99 | "message": "Evidenziato", 100 | "description": "Options: Theme machine edit highlight" 101 | }, 102 | "accent": { 103 | "message": "Accento", 104 | "description": "Options: Theme machine edit accent" 105 | }, 106 | "link": { 107 | "message": "Collegamento", 108 | "description": "Options: Theme machine edit link" 109 | }, 110 | "code": { 111 | "message": "Codice", 112 | "description": "Options: Theme machine edit code" 113 | }, 114 | "dropdown": { 115 | "message": "Menù a discesa", 116 | "description": "Options: Theme machine edit dropdown" 117 | }, 118 | "selectModifications": { 119 | "message": "Seleziona mod", 120 | "description": "Options: Modifications headline" 121 | }, 122 | "advancedFormatting": { 123 | "message": "Formattazione avanzata", 124 | "description": "Options: Title of advanced formatting mod" 125 | }, 126 | "advancedFormattingDesc": { 127 | "message": "Aggiunge un selettore emote, nuovi pulsanti per la formattazione del testo e consente di spostare e riordinare gli elementi della barra durante la modifica dei post sul forum", 128 | "description": "Options: Description of the advanced formatting mod" 129 | }, 130 | "hideHeader": { 131 | "message": "Nascondi l'header di Vivaldi su scorrimento", 132 | "description": "Options: Title of auto-hide header on scroll mod" 133 | }, 134 | "hideHeaderDesc": { 135 | "message": "Nasconde l'header quando scorri in basso, lo mostra nuovamente quando scorri in alto", 136 | "description": "Options: Description of auto-hide header on scroll mod" 137 | }, 138 | "navbookmarks": { 139 | "message": "Segnalibri nella barra di navigazione", 140 | "description": "Options: Title of bookmarks in navigation mod" 141 | }, 142 | "navbookmarksDesc": { 143 | "message": "Mostra un link alla pagina dei segnalibri nella barra di navigazione principale per un rapido accesso", 144 | "description": "Options: Description of bookmarks in navigation mod" 145 | }, 146 | "compactPosts": { 147 | "message": "Post compatti", 148 | "description": "Options: Title of compact posts mod" 149 | }, 150 | "compactPostsDesc": { 151 | "message": "Rimuove il margine tra il nome utente e il contenuto. Potrebbe rompere l'interfaccia.", 152 | "description": "Options: Description of compact posts mod" 153 | }, 154 | "customNotification": { 155 | "message": "Icone notifiche personalizzate", 156 | "description": "Options: Title of custom notification icons mod" 157 | }, 158 | "customNotificationDesc": { 159 | "message": "Mostra ulteriori icone nel menu delle notifiche per distinguerle meglio", 160 | "description": "Options: Description of custom notification icons mod" 161 | }, 162 | "showUID": { 163 | "message": "Mostra ID degli utenti", 164 | "description": "Options: Title of show user IDs mod" 165 | }, 166 | "showUIDDesc": { 167 | "message": "Mostra ID degli utenti passando col mouse sul nome utente in cima a un post o su un avatar nel loro profilo", 168 | "description": "Options: Description of show user IDs mod" 169 | }, 170 | "systemEmoji": { 171 | "message": "Utilizza emoji di sistema", 172 | "description": "Options: Title of use system emoji mod" 173 | }, 174 | "systemEmojiDesc": { 175 | "message": "Utilizza le emoji di sistema anziché usare quelle del forum di Vivaldi", 176 | "description": "Options: Description of use system emoji mod" 177 | }, 178 | "signatureMod": { 179 | "message": "Mod firma", 180 | "description": "Options: Title of signature mod" 181 | }, 182 | "signatureModDesc": { 183 | "message": "Nasconde tutte le firme e le sostituisce con un pulsante che, quando cliccato, mostra la firma del post interessato", 184 | "description": "Options: Description of signature mod" 185 | }, 186 | "squareAvatars": { 187 | "message": "Avatar quadrati", 188 | "description": "Options: Title of square avatars mod" 189 | }, 190 | "squareAvatarsDesc": { 191 | "message": "Avatar quadrati ovunque!", 192 | "description": "Options: Description of square avatars mod" 193 | }, 194 | "userCSS": { 195 | "message": "CSS utente", 196 | "description": "Options: User CSS headline" 197 | }, 198 | "userCSSDesc": { 199 | "message": "Inserire solo codice CSS! Premi AZIONA per attivare o disattivare, SALVA per meorizzare in archiviazione. Seleziona STANDARD nei TEMI se vuoi usare un tuo tema.", 200 | "description": "Options: User CSS placeholder/description" 201 | }, 202 | "changelog": { 203 | "message": "Storico versioni", 204 | "description": "Options: Changelog headline" 205 | }, 206 | "credits": { 207 | "message": "Ringraziamenti", 208 | "description": "Options: Credits headline" 209 | }, 210 | "save": { 211 | "message": "Salva", 212 | "description": "Options: Text to show on a button that performs some sort of save operation" 213 | }, 214 | "edit": { 215 | "message": "Modifica", 216 | "description": "Options: Text to show on a button that performs some sort of edit operation" 217 | }, 218 | "import": { 219 | "message": "Importa", 220 | "description": "Options: Text to show on a button that performs some sort of import operation" 221 | }, 222 | "cancel": { 223 | "message": "Annulla", 224 | "description": "Options: Text to show on a button that performs some sort of cancel operation" 225 | }, 226 | "export": { 227 | "message": "Esporta", 228 | "description": "Options: Text to show on a button that performs some sort of export operation" 229 | }, 230 | "reset": { 231 | "message": "Reset", 232 | "description": "Options: Text to show on a button that performs some sort of reset operation" 233 | }, 234 | "confirmReset": { 235 | "message": "Resettare l'estensione? Clicca nuovamente per confermare", 236 | "description": "Options: Status message to confirm reset" 237 | }, 238 | "cancelReset": { 239 | "message": "Reset annullato", 240 | "description": "Options: Status message after cancelled reset" 241 | }, 242 | "cancelImport": { 243 | "message": "Importazione annullata", 244 | "description": "Options: Status message after cancelled import" 245 | }, 246 | "optionsReset": { 247 | "message": "Opzioni resettate, archiviazione ripulita", 248 | "description": "Options: Status message after reset" 249 | }, 250 | "activateSchedule": { 251 | "message": "Pianificazione attivata", 252 | "description": "Options: Status message for Schedule activation" 253 | }, 254 | "deactivateSchedule": { 255 | "message": "Pianificazione disattivata", 256 | "description": "Options: Status message for Schedule deactivation" 257 | }, 258 | "activateUserCSS": { 259 | "message": "CSS utente attivato", 260 | "description": "Options: Status message for User CSS activation" 261 | }, 262 | "deactivateUserCSS": { 263 | "message": "CSS utente disattivato", 264 | "description": "Options: Status message for User CSS deactivation" 265 | }, 266 | "saveUserCSS": { 267 | "message": "CSS utente salvato in archiviazione", 268 | "description": "Options: Status message for saving User CSS to storage" 269 | }, 270 | "saveTheme": { 271 | "message": "Tema salvato e attivato", 272 | "description": "Options: Status message for theme activation" 273 | }, 274 | "exportTheme": { 275 | "message": "Codice tema copiato negli appunti", 276 | "description": "Options: Status message for exporting theme" 277 | }, 278 | "importThemeDesc": { 279 | "message": "Incolla o trascina il codice tema nel campo importa", 280 | "description": "Options: Status message describing theme import" 281 | }, 282 | "importTheme": { 283 | "message": "Tema importato. Clicca SALVA per memorizzare il tema", 284 | "description": "Options: Status message confirming theme import" 285 | }, 286 | "statusThemes": { 287 | "message": "Seleziona, crea e pianifica temi", 288 | "description": "Options: Status message themes" 289 | }, 290 | "statusModifications": { 291 | "message": "Scegli le mod e scrivi codice CSS personalizzato", 292 | "description": "Options: Status message modifications" 293 | }, 294 | "statusInfo": { 295 | "message": "Un grande ringraziamento a tutti gli utenti e ai collaboratori!", 296 | "description": "Options: Status message info" 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /_locales/ja/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "bookmarks": { 3 | "message": "Bookmarks", 4 | "description": "Link to bookmarks page from navigation bar" 5 | }, 6 | "signature": { 7 | "message": "署名", 8 | "description": "Signature toggle for forum posts" 9 | }, 10 | "copyCode": { 11 | "message": "copy code", 12 | "description": "Copy all code button for code markdown" 13 | }, 14 | "lastModified": { 15 | "message": "Last modified", 16 | "description": "Text before last edit timestamp in forum posts" 17 | }, 18 | "optionsLink": { 19 | "message": "VFmオプション", 20 | "description": "Link to options page in user dropdown menu. Probably no translation needed? Decide depending on language" 21 | }, 22 | "dismiss": { 23 | "message": "Dismiss", 24 | "description": "Dismisses community notifications" 25 | }, 26 | "emoticons": { 27 | "message": "Emote Picker", 28 | "description": "Title of formatting item for emote picker" 29 | }, 30 | "header": { 31 | "message": "ヘッダ", 32 | "description": "Title of formatting item header 1" 33 | }, 34 | "horizontal_line": { 35 | "message": "
", 36 | "description": "Title of formatting item horizontal rule" 37 | }, 38 | "block_quote": { 39 | "message": "クォート", 40 | "description": "Title of formatting item quote" 41 | }, 42 | "inline_code": { 43 | "message": "インラインコード", 44 | "description": "Title of formatting item fixed width font" 45 | }, 46 | "table": { 47 | "message": "テーブル", 48 | "description": "Title of formatting item table" 49 | }, 50 | "number_list": { 51 | "message": "ナンバリング", 52 | "description": "Title of formatting item numbered list" 53 | }, 54 | "spoiler": { 55 | "message": "ネタバレ", 56 | "description": "Title of formatting item spoiler" 57 | }, 58 | "customToolbarTitle": { 59 | "message": "カスタムツールバー編集", 60 | "description": "Title of custom toolbar editor" 61 | }, 62 | "dragText": { 63 | "message": "Click and drag to move", 64 | "description": "Hover text when on a draggable area" 65 | }, 66 | "themes": { 67 | "message": "テーマ", 68 | "description": "Options: Title of themes section" 69 | }, 70 | "modifications": { 71 | "message": "カスタマイズ", 72 | "description": "Options: Title of modifications section" 73 | }, 74 | "info": { 75 | "message": "VFmについて", 76 | "description": "Options: Title of info section" 77 | }, 78 | "feedback": { 79 | "message": "フィードバック", 80 | "description": "Options: Feedback link in navigation" 81 | }, 82 | "schedule": { 83 | "message": "スケジュール", 84 | "description": "Options: Schedule headline" 85 | }, 86 | "themeMachine": { 87 | "message": "テーマの選択", 88 | "description": "Options: Theme machine headline" 89 | }, 90 | "background": { 91 | "message": "背景", 92 | "description": "Options: Theme machine edit background" 93 | }, 94 | "foreground": { 95 | "message": "テキスト", 96 | "description": "Options: Theme machine edit foreground" 97 | }, 98 | "highlight": { 99 | "message": "ハイライト", 100 | "description": "Options: Theme machine edit highlight" 101 | }, 102 | "accent": { 103 | "message": "アクセント", 104 | "description": "Options: Theme machine edit accent" 105 | }, 106 | "link": { 107 | "message": "リンク", 108 | "description": "Options: Theme machine edit link" 109 | }, 110 | "code": { 111 | "message": "コード", 112 | "description": "Options: Theme machine edit code" 113 | }, 114 | "dropdown": { 115 | "message": "ドロップダウン", 116 | "description": "Options: Theme machine edit dropdown" 117 | }, 118 | "selectModifications": { 119 | "message": "カスタマイズの選択", 120 | "description": "Options: Modifications headline" 121 | }, 122 | "advancedFormatting": { 123 | "message": "筆箱", 124 | "description": "Options: Title of advanced formatting mod" 125 | }, 126 | "advancedFormattingDesc": { 127 | "message": "レス欄にカスタムツールバーと便利なボタンを表示。ドラッグでボタンの追加・削除・順番変更もできます。", 128 | "description": "Options: Description of the advanced formatting mod" 129 | }, 130 | "hideHeader": { 131 | "message": "スクロールでヘッダを閉じる", 132 | "description": "Options: Title of auto-hide header on scroll mod" 133 | }, 134 | "hideHeaderDesc": { 135 | "message": "スクロール時にヘッダを自動開閉する。", 136 | "description": "Options: Description of auto-hide header on scroll mod" 137 | }, 138 | "navbookmarks": { 139 | "message": "オプションへのリンク", 140 | "description": "Options: Title of bookmarks in navigation mod" 141 | }, 142 | "navbookmarksDesc": { 143 | "message": "プロフィール画像からのプルダウンメニューにオプションへのリンクを表示する。", 144 | "description": "Options: Description of bookmarks in navigation mod" 145 | }, 146 | "compactPosts": { 147 | "message": "コンパクト・スレッド", 148 | "description": "Options: Title of compact posts mod" 149 | }, 150 | "compactPostsDesc": { 151 | "message": "ユーザーネームとレスの間の余白を詰める。レイアウトが崩れる可能性があります。", 152 | "description": "Options: Description of compact posts mod" 153 | }, 154 | "customNotification": { 155 | "message": "カスタム通知アイコン", 156 | "description": "Options: Title of custom notification icons mod" 157 | }, 158 | "customNotificationDesc": { 159 | "message": "通知の横にアイコンを表示して、通知内容を分かりやすくする。", 160 | "description": "Options: Description of custom notification icons mod" 161 | }, 162 | "showUID": { 163 | "message": "ユーザーIDの表示", 164 | "description": "Options: Title of show user IDs mod" 165 | }, 166 | "showUIDDesc": { 167 | "message": "スレッドのユーザー名にマウス合わせるとユーザーIDを表示。", 168 | "description": "Options: Description of show user IDs mod" 169 | }, 170 | "systemEmoji": { 171 | "message": "システムの絵文字を使用", 172 | "description": "Options: Title of use system emoji mod" 173 | }, 174 | "systemEmojiDesc": { 175 | "message": "Vivaldiフォーラムの絵文字ではなく、OSの絵文字を使用。", 176 | "description": "Options: Description of use system emoji mod" 177 | }, 178 | "signatureMod": { 179 | "message": "署名", 180 | "description": "Options: Title of signature mod" 181 | }, 182 | "signatureModDesc": { 183 | "message": "「署名」を表示。クリックすると内容を表示する。", 184 | "description": "Options: Description of signature mod" 185 | }, 186 | "squareAvatars": { 187 | "message": "スクウェア・アバター", 188 | "description": "Options: Title of square avatars mod" 189 | }, 190 | "squareAvatarsDesc": { 191 | "message": "プルフィール画像を四角くする。", 192 | "description": "Options: Description of square avatars mod" 193 | }, 194 | "userCSS": { 195 | "message": "User CSS", 196 | "description": "Options: User CSS headline" 197 | }, 198 | "userCSSDesc": { 199 | "message": "Input CSS code only! Click the toggle to activate/deactivate. SAVE to save to storage. Select Standard in Themes, if you want to run your own theme.", 200 | "description": "Options: User CSS placeholder/description" 201 | }, 202 | "changelog": { 203 | "message": "Changelog", 204 | "description": "Options: Changelog headline" 205 | }, 206 | "credits": { 207 | "message": "Credits", 208 | "description": "Options: Credits headline" 209 | }, 210 | "save": { 211 | "message": "保存", 212 | "description": "Options: Text to show on a button that performs some sort of save operation" 213 | }, 214 | "edit": { 215 | "message": "編集", 216 | "description": "Options: Text to show on a button that performs some sort of edit operation" 217 | }, 218 | "import": { 219 | "message": "インポート", 220 | "description": "Options: Text to show on a button that performs some sort of import operation" 221 | }, 222 | "cancel": { 223 | "message": "キャンセル", 224 | "description": "Options: Text to show on a button that performs some sort of cancel operation" 225 | }, 226 | "export": { 227 | "message": "エクスポート", 228 | "description": "Options: Text to show on a button that performs some sort of export operation." 229 | }, 230 | "reset": { 231 | "message": "リセット", 232 | "description": "Options: Text to show on a button that performs some sort of reset operation" 233 | }, 234 | "confirmReset": { 235 | "message": "本当にリセットしますか?よろしければもう一度クリックして完了して下さい", 236 | "description": "Options: Status message to confirm reset" 237 | }, 238 | "cancelReset": { 239 | "message": "リセットをキャンセルしました", 240 | "description": "Options: Status message after cancelled reset" 241 | }, 242 | "cancelImport": { 243 | "message": "インポートをキャンセルしました", 244 | "description": "Options: Status message after cancelled import" 245 | }, 246 | "optionsReset": { 247 | "message": "設定はリセットされ、ストレージは消去されました", 248 | "description": "Options: Status message after reset" 249 | }, 250 | "activateSchedule": { 251 | "message": "スケジュールを有効にしました", 252 | "description": "Options: Status message for Schedule activation" 253 | }, 254 | "deactivateSchedule": { 255 | "message": "スケジュールを無効にしました", 256 | "description": "Options: Status message for Schedule deactivation" 257 | }, 258 | "activateUserCSS": { 259 | "message": "CSSを有効にしました", 260 | "description": "Options: Status message for User CSS activation" 261 | }, 262 | "deactivateUserCSS": { 263 | "message": "CSSを無効にしました", 264 | "description": "Options: Status message for User CSS deactivation" 265 | }, 266 | "saveUserCSS": { 267 | "message": "CSSをストレージに保存しました", 268 | "description": "Options: Status message for saving User CSS to storage" 269 | }, 270 | "saveTheme": { 271 | "message": "テーマを保存しアクティブにしました", 272 | "description": "Options: Status message for theme activation" 273 | }, 274 | "exportTheme": { 275 | "message": "テーマのコードを保存して下さい", 276 | "description": "Options: Status message for exporting theme" 277 | }, 278 | "importThemeDesc": { 279 | "message": "テーマのコードを貼り付けてください", 280 | "description": "Options: Status message describing theme import" 281 | }, 282 | "importTheme": { 283 | "message": "保存をクリックするとテーマがインポートされます", 284 | "description": "Options: Status message confirming theme import" 285 | }, 286 | "statusThemes": { 287 | "message": "テーマ・スケジュールの設定", 288 | "description": "Options: Status message themes" 289 | }, 290 | "statusModifications": { 291 | "message": "CSSの作成 / カスタマイズの選択", 292 | "description": "Options: Status message modifications" 293 | }, 294 | "statusInfo": { 295 | "message": "ご協力いただいた方々とユーザーの皆様に感謝!", 296 | "description": "Options: Status message info" 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /_locales/ru/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "bookmarks": { 3 | "message": "Закладки", 4 | "description": "Link to bookmarks page from navigation bar" 5 | }, 6 | "signature": { 7 | "message": "Подписи", 8 | "description": "Signature toggle for forum posts" 9 | }, 10 | "copyCode": { 11 | "message": "Копировать код", 12 | "description": "Copy all code button for code markdown" 13 | }, 14 | "lastModified": { 15 | "message": "Последнее редактирование", 16 | "description": "Text before last edit timestamp in forum posts" 17 | }, 18 | "optionsLink": { 19 | "message": "Модификации", 20 | "description": "Link to options page in user dropdown menu. Probably no translation needed? Decide depending on language" 21 | }, 22 | "dismiss": { 23 | "message": "Отключить", 24 | "description": "Dismisses community notifications" 25 | }, 26 | "emoticons": { 27 | "message": "Смайлики", 28 | "description": "Title of formatting item for emote picker" 29 | }, 30 | "header": { 31 | "message": "Заголовок", 32 | "description": "Title of formatting item header 1" 33 | }, 34 | "horizontal_line": { 35 | "message": "Горизонтальная линия", 36 | "description": "Title of formatting item horizontal rule" 37 | }, 38 | "block_quote": { 39 | "message": "Цитата", 40 | "description": "Title of formatting item quote" 41 | }, 42 | "inline_code": { 43 | "message": "Выделить код", 44 | "description": "Title of formatting item fixed width font" 45 | }, 46 | "table": { 47 | "message": "Таблица", 48 | "description": "Title of formatting item table" 49 | }, 50 | "number_list": { 51 | "message": "Пронумерованный", 52 | "description": "Title of formatting item numbered list" 53 | }, 54 | "spoiler": { 55 | "message": "Спойлер", 56 | "description": "Title of formatting item spoiler" 57 | }, 58 | "customToolbarTitle": { 59 | "message": "Настройки панели инструментов", 60 | "description": "Title of custom toolbar editor" 61 | }, 62 | "dragText": { 63 | "message": "Нажмите и удерживайте, чтобы перетащить", 64 | "description": "Hover text when on a draggable area" 65 | }, 66 | "themes": { 67 | "message": "Темы", 68 | "description": "Options: Title of themes section" 69 | }, 70 | "modifications": { 71 | "message": "Модификации", 72 | "description": "Options: Title of modifications section" 73 | }, 74 | "info": { 75 | "message": "Информация", 76 | "description": "Options: Title of info section" 77 | }, 78 | "feedback": { 79 | "message": "Обратная связь", 80 | "description": "Options: Feedback link in navigation" 81 | }, 82 | "schedule": { 83 | "message": "Расписание", 84 | "description": "Options: Schedule headline" 85 | }, 86 | "themeMachine": { 87 | "message": "Выбор темы", 88 | "description": "Options: Theme machine headline" 89 | }, 90 | "background": { 91 | "message": "Background", 92 | "description": "Options: Theme machine edit background" 93 | }, 94 | "foreground": { 95 | "message": "Foreground", 96 | "description": "Options: Theme machine edit foreground" 97 | }, 98 | "highlight": { 99 | "message": "Highlight", 100 | "description": "Options: Theme machine edit highlight" 101 | }, 102 | "accent": { 103 | "message": "Accent", 104 | "description": "Options: Theme machine edit accent" 105 | }, 106 | "link": { 107 | "message": "Link", 108 | "description": "Options: Theme machine edit link" 109 | }, 110 | "code": { 111 | "message": "Code", 112 | "description": "Options: Theme machine edit code" 113 | }, 114 | "dropdown": { 115 | "message": "Dropdown", 116 | "description": "Options: Theme machine edit dropdown" 117 | }, 118 | "selectModifications": { 119 | "message": "Выбор модификаций", 120 | "description": "Options: Modifications headline" 121 | }, 122 | "advancedFormatting": { 123 | "message": "Расширенное форматирование", 124 | "description": "Options: Title of advanced formatting mod" 125 | }, 126 | "advancedFormattingDesc": { 127 | "message": "Добавляет дополнительные кнопки форматирования и смайлики. Позволяет перетаскивать, удалять и добавлять новые кнопки форматирования текста на форуме.", 128 | "description": "Options: Description of the advanced formatting mod" 129 | }, 130 | "hideHeader": { 131 | "message": "Автоматически скрывать шапку сайта при прокрутке", 132 | "description": "Options: Title of auto-hide header on scroll mod" 133 | }, 134 | "hideHeaderDesc": { 135 | "message": "Скрывает шапку сайта при прокрутке страницы вниз, показывает её при прокрутке вверх.", 136 | "description": "Options: Description of auto-hide header on scroll mod" 137 | }, 138 | "navbookmarks": { 139 | "message": "Закладки на панели навигации", 140 | "description": "Options: Title of bookmarks in navigation mod" 141 | }, 142 | "navbookmarksDesc": { 143 | "message": "Отображает ссылку на страницу закладок прямо на панели навигации.", 144 | "description": "Options: Description of bookmarks in navigation mod" 145 | }, 146 | "compactPosts": { 147 | "message": "Компактные публикации", 148 | "description": "Options: Title of compact posts mod" 149 | }, 150 | "compactPostsDesc": { 151 | "message": "Удаляет отступы между именем пользователя и публикацией. Может сломать разметку сайта.", 152 | "description": "Options: Description of compact posts mod" 153 | }, 154 | "customNotification": { 155 | "message": "Настраиваемые иконки уведомлений", 156 | "description": "Options: Title of custom notification icons mod" 157 | }, 158 | "customNotificationDesc": { 159 | "message": "Добавляет иконки в заголовок уведомлений, чтобы вы могли легко отличить один тип уведомлений от другого.", 160 | "description": "Options: Description of custom notification icons mod" 161 | }, 162 | "showUID": { 163 | "message": "Показывать ID пользователей", 164 | "description": "Options: Title of show user IDs mod" 165 | }, 166 | "showUIDDesc": { 167 | "message": "Показывает ID пользователя при наведении курсора на его ник в заголовке комментария или аватарку на странице профиля.", 168 | "description": "Options: Description of show user IDs mod" 169 | }, 170 | "systemEmoji": { 171 | "message": "Использовать системные эмодзи", 172 | "description": "Options: Title of use system emoji mod" 173 | }, 174 | "systemEmojiDesc": { 175 | "message": "Использовать эмодзи операционной системы вместо эмодзи форума Vivaldi.", 176 | "description": "Options: Description of use system emoji mod" 177 | }, 178 | "signatureMod": { 179 | "message": "Скрыть подписи", 180 | "description": "Options: Title of signature mod" 181 | }, 182 | "signatureModDesc": { 183 | "message": "Скрывает подписи к сообщениям и заменяет их отдельной кнопкой.", 184 | "description": "Options: Description of signature mod" 185 | }, 186 | "squareAvatars": { 187 | "message": "Квадратные аватарки", 188 | "description": "Options: Title of square avatars mod" 189 | }, 190 | "squareAvatarsDesc": { 191 | "message": "Только квадратны, только хардкор!", 192 | "description": "Options: Description of square avatars mod" 193 | }, 194 | "userCSS": { 195 | "message": "Пользовательские CSS", 196 | "description": "Options: User CSS headline" 197 | }, 198 | "userCSSDesc": { 199 | "message": "Вводите только CSS-код! Нажмите ПРИМЕНИТЬ, чтобы активировать/деактивировать код, СОХРАНИТЬ, чтобы сохранить изменения. Если хотите создать собственную тему, сперва выберите СТАНДАРТНУЮ тему в настройках.", 200 | "description": "Options: User CSS placeholder/description" 201 | }, 202 | "changelog": { 203 | "message": "Список изменений", 204 | "description": "Options: Changelog headline" 205 | }, 206 | "credits": { 207 | "message": "Участники", 208 | "description": "Options: Credits headline" 209 | }, 210 | "save": { 211 | "message": "Сохранить", 212 | "description": "Options: Text to show on a button that performs some sort of save operation" 213 | }, 214 | "edit": { 215 | "message": "Редактировать", 216 | "description": "Options: Text to show on a button that performs some sort of edit operation" 217 | }, 218 | "import": { 219 | "message": "Импорт", 220 | "description": "Options: Text to show on a button that performs some sort of import operation" 221 | }, 222 | "cancel": { 223 | "message": "Отмена", 224 | "description": "Options: Text to show on a button that performs some sort of cancel operation" 225 | }, 226 | "export": { 227 | "message": "Экспорт", 228 | "description": "Options: Text to show on a button that performs some sort of export operation." 229 | }, 230 | "reset": { 231 | "message": "Сброс", 232 | "description": "Options: Text to show on a button that performs some sort of reset operation" 233 | }, 234 | "confirmReset": { 235 | "message": "Сбросить настройки расширения? Нажмите ещё раз, чтобы подтвердить решение.", 236 | "description": "Options: Status message to confirm reset" 237 | }, 238 | "cancelReset": { 239 | "message": "Сброс настроек отменён.", 240 | "description": "Options: Status message after cancelled reset" 241 | }, 242 | "cancelImport": { 243 | "message": "Импорт отменён.", 244 | "description": "Options: Status message after cancelled import" 245 | }, 246 | "optionsReset": { 247 | "message": "Настройки сброшены, хранилище данных очищено.", 248 | "description": "Options: Status message after reset" 249 | }, 250 | "activateSchedule": { 251 | "message": "Расписание ВКЛ.", 252 | "description": "Options: Status message for Schedule activation" 253 | }, 254 | "deactivateSchedule": { 255 | "message": "Расписание ВЫКЛ.", 256 | "description": "Options: Status message for Schedule deactivation" 257 | }, 258 | "activateUserCSS": { 259 | "message": "Пользовательские CSS активированы.", 260 | "description": "Options: Status message for User CSS activation" 261 | }, 262 | "deactivateUserCSS": { 263 | "message": "Пользовательские CSS деактивированы.", 264 | "description": "Options: Status message for User CSS deactivation" 265 | }, 266 | "saveUserCSS": { 267 | "message": "Пользовательские CSS сохранены.", 268 | "description": "Options: Status message for saving User CSS to storage" 269 | }, 270 | "saveTheme": { 271 | "message": "Тема сохранена и активирована.", 272 | "description": "Options: Status message for theme activation" 273 | }, 274 | "exportTheme": { 275 | "message": "Код темы скопирован в буфер обмена.", 276 | "description": "Options: Status message for exporting theme" 277 | }, 278 | "importThemeDesc": { 279 | "message": "Вставьте или перетащите код темы в поле импорта.", 280 | "description": "Options: Status message describing theme import" 281 | }, 282 | "importTheme": { 283 | "message": "Тема импортирована. Нажмите СОХРАНИТЬ, чтобы её сохранить.", 284 | "description": "Options: Status message confirming theme import" 285 | }, 286 | "statusThemes": { 287 | "message": "Выберите тему или создайте собственную.", 288 | "description": "Options: Status message themes" 289 | }, 290 | "statusModifications": { 291 | "message": "Наведите курсор на модификацию, чтобы прочитать её описание", 292 | "description": "Options: Status message modifications" 293 | }, 294 | "statusInfo": { 295 | "message": "Огромное спасибо всем нашим пользователям и участникам!", 296 | "description": "Options: Status message info" 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /_locales/vi/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "bookmarks": { 3 | "message": "Dấu trang", 4 | "description": "Link to bookmarks page from navigation bar" 5 | }, 6 | "signature": { 7 | "message": "Chữ ký", 8 | "description": "Signature toggle for forum posts" 9 | }, 10 | "copyCode": { 11 | "message": "Sao chép mã", 12 | "description": "Copy all code button for code markdown" 13 | }, 14 | "lastModified": { 15 | "message": "Chỉnh sửa lần cuối", 16 | "description": "Text before last edit timestamp in forum posts" 17 | }, 18 | "optionsLink": { 19 | "message": "Forum mod", 20 | "description": "Link to options page in user dropdown menu. Probably no translation needed? Decide depending on language" 21 | }, 22 | "dismiss": { 23 | "message": "Bỏ qua", 24 | "description": "Dismisses community notifications" 25 | }, 26 | "emoticons": { 27 | "message": "Bộ chọn biểu tượng cảm xúc", 28 | "description": "Title of formatting item for emote picker" 29 | }, 30 | "header": { 31 | "message": "Tiêu đề", 32 | "description": "Title of formatting item header 1" 33 | }, 34 | "horizontal_line": { 35 | "message": "Đường ngang", 36 | "description": "Title of formatting item horizontal rule" 37 | }, 38 | "block_quote": { 39 | "message": "Trích dẫn", 40 | "description": "Title of formatting item quote" 41 | }, 42 | "inline_code": { 43 | "message": "Mã nội tuyến", 44 | "description": "Title of formatting item fixed width font" 45 | }, 46 | "table": { 47 | "message": "Bảng", 48 | "description": "Title of formatting item table" 49 | }, 50 | "number_list": { 51 | "message": "Danh sách đánh số", 52 | "description": "Title of formatting item numbered list" 53 | }, 54 | "spoiler": { 55 | "message": "Spoiler", 56 | "description": "Title of formatting item spoiler" 57 | }, 58 | "customToolbarTitle": { 59 | "message": "Chỉnh sửa thanh công cụ tùy chỉnh", 60 | "description": "Title of custom toolbar editor" 61 | }, 62 | "dragText": { 63 | "message": "Nhấp và kéo để di chuyển", 64 | "description": "Hover text when on a draggable area" 65 | }, 66 | "themes": { 67 | "message": "Chủ đề", 68 | "description": "Options: Title of themes section" 69 | }, 70 | "modifications": { 71 | "message": "Chỉnh sửa", 72 | "description": "Options: Title of modifications section" 73 | }, 74 | "info": { 75 | "message": "Thông tin", 76 | "description": "Options: Title of info section" 77 | }, 78 | "feedback": { 79 | "message": "Phản hồi", 80 | "description": "Options: Feedback link in navigation" 81 | }, 82 | "schedule": { 83 | "message": "Lịch trình", 84 | "description": "Options: Schedule headline" 85 | }, 86 | "themeMachine": { 87 | "message": "Máy chủ đề", 88 | "description": "Options: Theme machine headline" 89 | }, 90 | "background": { 91 | "message": "Mặt nền", 92 | "description": "Options: Theme machine edit background" 93 | }, 94 | "foreground": { 95 | "message": "Mặt nổi", 96 | "description": "Options: Theme machine edit foreground" 97 | }, 98 | "highlight": { 99 | "message": "Nổi bật", 100 | "description": "Options: Theme machine edit highlight" 101 | }, 102 | "accent": { 103 | "message": "Màu nhấn", 104 | "description": "Options: Theme machine edit accent" 105 | }, 106 | "link": { 107 | "message": "Liên kết", 108 | "description": "Options: Theme machine edit link" 109 | }, 110 | "code": { 111 | "message": "Mã", 112 | "description": "Options: Theme machine edit code" 113 | }, 114 | "dropdown": { 115 | "message": "Thả xuống", 116 | "description": "Options: Theme machine edit dropdown" 117 | }, 118 | "selectModifications": { 119 | "message": "Chọn chỉnh sửa", 120 | "description": "Options: Modifications headline" 121 | }, 122 | "advancedFormatting": { 123 | "message": "Định dạng nâng cao", 124 | "description": "Options: Title of advanced formatting mod" 125 | }, 126 | "advancedFormattingDesc": { 127 | "message": "Thêm một bộ chọn biểu tượng cảm xúc và các nút định dạng bổ sung. Cho phép bạn kéo để sắp xếp lại, xóa khỏi và thêm vào thanh công cụ định dạng khi chỉnh sửa bài đăng trên diễn đàn của bạn.", 128 | "description": "Options: Description of the advanced formatting mod" 129 | }, 130 | "hideHeader": { 131 | "message": "Tự động ẩn tiêu đề khi cuộn", 132 | "description": "Options: Title of auto-hide header on scroll mod" 133 | }, 134 | "hideHeaderDesc": { 135 | "message": "Ẩn tiêu đề khi bạn cuộn xuống, hiển thị nó khi bạn cuộn lên.", 136 | "description": "Options: Description of auto-hide header on scroll mod" 137 | }, 138 | "navbookmarks": { 139 | "message": "Dấu trang trong thanh điều hướng", 140 | "description": "Options: Title of bookmarks in navigation mod" 141 | }, 142 | "navbookmarksDesc": { 143 | "message": "Hiển thị một liên kết đến trang dấu trang trong thanh điều hướng chính để dễ dàng truy cập.", 144 | "description": "Options: Description of bookmarks in navigation mod" 145 | }, 146 | "compactPosts": { 147 | "message": "Bài viết nhỏ gọn", 148 | "description": "Options: Title of compact posts mod" 149 | }, 150 | "compactPostsDesc": { 151 | "message": "Loại bỏ lề giữa tên người dùng và nội dung. Có thể làm vỡ bố cục.", 152 | "description": "Options: Description of compact posts mod" 153 | }, 154 | "customNotification": { 155 | "message": "Biểu tượng thông báo tùy chỉnh", 156 | "description": "Options: Title of custom notification icons mod" 157 | }, 158 | "customNotificationDesc": { 159 | "message": "Hiển thị các phông chữ biểu tượng trong danh sách thông báo thả xuống của đầu trang để nhanh chóng phân biệt một loại thông báo này với loại thông báo khác.", 160 | "description": "Options: Description of custom notification icons mod" 161 | }, 162 | "showUID": { 163 | "message": "Hiển thị các ID người dùng", 164 | "description": "Options: Title of show user IDs mod" 165 | }, 166 | "showUIDDesc": { 167 | "message": "Hiển thị các ID người dùng khi di chuột vào tên người dùng ở đầu bài đăng và khi di chuột vào hình đại diện của người dùng trên hồ sơ của họ.", 168 | "description": "Options: Description of show user IDs mod" 169 | }, 170 | "systemEmoji": { 171 | "message": "Sử dụng biểu tượng cảm xúc hệ thống", 172 | "description": "Options: Title of use system emoji mod" 173 | }, 174 | "systemEmojiDesc": { 175 | "message": "Sử dụng phông chữ biểu tượng cảm xúc do hệ điều hành cung cấp thay vì biểu tượng cảm xúc của diễn đàn Vivaldi.", 176 | "description": "Options: Description of use system emoji mod" 177 | }, 178 | "signatureMod": { 179 | "message": "Chữ ký mod", 180 | "description": "Options: Title of signature mod" 181 | }, 182 | "signatureModDesc": { 183 | "message": "Ẩn tất cả chữ ký và thay thế mỗi chữ ký bằng một nút. Khi nhấp vào, chữ ký của từng bài đăng sẽ được hiển thị.", 184 | "description": "Options: Description of signature mod" 185 | }, 186 | "squareAvatars": { 187 | "message": "Hình đại diện vuông", 188 | "description": "Options: Title of square avatars mod" 189 | }, 190 | "squareAvatarsDesc": { 191 | "message": "Hình đại diện vuông ở khắp mọi nơi!", 192 | "description": "Options: Description of square avatars mod" 193 | }, 194 | "userCSS": { 195 | "message": "CSS người dùng", 196 | "description": "Options: User CSS headline" 197 | }, 198 | "userCSSDesc": { 199 | "message": "Chỉ nhập mã CSS! Nhấp vào công tắc để kích hoạt/ngừng kích hoạt. LƯU để lưu vào bộ nhớ. Chọn tiêu chuẩn trong chủ đề, nếu bạn muốn chạy chủ đề của riêng mình.", 200 | "description": "Options: User CSS placeholder/description" 201 | }, 202 | "changelog": { 203 | "message": "Ghi chú thay đổi", 204 | "description": "Options: Changelog headline" 205 | }, 206 | "credits": { 207 | "message": "Tín dụng", 208 | "description": "Options: Credits headline" 209 | }, 210 | "save": { 211 | "message": "Lưu", 212 | "description": "Options: Text to show on a button that performs some sort of save operation" 213 | }, 214 | "edit": { 215 | "message": "Sửa", 216 | "description": "Options: Text to show on a button that performs some sort of edit operation" 217 | }, 218 | "import": { 219 | "message": "Nhập", 220 | "description": "Options: Text to show on a button that performs some sort of import operation" 221 | }, 222 | "cancel": { 223 | "message": "Hủy bỏ", 224 | "description": "Options: Text to show on a button that performs some sort of cancel operation" 225 | }, 226 | "export": { 227 | "message": "Xuất", 228 | "description": "Options: Text to show on a button that performs some sort of export operation." 229 | }, 230 | "reset": { 231 | "message": "Đặt lại", 232 | "description": "Options: Text to show on a button that performs some sort of reset operation" 233 | }, 234 | "confirmReset": { 235 | "message": "Đặt lại phần mở rộng? Nhấn một lần nữa để xác nhận", 236 | "description": "Options: Status message to confirm reset" 237 | }, 238 | "cancelReset": { 239 | "message": "Đặt lại đã hủy", 240 | "description": "Options: Status message after cancelled reset" 241 | }, 242 | "cancelImport": { 243 | "message": "Nhập đã hủy", 244 | "description": "Options: Status message after cancelled import" 245 | }, 246 | "optionsReset": { 247 | "message": "Các tùy chọn đặt lại, lưu trữ đã xóa", 248 | "description": "Options: Status message after reset" 249 | }, 250 | "activateSchedule": { 251 | "message": "Lịch trình đã kích hoạt", 252 | "description": "Options: Status message for Schedule activation" 253 | }, 254 | "deactivateSchedule": { 255 | "message": "Lịch trình đã ngừng kích hoạt", 256 | "description": "Options: Status message for Schedule deactivation" 257 | }, 258 | "activateUserCSS": { 259 | "message": "CSS người dùng đã kích hoạt", 260 | "description": "Options: Status message for User CSS activation" 261 | }, 262 | "deactivateUserCSS": { 263 | "message": "CSS người dùng đã ngừng kích hoạt", 264 | "description": "Options: Status message for User CSS deactivation" 265 | }, 266 | "saveUserCSS": { 267 | "message": "CSS người dùng được lưu vào bộ lưu trữ", 268 | "description": "Options: Status message for saving User CSS to storage" 269 | }, 270 | "saveTheme": { 271 | "message": "Chủ đề đã lưu và kích hoạt", 272 | "description": "Options: Status message for theme activation" 273 | }, 274 | "exportTheme": { 275 | "message": "Mã chủ đề đã sao chép vào bộ nhớ tạm", 276 | "description": "Options: Status message for exporting theme" 277 | }, 278 | "importThemeDesc": { 279 | "message": "Dán hoặc kéo và thả mã chủ đề vào trường nhập", 280 | "description": "Options: Status message describing theme import" 281 | }, 282 | "importTheme": { 283 | "message": "Chủ đề đã nhập. Nhấp vào LƯU để lưu chủ đề", 284 | "description": "Options: Status message confirming theme import" 285 | }, 286 | "statusThemes": { 287 | "message": "Chọn, tạo và lập lịch trình chủ đề", 288 | "description": "Options: Status message themes" 289 | }, 290 | "statusModifications": { 291 | "message": "Bật tắt các chỉnh sửa và viết CSS tùy chỉnh", 292 | "description": "Options: Status message modifications" 293 | }, 294 | "statusInfo": { 295 | "message": "Xin chân thành cảm ơn tất cả những cộng tác viên và những người dùng!", 296 | "description": "Options: Status message info" 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /default.css: -------------------------------------------------------------------------------- 1 | /* Default fixes, improvements and modifications for all themes */ 2 | 3 | /* Font icons */ 4 | .fa-angle-down::before { 5 | content: "\f0d7" !important; 6 | } 7 | .fa-angle-up::before { 8 | content: "\f0d8" !important; 9 | } 10 | #search-form .fa.fa-gears::before { 11 | content: "\f00e" !important; 12 | } 13 | 14 | /* Advanced search panel cursor */ 15 | #advanced-search .panel-default > .panel-heading:hover { 16 | cursor: pointer; 17 | } 18 | 19 | /* Threaded replies cleanup */ 20 | a.threaded-replies.no-select span.replies-last.hidden-xs { 21 | display: none; 22 | } 23 | 24 | /* Reduces the number of font sizes used in posts */ 25 | .topic .threaded-replies, 26 | small.pull-left, 27 | .topic span.timeago, 28 | .post-signature, 29 | blockquote { 30 | font-size: 13px !important; 31 | } 32 | 33 | /* Correct cursor over vote count span (clickable) */ 34 | .pull-right .votes span { 35 | cursor: pointer; 36 | } 37 | 38 | /* Blockquote search fontsize/margin fix */ 39 | .search blockquote { 40 | font-size: 100%; 41 | margin: 8px 0; 42 | padding: 0 10px; 43 | } 44 | 45 | /* Line breaks for code in topics (no horizontal scroll) */ 46 | .topic .posts .content pre code { 47 | white-space: pre-wrap !important; 48 | } 49 | 50 | /* Code vertical scrollbar from markdown to hljs */ 51 | .topic .posts .content pre { 52 | max-height: unset !important; 53 | } 54 | .markdown-highlight .hljs { 55 | max-height: 350px; 56 | } 57 | 58 | /* Disabled user-select for logged-in menu (prevents accidental highlighting of dropdown text when dropdown isn't expanded) */ 59 | #logged-in-menu.nav.navbar-nav.navbar-right { 60 | user-select: none; 61 | } 62 | 63 | /* Position status circles in user menu */ 64 | a[component="header/profilelink"] i, 65 | .user-status i { 66 | vertical-align: unset !important; 67 | } 68 | 69 | /* Alert margin on Unread page */ 70 | #new-topics-alert { 71 | margin-top: 0 !important; 72 | } 73 | 74 | /* Copy all code button */ 75 | .copy-all-code-button { 76 | position: absolute; 77 | right: 25px; 78 | font-weight: bold; 79 | opacity: 0; 80 | padding: 4px; 81 | border: none; 82 | border-radius: 2px; 83 | outline: none; 84 | } 85 | .markdown-highlight 86 | code[data-theme-preview-checked="true"] 87 | + .copy-all-code-button { 88 | display: none; 89 | } 90 | .markdown-highlight:hover .copy-all-code-button, 91 | .copy-all-code-button:hover { 92 | opacity: 1; 93 | } 94 | 95 | /* theme preview mod */ 96 | .theme-preview .themebox { 97 | display: inline-block; 98 | margin: 15px 15px 5px 0; 99 | vertical-align: top; 100 | width: 110px; 101 | } 102 | .theme-preview .themebox .themebox-image svg { 103 | width: 100%; 104 | height: auto; 105 | } 106 | .theme-preview .themebox .themebox-title { 107 | text-align: center; 108 | font-weight: 700; 109 | white-space: normal; 110 | overflow: hidden; 111 | text-overflow: ellipsis; 112 | } 113 | 114 | /* Easter egg - Based off of https://codepen.io/aybukeceylan/pen/MWYEoXZ */ 115 | .vfm-snow { 116 | position: fixed; 117 | top: 0; 118 | z-index: 3; 119 | width: 100%; 120 | height: 100%; 121 | pointer-events: none; 122 | } 123 | .vfm-snow .vfm-flake { 124 | position: absolute; 125 | background: #fff; 126 | border-radius: 50%; 127 | animation-name: snow-fall, snow-shake; 128 | animation-duration: 12s, 4s; 129 | animation-timing-function: linear, ease-in-out; 130 | animation-iteration-count: infinite, infinite; 131 | } 132 | @keyframes snow-fall { 133 | 0% { 134 | top: -10%; 135 | } 136 | 100% { 137 | top: 100%; 138 | } 139 | } 140 | @keyframes snow-shake { 141 | 0% { 142 | transform: translateX(0px); 143 | } 144 | 50% { 145 | transform: translateX(60px); 146 | } 147 | 100% { 148 | transform: translateX(0px); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /default.js: -------------------------------------------------------------------------------- 1 | // Header 2 | 3 | function header() { 4 | document.getElementById("vlogo").innerHTML = ` 5 | 6 | 7 | 8 | 9 | 13 | 14 | `; 15 | document.getElementById("vivaldimenu").innerHTML = ` 16 |
  • News
  • 17 |
  • Community
  • 18 |
  • Forum
  • 19 |
  • Help
  • 20 |
  • Themes
  • 21 |
  • Webmail
  • 22 | `; 23 | const links = document.querySelectorAll("#submenu li > a"); 24 | links.forEach((link) => link.title = ""); 25 | } 26 | 27 | // Get the username 28 | 29 | function username() { 30 | const user = document 31 | .querySelector('#user-control-list [component="header/username"]') 32 | .innerHTML.toLowerCase() 33 | .replace(/\./g, "-"); 34 | return user; 35 | } 36 | 37 | // Menu entry for options page 38 | 39 | function userMenu() { 40 | const dropdown = document.querySelector("#user-control-list.dropdown-menu"); 41 | if (dropdown) { 42 | const options = document.createElement("li"); 43 | options.classList.add("optionsLink"); 44 | options.style = "cursor: pointer"; 45 | options.innerHTML = ` ${chrome.i18n.getMessage( 46 | "optionsLink" 47 | )} `; 48 | dropdown.insertBefore(options, dropdown.childNodes[20]); 49 | document.querySelector(".optionsLink").addEventListener("click", () => { 50 | chrome.runtime.sendMessage({ message: "options pls" }); 51 | }); 52 | } 53 | } 54 | 55 | // Copy all code button 56 | 57 | function make_copy_button() { 58 | const new_button = document.createElement("button"); 59 | new_button.textContent = chrome.i18n.getMessage("copyCode"); 60 | new_button.className = "copy-all-code-button"; 61 | new_button.addEventListener("click", copy_all); 62 | return new_button; 63 | } 64 | 65 | function copy_all(event) { 66 | const code_node = event.currentTarget.parentElement.querySelector("code"); 67 | const window_selection = window.getSelection(); 68 | const code_range = document.createRange(); 69 | code_range.selectNodeContents(code_node); 70 | window_selection.removeAllRanges(); 71 | window_selection.addRange(code_range); 72 | document.execCommand("copy"); 73 | } 74 | 75 | function add_copy_code() { 76 | setTimeout(() => { 77 | const topic = document.querySelector(".topic"); 78 | if (topic) { 79 | const codeblocks = document.querySelectorAll("pre.markdown-highlight"); 80 | codeblocks.forEach((codeblock) => { 81 | if ( 82 | codeblock.classList.contains("copy") === false && 83 | codeblock.firstChild.classList.contains("hljs") === true 84 | ) { 85 | codeblock.style.position = "relative"; 86 | codeblock.classList.add("copy"); 87 | codeblock.insertBefore(make_copy_button(), codeblock.lastChild); 88 | } 89 | }); 90 | } 91 | }, 2000); 92 | } 93 | 94 | // Link and signature button for post tools 95 | 96 | function toolaction(e, o) { 97 | if (e.target.classList.contains("vfm-link")) { 98 | const pid = o.getAttribute("data-pid"); 99 | const copy = `https://forum.vivaldi.net/post/${pid}`; 100 | navigator.clipboard.writeText(copy); 101 | e.target.classList.add("vfm-highlight"); 102 | setTimeout(() => e.target.classList.remove("vfm-highlight"), 3333); 103 | } else { 104 | o.style.display = "block"; 105 | e.target.style.textDecoration = "none"; 106 | e.target.style.cursor = "default"; 107 | } 108 | } 109 | 110 | function tools(s) { 111 | const topic = document.querySelector(".topic"); 112 | if (topic) { 113 | const tools = Array.from(topic.getElementsByClassName("post-tools")); 114 | const transLink = chrome.i18n.getMessage("link"); 115 | const transSign = chrome.i18n.getMessage("signature"); 116 | tools.forEach((tool) => { 117 | const post = tool.parentNode.parentNode.parentNode.parentNode; 118 | if ( 119 | !tool.classList.contains("vfm-tools") && 120 | !post.classList.contains("deleted") 121 | ) { 122 | const link = document.createElement("a"); 123 | link.innerHTML = transLink; 124 | link.classList.add("no-select", "vfm-link"); 125 | tool.appendChild(link); 126 | const hlp1 = (event) => toolaction(event, post); 127 | link.addEventListener("click", hlp1); 128 | if (s === "on") { 129 | const sig = tool.parentNode.parentNode.previousElementSibling; 130 | if (sig !== null && sig.classList.contains("post-signature")) { 131 | const sign = document.createElement("a"); 132 | sign.innerHTML = transSign; 133 | sign.classList.add("no-select", "vfm-sign"); 134 | tool.appendChild(sign); 135 | const hlp2 = (event) => toolaction(event, sig); 136 | sign.addEventListener("click", hlp2); 137 | } 138 | } 139 | tool.classList.add("vfm-tools"); 140 | } 141 | }); 142 | } 143 | } 144 | 145 | // Unofficial Discord and Contribute link in footer 146 | 147 | function discord() { 148 | document.querySelector(".footerlinks").innerHTML += 149 | ' | Contribute | Discord'; 150 | } 151 | 152 | // Easter egg 153 | 154 | // https://stackoverflow.com/a/45736131/12275656 155 | function genRand(min, max, decimalPlaces) { 156 | const rand = Math.random() * (max - min) + min; 157 | const power = Math.pow(10, decimalPlaces); 158 | return Math.floor(rand * power) / power; 159 | } 160 | 161 | function genSnowFlake() { 162 | const size = genRand(4, 8, 0); 163 | const flake = ` 164 |
    172 | `; 173 | return flake; 174 | } 175 | 176 | function loadEasterEgg(numFlakes) { 177 | const del = document.querySelector(".vfm-snow"); 178 | if (del) del.parentNode.removeChild(del); 179 | const snow = document.createElement("div"); 180 | snow.setAttribute("class", "vfm-snow"); 181 | let flakes = ""; 182 | for (let i = 0; i < numFlakes; i++) { 183 | flakes += genSnowFlake(); 184 | } 185 | snow.innerHTML = flakes; 186 | document.body.prepend(snow); 187 | } 188 | 189 | function checkInput(e, el) { 190 | if (e.key === "Enter") { 191 | const input = el.value.replace(/\s+/g, "").toLowerCase(); 192 | if (input.includes("letitsnow")) { 193 | let num; 194 | try { 195 | num = parseInt(input.match(/\d/g).join("")); 196 | } catch (e) { 197 | num = 90; 198 | } 199 | if (num > 0 && num < 1000) loadEasterEgg(num); 200 | else loadEasterEgg(90); 201 | } 202 | } 203 | } 204 | 205 | function easterEgg() { 206 | const input = document.querySelector("#search-form .form-control"); 207 | const bunny = (event) => checkInput(event, input); 208 | input.addEventListener("keydown", bunny); 209 | } 210 | -------------------------------------------------------------------------------- /icons/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vfm-org/vivaldi-forum-mod/79d212519024d7702a8205c64a2275bb46e86ef5/icons/icon128.png -------------------------------------------------------------------------------- /icons/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vfm-org/vivaldi-forum-mod/79d212519024d7702a8205c64a2275bb46e86ef5/icons/icon16.png -------------------------------------------------------------------------------- /icons/icon24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vfm-org/vivaldi-forum-mod/79d212519024d7702a8205c64a2275bb46e86ef5/icons/icon24.png -------------------------------------------------------------------------------- /icons/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vfm-org/vivaldi-forum-mod/79d212519024d7702a8205c64a2275bb46e86ef5/icons/icon48.png -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "Vivaldi Forum mod", 4 | "short_name": "VF mod", 5 | "version": "5.0", 6 | "author": "luetage", 7 | "description": "Modular extension. Themes, fixes and modifications.", 8 | "homepage_url": "https://github.com/luetage/vivaldi_forum_mod", 9 | "icons": { 10 | "48": "icons/icon48.png", 11 | "128": "icons/icon128.png" 12 | }, 13 | "permissions": ["storage", "alarms"], 14 | "options_ui": { 15 | "page": "options/options.html", 16 | "open_in_tab": true 17 | }, 18 | "web_accessible_resources": [ 19 | { 20 | "resources": [ 21 | "themes/custom.css", 22 | "themes/vivaldi-light.css", 23 | "themes/vivaldi-dark.css", 24 | "mods/advanced-formatting.css", 25 | "mods/compact-posts.css", 26 | "mods/header-scroll.css", 27 | "mods/notification-icons.css", 28 | "mods/signature-mod.css", 29 | "mods/square-avatars.css", 30 | "mods/userID.css", 31 | "icons/icon16.png" 32 | ], 33 | "matches": ["https://forum.vivaldi.net/*"], 34 | "exclude_matches": [ 35 | "https://forum.vivaldi.net/assets/*", 36 | "https://forum.vivaldi.net/uploads/*", 37 | "https://forum.vivaldi.net/plugins/*" 38 | ] 39 | } 40 | ], 41 | "content_scripts": [ 42 | { 43 | "matches": ["https://forum.vivaldi.net/*"], 44 | "exclude_matches": [ 45 | "https://forum.vivaldi.net/assets/*", 46 | "https://forum.vivaldi.net/uploads/*", 47 | "https://forum.vivaldi.net/plugins/*" 48 | ], 49 | "js": ["theme.js"], 50 | "run_at": "document_start" 51 | }, 52 | { 53 | "matches": ["https://forum.vivaldi.net/*"], 54 | "exclude_matches": [ 55 | "https://forum.vivaldi.net/assets/*", 56 | "https://forum.vivaldi.net/uploads/*", 57 | "https://forum.vivaldi.net/plugins/*" 58 | ], 59 | "js": [ 60 | "mods/advanced-formatting.js", 61 | "mods/theme-preview.js", 62 | "default.js", 63 | "mods.js" 64 | ], 65 | "css": ["default.css"], 66 | "run_at": "document_end" 67 | } 68 | ], 69 | "background": { 70 | "service_worker": "serviceworker.js" 71 | }, 72 | "default_locale": "en" 73 | } 74 | -------------------------------------------------------------------------------- /mods.js: -------------------------------------------------------------------------------- 1 | // Modifications 2 | // Use system emoji 3 | 4 | function undoMoji(img) { 5 | const rawEmojiSequence = Array.from(img.alt); 6 | var emojidom = document.createElement("span"); 7 | emojidom.className = "vm-emoji"; 8 | emojidom.title = img.title; 9 | // adds in joiner character \u200D to correctly stich together emoji sequences 10 | // the location of joiner is dependent on number of emoji in the sequence 11 | let text = ""; 12 | const len = rawEmojiSequence.length; 13 | switch (len) { 14 | case 2: 15 | // skin tones break if joined with \u200D, but plain emoji need to be joined 16 | if ( 17 | /light_skin|medium-light_skin|medium_skin|medium-dark_skin|dark_skin/.test( 18 | img.title 19 | ) 20 | ) { 21 | text = rawEmojiSequence.reduce((prev, curr) => prev + curr); 22 | } else { 23 | text = rawEmojiSequence[0] + "\u200D" + rawEmojiSequence[1]; 24 | } 25 | break; 26 | case 3: 27 | text = 28 | rawEmojiSequence[0] + 29 | rawEmojiSequence[1] + 30 | "\u200D" + 31 | rawEmojiSequence[2]; 32 | break; 33 | case 4: 34 | text = 35 | rawEmojiSequence[0] + 36 | rawEmojiSequence[1] + 37 | "\u200D" + 38 | rawEmojiSequence[2] + 39 | rawEmojiSequence[3]; 40 | break; 41 | default: 42 | text = rawEmojiSequence.reduce((prev, curr) => prev + curr); 43 | break; 44 | } 45 | emojidom.innerText = text; 46 | img.insertAdjacentElement("beforebegin", emojidom); 47 | var post = img.parentElement; 48 | post.removeChild(img); 49 | } 50 | 51 | function checkMoji() { 52 | let allEmoji = Array.from( 53 | document.querySelectorAll( 54 | "img.emoji:not(#emoji-dialog img.emoji):not(.emoji-vivaldi)" 55 | ) 56 | ); 57 | // emoji indicating sex are always separated into an independent img from the 58 | // base emoji in a sequence. this adds the sex indicator emoji to the previous 59 | // img's alt text and adjusts the title to match 60 | let last = null; 61 | allEmoji = allEmoji.reduce((prev, curr) => { 62 | let next = last 63 | ? last.nextSibling 64 | ? last.nextSibling 65 | : { textContent: "false" } 66 | : { textContent: "false" }; 67 | // when an emoji isn't part of a sequence, it doesn't need to be altered 68 | if (last == null || next.textContent !== "\u200d") { 69 | prev.push(curr); 70 | } else { 71 | // if an emoji is determined to be the 2nd or greater emoji of a sequence, 72 | //it needs to be added back to the 1st emoji of the sequence 73 | let previousEmoji = prev[prev.length - 1]; 74 | const sex = curr.title.includes("female") ? "woman" : "man"; 75 | previousEmoji.alt = previousEmoji.alt + curr.alt; 76 | previousEmoji.title = previousEmoji.title.replace("person", sex); 77 | const post = curr.parentElement; 78 | post.removeChild(curr); 79 | } 80 | last = curr; 81 | return prev; 82 | }, []); 83 | allEmoji.forEach(undoMoji); 84 | } 85 | 86 | // Auto-hide header on scroll 87 | 88 | function autoScroll() { 89 | if (_scp > window.scrollY) { 90 | _vivaldiHeader.style.top = "0px"; 91 | _subMenu.style.top = _top + "px"; 92 | } else if (window.scrollY <= _top) { 93 | _vivaldiHeader.style.top = "0px"; 94 | _subMenu.style.top = _top + "px"; 95 | } else if (window.scrollY > _top) { 96 | _vivaldiHeader.style = __top; 97 | _subMenu.style = "top: 0px !important"; 98 | } 99 | _scp = window.scrollY; 100 | } 101 | 102 | // Bookmarks in navigation 103 | 104 | function _bookmarks() { 105 | const nav = document.querySelector("#submenu ul"); 106 | const li = document.createElement("li"); 107 | const link = document.createElement("a"); 108 | link.classList.add("navigation-link"); 109 | link.href = "/user/" + username() + "/bookmarks"; 110 | link.setAttribute("title", ""); 111 | link.innerHTML = ` ${chrome.i18n.getMessage( 112 | "bookmarks" 113 | )} `; 114 | nav.insertBefore(li, nav.lastChild); 115 | li.appendChild(link); 116 | } 117 | 118 | chrome.storage.sync.get({ VFM_MODS: "" }, (get) => { 119 | const mods = get.VFM_MODS; 120 | console.log(mods); 121 | if (mods.compactPosts === true) loadFile("mods/compact-posts.css"); 122 | if (mods.notificationIcons === true) loadFile("mods/notification-icons.css"); 123 | if (mods.userID === true) loadFile("mods/userID.css"); 124 | if (mods.square === true) loadFile("mods/square-avatars.css"); 125 | if (mods.signatureMod === true) loadFile("mods/signature-mod.css"); 126 | if (mods.advancedFormatting === true) 127 | loadFile("mods/advanced-formatting.css"); 128 | if (mods.bookmarks === true) _bookmarks(); 129 | if (mods.headerScroll === true) { 130 | _top = 64; 131 | __top = "top: -64px !important"; 132 | _scp = 0; 133 | _vivaldiHeader = document.getElementById("vivaldi-header"); 134 | _subMenu = document.getElementById("submenu"); 135 | window.addEventListener("scroll", autoScroll); 136 | loadFile("mods/header-scroll.css"); 137 | } 138 | let startmods = (mutations) => { 139 | mutations.forEach((mutation) => { 140 | if (mutation.addedNodes.length || mutation.removedNodes.length) { 141 | add_copy_code(); 142 | themePreview(content); 143 | let signature; 144 | if (mods.signatureMod === true) signature = "on"; 145 | else signature = "off"; 146 | tools(signature); 147 | if (mods.systemEmoji === true) checkMoji(); 148 | } 149 | }); 150 | }; 151 | new MutationObserver(startmods).observe(document.getElementById("body"), { 152 | childList: true, 153 | subtree: true, 154 | }); 155 | }); 156 | 157 | header(); 158 | userMenu(); 159 | discord(); 160 | easterEgg(); 161 | -------------------------------------------------------------------------------- /mods/advanced-formatting.css: -------------------------------------------------------------------------------- 1 | /* Style modal boxes */ 2 | .vivaldi-mod-modal-box { 3 | position: fixed; 4 | z-index: 9999999999; 5 | width: 250px; 6 | padding: 5px; 7 | grid-template-columns: 20fr 20fr 20fr 20fr 20fr; 8 | grid-row-gap: 5px; 9 | border-width: 5px; 10 | border-style: solid; 11 | border-radius: 4px; 12 | box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2); 13 | } 14 | 15 | .vivaldi-mod-modal-box-control-bar { 16 | grid-column: 1 / 5; 17 | place-self: stretch; 18 | cursor: move; 19 | border-radius: 4px 0px 0px 4px; 20 | text-align: center; 21 | } 22 | 23 | .vivaldi-mod-modal-box-close { 24 | border: none; 25 | border-radius: 0px 4px 4px 0px; 26 | } 27 | 28 | /* Style emote picker */ 29 | #emote-picker img { 30 | cursor: pointer; 31 | place-self: center; 32 | } 33 | 34 | #emote-picker-button:focus:not(:hover) { 35 | background: transparent; 36 | } 37 | 38 | /* Style dropzone indicator */ 39 | .dropmarker { 40 | display: block; 41 | width: 5px; 42 | height: 35px; 43 | position: fixed; 44 | z-index: 9999999999; 45 | pointer-events: none; 46 | } 47 | 48 | .dropmarker:before { 49 | content: ""; 50 | width: 8px; 51 | height: 8px; 52 | display: block; 53 | position: absolute; 54 | border-style: solid; 55 | border-width: 0px 3px 3px 0px; 56 | left: -2.5px; 57 | top: -13px; 58 | } 59 | 60 | .dropmarker:after { 61 | content: ""; 62 | width: 2px; 63 | height: 12px; 64 | display: block; 65 | position: absolute; 66 | transform: rotate(-45deg); 67 | left: -1px; 68 | top: -17px; 69 | } 70 | 71 | /* style hidden items modal */ 72 | 73 | #toolbar-custom ul { 74 | grid-column: 1 / 6; 75 | place-self: stretch; 76 | display: grid; 77 | grid-template-columns: 20fr 20fr 20fr 20fr 20fr; 78 | grid-row-gap: 5px; 79 | list-style: none; 80 | padding-left: 0px; 81 | } 82 | 83 | #toolbar-custom ul li { 84 | place-self: stretch; 85 | display: flex; 86 | justify-content: center; 87 | align-items: center; 88 | padding: 5px; 89 | cursor: pointer; 90 | } 91 | -------------------------------------------------------------------------------- /mods/compact-posts.css: -------------------------------------------------------------------------------- 1 | /* Get rid of the margin between user name and content */ 2 | 3 | .topic .content { 4 | clear: unset !important; 5 | margin-top: -40px !important; 6 | } 7 | @media (max-width: 991px) { 8 | .topic .content { 9 | margin-top: -10px !important; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /mods/header-scroll.css: -------------------------------------------------------------------------------- 1 | /* Auto-hide header transition */ 2 | 3 | #vivaldi-header, 4 | #submenu { 5 | transition: top 0.4s ease-out !important; 6 | } 7 | -------------------------------------------------------------------------------- /mods/notification-icons.css: -------------------------------------------------------------------------------- 1 | /* Custom notification icons */ 2 | 3 | .header .notification-list li[data-nid^="new_post"] .mark-read::after { 4 | content: "\f1d8"; 5 | } 6 | .header .notification-list li[data-nid^="edit_post"] .mark-read::after { 7 | content: "\f044"; 8 | } 9 | .header .notification-list li[data-nid^="upvote"] .mark-read::after { 10 | content: "\f164"; 11 | } 12 | .header .notification-list li[data-nid^="follow"] .mark-read::after { 13 | content: "\f06e"; 14 | } 15 | .header .notification-list li[data-nid^="move"] .mark-read::after { 16 | content: "\f35a"; 17 | } 18 | .header .notification-list li[data-nid^="chat"] .mark-read::after { 19 | content: "\f0e0"; 20 | } 21 | /* mentions/new topics (no specific data-nid) */ 22 | .header .notification-list li[data-nid^="tid"] .mark-read::after { 23 | content: "\f4ad"; 24 | } 25 | -------------------------------------------------------------------------------- /mods/signature-mod.css: -------------------------------------------------------------------------------- 1 | /* 2 | Disables Signatures 3 | The function for showing the signature buttons can be found in mods.js, 4 | this is merely a fallback. 5 | */ 6 | 7 | .topic .post-signature { 8 | display: none; 9 | } 10 | -------------------------------------------------------------------------------- /mods/square-avatars.css: -------------------------------------------------------------------------------- 1 | /* Square avatars everywhere! */ 2 | 3 | .avatar.pull-left .user-icon, avatar.pull-left img, .user-img, .user-icon.user-img, .topic .posts .icon .user-icon, .topic .posts .icon img, .dropdown-toggle img, .message-header img, .message-header .user-icon, .users-container .user-icon, .users-container img, .avatar.avatar-rounded, .categories > li .content .icon, .category > ul > li .content .icon, .account .cover .avatar-wrapper { 4 | border-radius: 5px !important; 5 | } 6 | .icon.pull-left i.fa.fa-circle, .cover i.fa.fa-circle { 7 | display: none; 8 | } 9 | -------------------------------------------------------------------------------- /mods/theme-preview.js: -------------------------------------------------------------------------------- 1 | // Theme Preview 2 | 3 | function tryParseJSON(jsonString) { 4 | try { 5 | var o = JSON.parse(jsonString); 6 | if (o && typeof o === "object") { 7 | return o; 8 | } 9 | } catch (e) {} 10 | return false; 11 | } 12 | 13 | function checkThemeForum(theme) { 14 | if ( 15 | typeof theme.themeName !== "string" || 16 | typeof theme.colorBg !== "string" || 17 | !/^#(?:[0-9a-f]{3}){1,2}$/i.test(theme.colorBg) || 18 | typeof theme.colorFg !== "string" || 19 | !/^#(?:[0-9a-f]{3}){1,2}$/i.test(theme.colorFg) || 20 | typeof theme.colorHi !== "string" || 21 | !/^#(?:[0-9a-f]{3}){1,2}$/i.test(theme.colorHi) || 22 | typeof theme.colorAc !== "string" || 23 | !/^#(?:[0-9a-f]{3}){1,2}$/i.test(theme.colorAc) || 24 | typeof theme.colorLi !== "string" || 25 | !/^#(?:[0-9a-f]{3}){1,2}$/i.test(theme.colorLi) || 26 | typeof theme.colorCo !== "string" || 27 | !/^#(?:[0-9a-f]{3}){1,2}$/i.test(theme.colorCo) || 28 | typeof theme.colorDd !== "string" || 29 | !/^#(?:[0-9a-f]{3}){1,2}$/i.test(theme.colorDd) 30 | ) { 31 | return false; 32 | } else { 33 | return true; 34 | } 35 | } 36 | 37 | function shadeHexColor(color, percent) { 38 | var f = parseInt(color.slice(1), 16), 39 | t = percent < 0 ? 0 : 255, 40 | p = percent < 0 ? percent * -1 : percent, 41 | R = f >> 16, 42 | G = (f >> 8) & 0x00ff, 43 | B = f & 0x0000ff; 44 | return ( 45 | "#" + 46 | ( 47 | 0x1000000 + 48 | (Math.round((t - R) * p) + R) * 0x10000 + 49 | (Math.round((t - G) * p) + G) * 0x100 + 50 | (Math.round((t - B) * p) + B) 51 | ) 52 | .toString(16) 53 | .slice(1) 54 | ); 55 | } 56 | 57 | function htmlToElement(html) { 58 | var template = document.createElement("template"); 59 | template.innerHTML = html.trim(); 60 | return template.content.firstChild; 61 | } 62 | 63 | function createThemeForumImage(theme) { 64 | var themeForumImage = htmlToElement( 65 | '' 66 | ); 67 | themeForumImage.style.setProperty("--colorBg", theme.colorBg); 68 | themeForumImage.style.setProperty("--colorFg", theme.colorFg); 69 | themeForumImage.style.setProperty("--colorHi", theme.colorHi); 70 | themeForumImage.style.setProperty("--colorAc", theme.colorAc); 71 | themeForumImage.style.setProperty("--colorLi", theme.colorLi); 72 | themeForumImage.style.setProperty("--colorCo", theme.colorCo); 73 | themeForumImage.style.setProperty("--colorDd", theme.colorDd); 74 | return themeForumImage; 75 | } 76 | 77 | function createThemeBox(theme) { 78 | var themeboxImage = document.createElement("div"); 79 | themeboxImage.className = "themebox-image"; 80 | themeboxImage.appendChild(createThemeForumImage(theme)); 81 | var themeboxTitle = document.createElement("div"); 82 | themeboxTitle.className = "themebox-title"; 83 | themeboxTitle.innerHTML = theme.themeName; 84 | var themebox = document.createElement("div"); 85 | themebox.className = "themebox"; 86 | themebox.appendChild(themeboxImage); 87 | themebox.appendChild(themeboxTitle); 88 | return themebox; 89 | } 90 | 91 | function importForumTheme(e) { 92 | var target = e.target; 93 | while (!target.classList.contains("theme-preview")) { 94 | target = target.parentNode; 95 | } 96 | console.log(target.parentNode.firstChild.innerText); 97 | var code = JSON.parse(target.parentNode.firstChild.innerText.trim()); 98 | chrome.runtime.sendMessage({ theme: code }); 99 | } 100 | 101 | function createThemeForumPreview(theme, code) { 102 | var themePreview = document.createElement("div"); 103 | themePreview.className = "theme-preview"; 104 | themePreview.appendChild(createThemeBox(theme)); 105 | code.parentNode.insertBefore(themePreview, code.nextSibling); 106 | themePreview.previousSibling.style.display = "none"; 107 | var themebox = themePreview.firstChild; 108 | themebox.style.cursor = "pointer"; 109 | themebox.addEventListener("click", importForumTheme); 110 | } 111 | 112 | function themePreview(content) { 113 | var codes = content.querySelectorAll( 114 | 'code:not([data-theme-preview-checked="true"])' 115 | ); 116 | var theme; 117 | codes.forEach(function (code) { 118 | code.dataset.themePreviewChecked = true; 119 | if (!code.querySelector("code")) { 120 | if ((theme = tryParseJSON(code.innerText.trim()))) { 121 | if (checkThemeForum(theme)) { 122 | createThemeForumPreview(theme, code); 123 | } 124 | } 125 | } 126 | }); 127 | } 128 | -------------------------------------------------------------------------------- /mods/userID.css: -------------------------------------------------------------------------------- 1 | /* Displays user IDs on profiles and posts */ 2 | 3 | /* forum */ 4 | .clearfix.post-header small.pull-left strong a:hover::after { 5 | content: " [UID " attr(data-uid) "]"; 6 | } 7 | 8 | /* profiles */ 9 | .account .cover .avatar-wrapper::after { 10 | content: "UID " attr(data-uid); 11 | position: absolute; 12 | opacity: 0; 13 | width: 100%; 14 | text-align: center; 15 | margin-top: 135px; 16 | margin-left: -128px; 17 | transition: opacity 0.6s ease-out; 18 | font-size: 12px; 19 | font-weight: 500; 20 | } 21 | .account .cover .avatar-wrapper:hover::after { 22 | opacity: 0.8; 23 | } 24 | -------------------------------------------------------------------------------- /options/localisation.js: -------------------------------------------------------------------------------- 1 | function localisation() { 2 | //navigation 3 | document.getElementById("themes-btn").innerText = 4 | chrome.i18n.getMessage("themes"); 5 | document.getElementById("modifications-btn").innerText = 6 | chrome.i18n.getMessage("modifications"); 7 | document.getElementById("info-btn").innerText = 8 | chrome.i18n.getMessage("info"); 9 | document.getElementById("feedback-btn").innerText = 10 | chrome.i18n.getMessage("feedback"); 11 | document.getElementById("reset-btn").innerText = 12 | chrome.i18n.getMessage("reset"); 13 | 14 | //themes 15 | document.querySelector(".schedule").innerText = 16 | chrome.i18n.getMessage("schedule"); 17 | document.querySelector(".themeMachine").innerText = 18 | chrome.i18n.getMessage("themeMachine"); 19 | document.querySelector(".theme-edit").innerText = 20 | chrome.i18n.getMessage("edit"); 21 | document.querySelector(".theme-save").innerText = 22 | chrome.i18n.getMessage("save"); 23 | document.querySelector(".theme-import").innerText = 24 | chrome.i18n.getMessage("import"); 25 | document.querySelector(".theme-export").innerText = 26 | chrome.i18n.getMessage("export"); 27 | document.querySelector(".background").innerText = 28 | chrome.i18n.getMessage("background"); 29 | document.querySelector(".foreground").innerText = 30 | chrome.i18n.getMessage("foreground"); 31 | document.querySelector(".highlight").innerText = 32 | chrome.i18n.getMessage("highlight"); 33 | document.querySelector(".accent").innerText = 34 | chrome.i18n.getMessage("accent"); 35 | document.querySelector(".link").innerText = chrome.i18n.getMessage("link"); 36 | document.querySelector(".code").innerText = chrome.i18n.getMessage("code"); 37 | document.querySelector(".dropdown").innerText = 38 | chrome.i18n.getMessage("dropdown"); 39 | 40 | //modifications 41 | document.querySelector(".selectModifications").innerText = 42 | chrome.i18n.getMessage("selectModifications"); 43 | document.getElementById("advancedFormatting").innerText = 44 | chrome.i18n.getMessage("advancedFormatting"); 45 | document.getElementById("advancedFormatting").title = chrome.i18n.getMessage( 46 | "advancedFormattingDesc" 47 | ); 48 | document.getElementById("headerScroll").innerText = 49 | chrome.i18n.getMessage("hideHeader"); 50 | document.getElementById("headerScroll").title = 51 | chrome.i18n.getMessage("hideHeaderDesc"); 52 | document.getElementById("bookmarks").innerText = 53 | chrome.i18n.getMessage("navBookmarks"); 54 | document.getElementById("bookmarks").title = 55 | chrome.i18n.getMessage("navBookmarksDesc"); 56 | document.getElementById("compactPosts").innerText = 57 | chrome.i18n.getMessage("compactPosts"); 58 | document.getElementById("compactPosts").title = 59 | chrome.i18n.getMessage("compactPostsDesc"); 60 | document.getElementById("notificationIcons").innerText = 61 | chrome.i18n.getMessage("customNotification"); 62 | document.getElementById("notificationIcons").title = chrome.i18n.getMessage( 63 | "customNotificationDesc" 64 | ); 65 | document.getElementById("systemEmoji").innerText = 66 | chrome.i18n.getMessage("systemEmoji"); 67 | document.getElementById("systemEmoji").title = 68 | chrome.i18n.getMessage("systemEmojiDesc"); 69 | document.getElementById("userID").innerText = 70 | chrome.i18n.getMessage("showUID"); 71 | document.getElementById("userID").title = 72 | chrome.i18n.getMessage("showUIDDesc"); 73 | document.getElementById("signatureMod").innerText = 74 | chrome.i18n.getMessage("signatureMod"); 75 | document.getElementById("signatureMod").title = 76 | chrome.i18n.getMessage("signatureModDesc"); 77 | document.getElementById("square").innerText = 78 | chrome.i18n.getMessage("squareAvatars"); 79 | document.getElementById("square").title = 80 | chrome.i18n.getMessage("squareAvatarsDesc"); 81 | document.querySelector(".userCSS").innerText = 82 | chrome.i18n.getMessage("userCSS"); 83 | document.getElementById("css-save").innerText = 84 | chrome.i18n.getMessage("save"); 85 | document.getElementById("userCSS").placeholder = 86 | chrome.i18n.getMessage("userCSSDesc"); 87 | 88 | //info 89 | document.querySelector(".changelog").innerText = 90 | chrome.i18n.getMessage("changelog"); 91 | document.querySelector(".credits").innerText = 92 | chrome.i18n.getMessage("credits"); 93 | } 94 | 95 | localisation(); 96 | -------------------------------------------------------------------------------- /options/options.css: -------------------------------------------------------------------------------- 1 | :root { 2 | /* For page load */ 3 | --colorBg: hsl(0, 0%, 0%); 4 | } 5 | 6 | body.vfm-vivaldi_light { 7 | --colorBg: #fff; 8 | --colorBgC: #f2f2f2; 9 | --colorBgL: #f2f2f2; 10 | --colorBgM: #e6e6e6; 11 | --colorFg: #212121; 12 | --colorFg2: #595959; 13 | --colorHi: #c91106; 14 | --colorLi: #4c70f0; 15 | --colorCo: #4c70f0; 16 | --colorCo2: #7994f4; 17 | --colorAc: #3b57bb; 18 | --colorAcFg: #fff; 19 | --colorDd: #fff; 20 | --colorDdFg: #212121; 21 | } 22 | body.vfm-vivaldi_dark { 23 | --colorBg: #141414; 24 | --colorBgC: #2c2c2c; 25 | --colorBgL: #2c2c2c; 26 | --colorBgM: #434343; 27 | --colorFg: #fff; 28 | --colorFg2: #e0e0e0; 29 | --colorHi: #c91106; 30 | --colorLi: #4c70f0; 31 | --colorCo: #4c70f0; 32 | --colorCo2: #4363d3; 33 | --colorAc: #2a3f87; 34 | --colorAcFg: #fff; 35 | --colorDd: #303030; 36 | --colorDdFg: #fff; 37 | } 38 | body { 39 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 40 | Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 41 | font-weight: 400; 42 | font-size: 14px; 43 | background-color: var(--colorBg); 44 | cursor: default; 45 | margin: 0; 46 | user-select: none; 47 | } 48 | 49 | /* Header */ 50 | header { 51 | height: 67px; 52 | white-space: nowrap; 53 | color: var(--colorBgM); 54 | background-color: var(--colorBg); 55 | cursor: default; 56 | position: fixed; 57 | top: 0; 58 | right: 0; 59 | left: 0; 60 | z-index: 10; 61 | } 62 | #logo { 63 | position: fixed; 64 | top: 8px; 65 | left: 40px; 66 | } 67 | #themes-btn { 68 | margin-left: 70px; 69 | } 70 | #themes-btn, 71 | #modifications-btn, 72 | #info-btn, 73 | #feedback-btn, 74 | #reset-btn { 75 | color: var(--colorFg); 76 | cursor: default; 77 | background: none; 78 | background-image: none !important; 79 | border: none !important; 80 | box-shadow: none !important; 81 | text-shadow: none !important; 82 | height: 40px; 83 | font-weight: 600; 84 | font-size: 14px; 85 | padding: 0 8px; 86 | cursor: pointer; 87 | } 88 | #themes-btn:hover, 89 | #modifications-btn:hover, 90 | #info-btn:hover, 91 | #feedback-btn:hover, 92 | #reset-btn:hover, 93 | .view { 94 | color: var(--colorLi) !important; 95 | } 96 | form { 97 | display: inline; 98 | } 99 | header div { 100 | height: 27px; 101 | color: var(--colorAcFg); 102 | font-weight: 600; 103 | background: var(--colorAc); 104 | position: fixed; 105 | left: 0; 106 | right: 0; 107 | text-align: center; 108 | padding: 5px 0; 109 | } 110 | 111 | /* Content */ 112 | #content { 113 | position: absolute; 114 | width: 100%; 115 | color: var(--colorFg); 116 | top: calc(67px + 8vh); 117 | left: 0; 118 | right: 0; 119 | padding-bottom: 55px; 120 | margin: auto; 121 | text-align: left; 122 | } 123 | * { 124 | box-sizing: border-box; 125 | } 126 | 127 | /* Create columns */ 128 | .column-left { 129 | float: left; 130 | width: 50%; 131 | padding: 0 20px 0 40px; 132 | margin-bottom: 30px; 133 | } 134 | .column-right { 135 | float: right; 136 | width: 50%; 137 | padding: 0 20px 0 40px; 138 | } 139 | .scroll-column { 140 | width: 100%; 141 | max-height: 49vh; 142 | padding-right: 20px; 143 | overflow: hidden; 144 | text-overflow: ellipsis; 145 | } 146 | .scroll-column:hover { 147 | width: 100%; 148 | overflow-y: overlay; 149 | } 150 | .scroll-column p:first-of-type { 151 | margin-top: 0px; 152 | } 153 | 154 | /* Clears floats after the columns */ 155 | .row:after { 156 | content: ""; 157 | display: table; 158 | clear: both; 159 | } 160 | 161 | /* Stacks columns on top of each other for smaller displays */ 162 | @media screen and (max-width: 1000px) { 163 | .column-right, 164 | .right, 165 | .column-left, 166 | .left { 167 | width: 100%; 168 | } 169 | #content { 170 | top: 97px; 171 | } 172 | } 173 | .float { 174 | white-space: nowrap; 175 | overflow: auto; 176 | margin-bottom: 15px; 177 | } 178 | .left { 179 | float: left; 180 | } 181 | .right { 182 | float: right; 183 | left: -100px; 184 | } 185 | 186 | h2 { 187 | margin-top: 0; 188 | text-align: left; 189 | font-size: 1.3rem; 190 | color: var(--colorLi); 191 | } 192 | strong { 193 | color: var(--colorCo); 194 | } 195 | a { 196 | color: var(--colorLi); 197 | } 198 | #modifications, 199 | #info { 200 | display: none; 201 | } 202 | 203 | /* Themes page */ 204 | .themebox { 205 | width: 113px; 206 | padding: 0; 207 | border: 0; 208 | margin: 0 14px 14px 0; 209 | display: inline-block; 210 | vertical-align: top; 211 | text-align: center; 212 | background-color: transparent; 213 | } 214 | .themebox:hover { 215 | background: transparent !important; 216 | } 217 | .themebox .themebox-image { 218 | position: relative; 219 | overflow: hidden; 220 | border: 2px solid var(--colorBgL); 221 | outline: 1px solid var(--colorBgL); 222 | font-size: 0; 223 | } 224 | .active .themebox-image::before { 225 | opacity: 1; 226 | transform: scale(1); 227 | } 228 | .themebox-image::before { 229 | content: ""; 230 | position: absolute; 231 | transform: scale(0); 232 | opacity: 0; 233 | transition: 0.4s; 234 | transform-origin: 100% 100%; 235 | top: auto; 236 | left: auto; 237 | right: 0; 238 | bottom: 0; 239 | background-color: transparent; 240 | border: 20px solid transparent; 241 | } 242 | .active .themebox-image .themebox-o_mark { 243 | opacity: 1; 244 | transform: none; 245 | } 246 | .themebox-image .themebox-o_mark { 247 | transform: scale(1.5) translateX(2px) translateY(2px); 248 | opacity: 0; 249 | transition: 0.4s; 250 | position: absolute; 251 | height: 16px; 252 | width: 16px; 253 | bottom: 3px; 254 | right: 3px; 255 | stroke-width: 2px; 256 | } 257 | .themebox .themebox-title { 258 | white-space: normal; 259 | overflow: hidden; 260 | text-overflow: ellipsis; 261 | font-size: 13px; 262 | margin-top: 7px; 263 | letter-spacing: 0.5px; 264 | color: var(--colorFg); 265 | } 266 | #addTheme, 267 | #moveLeft, 268 | .theme-save, 269 | .theme-import, 270 | #addSchedule, 271 | #css-save { 272 | margin-right: 2px; 273 | } 274 | .theme-edit { 275 | margin: 0 6px; 276 | } 277 | .toggleEdit { 278 | opacity: 0; 279 | margin-top: 8px; 280 | } 281 | .toggleEdit div { 282 | height: 24px; 283 | margin-bottom: 3px; 284 | } 285 | .toggleEdit div:first-of-type { 286 | margin-top: 6px; 287 | } 288 | .toggleEdit input:not(#themeName), 289 | .toogleEdit label { 290 | vertical-align: middle; 291 | } 292 | input[type="text" i] { 293 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 294 | Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 295 | font-weight: 600; 296 | font-size: 13px; 297 | color: var(--colorFg); 298 | background-color: transparent; 299 | letter-spacing: 0.5px; 300 | width: 166px; 301 | height: 27px; 302 | text-indent: 5px; 303 | border: 2px solid var(--colorBgM); 304 | } 305 | .import::-webkit-input-placeholder { 306 | text-align: center; 307 | opacity: 1; 308 | color: var(--colorHi); 309 | } 310 | input[type="color"] { 311 | -webkit-appearance: none; 312 | cursor: pointer; 313 | border: none; 314 | outline: none; 315 | width: 38px; 316 | height: 24px; 317 | padding: 0; 318 | margin-right: 4px; 319 | } 320 | input[type="color"]::-webkit-color-swatch-wrapper { 321 | padding: 0; 322 | } 323 | input[type="color"]::-webkit-color-swatch { 324 | border: 1px solid var(--colorBgM); 325 | } 326 | /* themebox border colors */ 327 | .active .themebox-image { 328 | border-color: var(--colorHi); 329 | } 330 | .active .themebox-image::before { 331 | border-bottom-color: var(--colorHi); 332 | border-right-color: var(--colorHi); 333 | } 334 | .themebox-image .themebox-o_mark { 335 | fill: var(--colorHi); 336 | stroke: var(--colorBg); 337 | } 338 | 339 | /* Schedule */ 340 | .schedule, 341 | .userCSS { 342 | display: inline-block; 343 | } 344 | .switch { 345 | margin-left: 12px; 346 | margin-top: 3px; 347 | position: absolute; 348 | display: inline-block; 349 | vertical-align: middle; 350 | width: 30px; 351 | height: 17px; 352 | } 353 | .switch input { 354 | opacity: 0; 355 | width: 0; 356 | height: 0; 357 | } 358 | .slider { 359 | position: absolute; 360 | cursor: pointer; 361 | top: 0; 362 | left: 0; 363 | right: 0; 364 | bottom: 0; 365 | background-color: var(--colorBgM); 366 | transition: 0.4s; 367 | } 368 | .slider:before { 369 | position: absolute; 370 | content: ""; 371 | height: 13px; 372 | width: 13px; 373 | left: 2px; 374 | bottom: 2px; 375 | background-color: var(--colorFg); 376 | transition: 0.4s; 377 | } 378 | input:checked + .slider { 379 | background-color: var(--colorHi); 380 | } 381 | input:focus + .slider { 382 | box-shadow: 0 0 1px var(--colorHi); 383 | } 384 | input:checked + .slider:before { 385 | transform: translateX(13px); 386 | background-color: var(--colorBg); 387 | } 388 | .slider.round { 389 | border-radius: 17px; 390 | } 391 | .slider.round:before { 392 | border-radius: 50%; 393 | } 394 | .listSchedule { 395 | margin-top: 6px; 396 | } 397 | .listSchedule div { 398 | margin-bottom: 3px; 399 | } 400 | .listSchedule div select:focus { 401 | outline: none; 402 | } 403 | .listSchedule div select:not(last-of-type) { 404 | margin-right: 3px; 405 | } 406 | option { 407 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 408 | Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 409 | background: var(--colorDd); 410 | color: var(--colorDdFg); 411 | } 412 | select { 413 | background: var(--colorBgM); 414 | color: var(--colorFg); 415 | border: 2px solid var(--colorBgM); 416 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 417 | Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 418 | font-weight: 600; 419 | font-size: 13px; 420 | letter-spacing: 0.5px; 421 | padding: 4px 11px; 422 | border-radius: 3px; 423 | cursor: pointer; 424 | } 425 | select:hover { 426 | color: var(--colorCo); 427 | } 428 | 429 | /* Modifications page */ 430 | #selectMods span { 431 | font-weight: 600; 432 | letter-spacing: 0.5px; 433 | padding: 2px 0; 434 | } 435 | #selectMods span::before { 436 | content: "\25ef"; 437 | color: var(--colorFg); 438 | float: left; 439 | margin-top: -2px; 440 | padding-right: 8px; 441 | opacity: 0; 442 | } 443 | .selected { 444 | color: var(--colorHi); 445 | } 446 | #selectMods span.selected::before { 447 | opacity: 1; 448 | } 449 | #editCSS button { 450 | margin-bottom: 4px; 451 | } 452 | #userCSS { 453 | font-family: monospace; 454 | font-size: 12px; 455 | color: var(--colorFg); 456 | background-color: var(--colorBgC); 457 | padding: 5px; 458 | border: 2px solid var(--colorBgM); 459 | width: 100%; 460 | height: 49vh; 461 | resize: vertical; 462 | min-height: 100px; 463 | } 464 | #userCSS:disabled { 465 | background-color: var(--colorBgL); 466 | opacity: 0.65; 467 | } 468 | textarea::-webkit-input-placeholder { 469 | color: var(--colorFg2) !important; 470 | } 471 | 472 | /* Buttons */ 473 | button { 474 | background: var(--colorCo); 475 | color: var(--colorBg); 476 | border: 2px solid var(--colorCo); 477 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 478 | Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 479 | font-weight: 600; 480 | font-size: 13px; 481 | letter-spacing: 0.5px; 482 | padding: 4px 11px; 483 | border-radius: 3px; 484 | cursor: pointer; 485 | } 486 | button:hover:not(:disabled) { 487 | background: var(--colorCo2); 488 | border-color: var(--colorCo2); 489 | } 490 | button:disabled { 491 | cursor: default; 492 | opacity: 0.65; 493 | } 494 | button, 495 | #selectMods > p > span, 496 | .editTheme input:not(:first-of-type) { 497 | cursor: pointer; 498 | } 499 | button:focus { 500 | outline: none; 501 | } 502 | -------------------------------------------------------------------------------- /options/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vivaldi Forum mod 6 | 7 | 8 | 9 | 10 | 11 | 12 |
    13 | 14 | | | |
    | 15 |
    16 | 17 |
    18 |
    19 | 20 |
    21 |
    22 |
    23 |
    24 |
    25 |

    26 | 41 |
    56 |
    57 | 58 | 59 |
    60 |
    61 |
    62 |
    63 |
    64 |
    65 |
    66 |
    67 |
    68 |
    69 |
    70 |
    71 |
    72 |
    73 |
    74 |
    75 |
    76 |
    77 |
    78 |
    79 |

    80 | 84 |
    85 | 86 |
    87 |
    88 |
    89 |
    90 |
    91 |
    92 |
    93 |
    94 |

    95 | 99 |
    100 | 101 |
    102 | 103 |
    104 |
    105 |
    106 |
    107 |

    108 |

    109 |

    110 |

    111 |

    112 |

    113 |

    114 |

    115 |

    116 |

    117 |
    118 |
    119 |
    120 |
    121 |
    122 |

    123 |
    124 |

    5.0 Eight additional default themes including GitLook by bariton, remove download permission, theme fixes

    125 |

    4.7 Theme fixes, Vivaldi dark, system emoji compatibility update, easter egg

    126 |

    4.6 Add Santa hat Tony emote

    127 |

    4.5 Add Vivaldi Social’s Tony emoji to emote picker

    128 |

    4.4 Themes: textcomplete and topics

    129 |

    4.3 Simplify notification icons mod, highlight color for pinned topics, styling and font icon for search form

    130 |

    4.2 Various header fixes after forum update, rework notification icons mod

    131 |

    4.1 Activate add theme button for standard theme. Fixes for system emoji, copy code in quotes, advanced formatting popups

    132 |

    4.0 Migrate to manifest version 3, fix advanced formatting popups in zen mode, load theme when resetting extension

    133 |

    3.9 Chat page and header theming, bug fixes

    134 |

    3.8 New mod: Copy link of current post to clipboard

    135 |

    3.7 Theme solution field. New mod: Compact Posts

    136 |

    3.6 Fix avatar backgrounds and theming of quote buttons on hover

    137 |

    3.5 Smaller pagination block, regular upvote thumb, toned down timeline events

    138 |

    3.4 Fix for font awesome icons and dismissing notifications. Theme new tags

    139 |

    3.3 Silent update, system emoji fix

    140 |

    3.2 Advanced formatting fixes, custom.css update, system emoji and Japanese translation improvements, contribute link in footer

    141 |

    3.1 Improved advanced formatting, themed options page and Japanese translation

    142 |

    3.0 Unlimited custom themes, automatic import of theme previews, seamless theme changes and scheduled theming. New mod: Use System Emoji. Translations for Russian and Czech 143 |

    144 |

    2.4 Theme preview for Vivaldi Forum mod themes and Vivaldi Browser themes in topics. Vietnamese translation

    145 |

    2.3 Fix for pagination coloring on all themes, small settings fixes

    146 |

    2.0 New options page. New system for importing/exporting themes. Translations for French, German, Italian and Spanish

    147 |

    1.84 New logos by Rexfahrer, all themes updated, User CSS toggle reenabled

    148 |

    1.66 Theme Mod and Sprucey Bonus Dark updated, account, group and content margin fixes for all screen sizes

    149 |

    1.65 Modification and custom theme fixes after big Vivaldi Forum update. Only custom themes working

    150 |

    1.64 Mobile view fixes

    151 |

    1.62 Option to dismiss community notifications

    152 |

    1.61 Custom theme improvements, bug fixes

    153 |

    1.60 Advanced formatting improvements + account margin fix

    154 |

    1.59 Advanced formatting instead of emote picker

    155 |

    1.58 Improve emote picker usability

    156 |

    1.57 Add emote picker mod by LonM

    157 |

    1.56 Mobile menu fix, custom theme impprovements

    158 |

    1.55 Update to Theme Light-Grey, Theme Gray-Pink removed

    159 |

    1.54 Update to Dark-Grey, general theme fixes

    160 |

    1.53 Dark and light code markdown display, community info mod removed (Vivaldi removed the info), custom theme fixes

    161 |

    1.52 Extension runs in the background now, which should save resources. More consisten tags for custom themes (japanese/english)

    162 |

    1.50-1.51 Some small fixes here and there

    163 |

    1.49 Content adjustment for compact header mod, better visibility for special feature request tags in custom themes

    164 |

    1.48 Fixes an error related to automated colors in custom themes

    165 |

    1.47 Additional exceptions for copy all code button (blockquote, non formatted)

    166 |

    1.46 Link to the unofficial Vivaldi Discord chat and the official Vivaldi store added to footer. Copy all code button is consistent on all themes now. Fix for vertical code scrolling (removed space and up/down movement of the hljs part)

    167 |

    1.45 New default mod Copy all code button. Adds a button to each code block, which copies all code within the block. Written by LonM

    168 |

    1.44 Silent update -- background fixes

    169 |

    1.43 Last edit timestamp update, it displays local time instead of UTC now. History forward/backward fix for window.onload functions

    170 |

    1.42 window.onload consolidation, latest version didn't work in certain conditions

    171 |

    1.41 New mod Bookmarks in navigation (see Info), code improvements and cleanup

    172 |

    1.40 Backup functionality for User CSS, options page design cleanup

    173 |

    1.39 User CSS storage is local now (5MB instead of 8KB), Reset button to clear storage and options

    174 |

    1.38 Disabled spellcheck and added limit breach warning and error message for User CSS

    175 |

    1.37 New User CSS input and storage. Improvements to avatar dropdown menu. Status offline/invisible changes for the custom theme

    176 |

    1.35-1.36 New Forum Profile link in avatar dropdown menu. Fixing an issue Default custom theme changed to Solarized Light

    177 |

    1.34 Feature request box and default button spacing, redesign of default buttons and backgrounds for the custom theme

    178 |

    1.33 A fix for custom notification icon alignment, changed new tag styling for the custom theme

    179 |

    1.32 Fixing a bug for the bookmarking feature, additional font icons for code improvements

    180 |

    1.31 Reintroduction of tooltips mod

    181 |

    1.29-1.30 Further custom theme updates

    182 |

    1.28 Blockquote fix for search, automatic line breaks for code and emoji license view =)

    183 |

    1.25-1.27 Major bugfixes and styling for Sprucey Bonus Dark

    184 |

    1.1 - 1.24 Improvements and bugfixes for the custom theme option

    185 |

    1.0 Custom Theme option/interface and Compact Header mod

    186 |

    0.66 Reduced number of font sizes used in posts, simpler threaded replies header

    187 |

    0.64 Some site-wide inconsistencies fixed, improvements to GrayPink and Mod themes

    188 |

    0.62 Improvements to GrayPink. Missing "mentioned" notification icon added

    189 |

    0.60 Theme Mod + bugfixes

    190 |

    0.54 Silent update. Improvements and fixes for all themes

    191 |

    0.52 New logo animation and new theme (DarkGrey by sjudenim). Updates for LightGrey and Sprucey, fixed scroll bug.

    192 |

    0.44 Feedback link added

    193 |

    0.42 Release on Chrome web store

    194 |

    0.34 Improved options page. Changelog, Credits and Info

    195 |

    0.27 Theme Sprucey Bonus Dark, Square avatars

    196 |

    0.24 Theme LightGrey. More space for expanded chat input

    197 |
    198 |
    199 |
    200 |

    201 |
    202 |

    bariton GitLook

    203 |

    burbuja Spanish translation

    204 |

    greenenemy Voting Indicators

    205 |

    Hadden89 Italian translation

    206 |

    hlehyaric French translation

    207 |

    Isildur Font Icons • Square Avatars • Last Edit Timestamp

    208 |

    LonM Copy All Code Button • Advanced Formatting • Use System Emoji

    209 |

    nomadic Advanced Formatting improvements • Tony Santa emote

    210 |

    pafflick Custom Notification Icons

    211 |

    tiosgz Czech translation • Themed options page

    212 |

    Rexfahrer Vivaldi logos with transparency

    213 |

    Semenov-Sherin Russian translation

    214 |

    shifte Japanese translation

    215 |

    sjudenim Settings • DarkGrey • LightGrey

    216 |

    tam710562 Theme Preview • Vietnamese translation

    217 |

    wiiija Sprucey Bonus Dark

    218 |

    Zalex108 Spanish translation

    219 |
    220 |
    221 |
    222 |
    223 |
    224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /options/options.js: -------------------------------------------------------------------------------- 1 | // Restore Options 2 | 3 | function _restore() { 4 | _restoreThemes(); 5 | _restoreSchedule(); 6 | _loadTheme(); 7 | chrome.storage.sync.get( 8 | { 9 | VFM_MODS: "", 10 | VFM_USER_CSS: "", 11 | VFM_SCHEDULE: "", 12 | }, 13 | function (restore) { 14 | let mods = restore.VFM_MODS; 15 | Object.keys(mods).forEach(function (mod) { 16 | if (mods[mod] === true) { 17 | document.getElementById(mod).classList.add("selected"); 18 | } 19 | }); 20 | chrome.storage.local.get({ userCSS: "" }, function (local) { 21 | document.getElementById("userCSS").value = local.userCSS; 22 | }); 23 | if (restore.VFM_USER_CSS === true) { 24 | toggleBtn.setAttribute("checked", true); 25 | textarea.disabled = false; 26 | save2Btn.disabled = false; 27 | } else { 28 | toggleBtn.removeAttribute("checked"); 29 | textarea.disabled = true; 30 | save2Btn.disabled = true; 31 | } 32 | if (restore.VFM_SCHEDULE.activated === true) 33 | toggleSchedule.setAttribute("checked", true); 34 | else toggleSchedule.removeAttribute("checked"); 35 | if (changeMessage === false) { 36 | _status.style.opacity = "0"; 37 | _status.innerText = chrome.i18n.getMessage("statusThemes"); 38 | _fade(); 39 | } 40 | } 41 | ); 42 | } 43 | 44 | // Set page theme 45 | 46 | function _loadTheme() { 47 | chrome.storage.sync.get({ VFM_CURRENT_THEME: "" }, function (get) { 48 | let theme = get.VFM_CURRENT_THEME.selected; 49 | if (theme.startsWith("vfm_")) { 50 | document.body.classList.remove("vfm-vivaldi_light", "vfm-vivaldi_dark"); 51 | let colors = get.VFM_CURRENT_THEME.colors; 52 | for (const [key, value] of Object.entries(colors)) { 53 | document.body.style.setProperty("--" + key, value); 54 | } 55 | } else { 56 | document.body.removeAttribute("style"); 57 | document.body.classList.remove("vfm-vivaldi_light", "vfm-vivaldi_dark"); 58 | if (theme === "vfm-vivaldi_light") 59 | document.body.classList.add("vfm-vivaldi_light"); 60 | else document.body.classList.add("vfm-vivaldi_dark"); 61 | } 62 | }); 63 | } 64 | 65 | // Save Modifications 66 | 67 | function _selectMods(event) { 68 | const target = event.currentTarget; 69 | const toggle = target.getAttribute("id"); 70 | chrome.storage.sync.get({ VFM_MODS: "" }, function (select) { 71 | let mods = select.VFM_MODS; 72 | if (target.classList.contains("selected")) { 73 | target.removeAttribute("class"); 74 | mods[toggle] = false; 75 | } else { 76 | target.classList.add("selected"); 77 | mods[toggle] = true; 78 | } 79 | chrome.storage.sync.set({ VFM_MODS: mods }); 80 | }); 81 | } 82 | 83 | // Use tab in textarea (tab to 4 spaces) 84 | 85 | function _tabSpaces(key) { 86 | if (key.keyCode === 9 || key.which === 9) { 87 | key.preventDefault(); 88 | let select = this.selectionStart; 89 | this.value = 90 | this.value.substring(0, this.selectionStart) + 91 | " " + 92 | this.value.substring(this.selectionEnd); 93 | this.selectionEnd = select + 4; 94 | } 95 | } 96 | 97 | // Toggle User CSS 98 | 99 | function _toggleUserCSS() { 100 | chrome.storage.sync.get({ VFM_USER_CSS: "" }, function (get) { 101 | let css = get.VFM_USER_CSS; 102 | if (css === true) { 103 | css = false; 104 | save2Btn.disabled = true; 105 | textarea.disabled = true; 106 | toggleBtn.removeAttribute("checked"); 107 | var text = chrome.i18n.getMessage("deactivateUserCSS"); 108 | } else { 109 | css = true; 110 | toggleBtn.setAttribute("checked", true); 111 | save2Btn.disabled = false; 112 | textarea.disabled = false; 113 | var text = chrome.i18n.getMessage("activateUserCSS"); 114 | } 115 | chrome.storage.sync.set({ VFM_USER_CSS: css }, function () { 116 | chrome.runtime.sendMessage({ message: "trigger usercss" }); 117 | _status.style.opacity = "0"; 118 | _status.innerText = text; 119 | _fade(); 120 | }); 121 | }); 122 | } 123 | 124 | // Save User CSS 125 | 126 | function _saveUserCSS() { 127 | let userCSS = document.getElementById("userCSS").value; 128 | chrome.storage.local.set( 129 | { 130 | userCSS: userCSS, 131 | }, 132 | function () { 133 | chrome.runtime.sendMessage({ message: "trigger usercss" }); 134 | _status.style.opacity = "0"; 135 | _status.innerText = chrome.i18n.getMessage("saveUserCSS"); 136 | _fade(); 137 | } 138 | ); 139 | } 140 | 141 | // Toggle Schedule 142 | 143 | function _toggleSchedule() { 144 | chrome.storage.sync.get({ VFM_SCHEDULE: "" }, function (get) { 145 | let schedule = get.VFM_SCHEDULE; 146 | if (schedule.activated === false) { 147 | schedule.activated = true; 148 | var systemMessage = "trigger schedule"; 149 | var text = chrome.i18n.getMessage("activateSchedule"); 150 | toggleSchedule.setAttribute("checked", true); 151 | } else { 152 | schedule.activated = false; 153 | var systemMessage = "clear alarm"; 154 | var text = chrome.i18n.getMessage("deactivateSchedule"); 155 | toggleSchedule.removeAttribute("checked"); 156 | } 157 | chrome.storage.sync.set({ VFM_SCHEDULE: schedule }, function () { 158 | chrome.runtime.sendMessage({ message: systemMessage }); 159 | _status.style.opacity = "0"; 160 | _status.innerText = text; 161 | _fade(); 162 | }); 163 | }); 164 | } 165 | 166 | // Restore Schedule 167 | 168 | function _restoreSchedule() { 169 | chrome.storage.sync.get( 170 | { 171 | VFM_SCHEDULE: { schedule: {} }, 172 | VFM_THEMES: "", 173 | }, 174 | function (restore) { 175 | listSchedule.innerHTML = ""; 176 | let themes = restore.VFM_THEMES; 177 | let schedule = restore.VFM_SCHEDULE; 178 | let entries = schedule.schedule; 179 | Object.keys(entries).forEach((entry) => { 180 | let vivaldiTheme = true; 181 | const scheduleEntry = document.createElement("div"); 182 | scheduleEntry.id = `schedule-${entry}`; 183 | scheduleEntry.innerHTML = ``; 184 | listSchedule.appendChild(scheduleEntry); 185 | const hours = entries[entry].time.substring(0, 2); 186 | const minutes = entries[entry].time.substring(3, 5); 187 | document 188 | .querySelector( 189 | `#schedule-${entry} .sc-hours option[value="${hours}"]` 190 | ) 191 | .setAttribute("selected", true); 192 | document 193 | .querySelector( 194 | `#schedule-${entry} .sc-minutes option[value="${minutes}"]` 195 | ) 196 | .setAttribute("selected", true); 197 | Object.keys(themes).forEach((theme) => { 198 | const name = themes[theme].themeName; 199 | const option = document.createElement("option"); 200 | option.value = name; 201 | if (name === entries[entry].theme) { 202 | option.setAttribute("selected", true); 203 | vivaldiTheme = false; 204 | } 205 | option.text = name.substring(4).replace(/_/g, " "); 206 | document 207 | .querySelector(`#schedule-${entry} .sc-themes`) 208 | .appendChild(option); 209 | }); 210 | if (vivaldiTheme === true) { 211 | if (entries[entry].theme === "vfm-vivaldi_light") { 212 | document.querySelector(`#schedule-${entry} .vivaldi_light`).setAttribute("selected", true); 213 | } 214 | else { 215 | document.querySelector(`#schedule-${entry} .vivaldi_dark`).setAttribute("selected", true); 216 | } 217 | } 218 | }); 219 | const select = document.querySelectorAll("select"); 220 | select.forEach((selected) => { 221 | selected.addEventListener("change", function () { 222 | _editSchedule(selected); 223 | }); 224 | }); 225 | } 226 | ); 227 | } 228 | 229 | // Edit Schedule 230 | 231 | function _editSchedule(el) { 232 | chrome.storage.sync.get({ VFM_SCHEDULE: "" }, function (get) { 233 | let schedule = get.VFM_SCHEDULE; 234 | const saveValue = el.options[el.selectedIndex].value; 235 | const index = Number(el.parentNode.id.replace(/^\D+/g, "")); 236 | if (el.classList.contains("sc-themes")) { 237 | schedule.schedule[index].theme = saveValue; 238 | } else if (el.classList.contains("sc-hours")) { 239 | schedule.schedule[index].time = 240 | saveValue + schedule.schedule[index].time.substring(2, 5); 241 | } else { 242 | schedule.schedule[index].time = 243 | schedule.schedule[index].time.substring(0, 3) + saveValue; 244 | } 245 | schedule.schedule.sort((a, b) => { 246 | if (b.time > a.time) return -1; 247 | if (a.time > b.time) return 1; 248 | return 0; 249 | }); 250 | chrome.storage.sync.set({ VFM_SCHEDULE: schedule }, function () { 251 | _restoreSchedule(); 252 | chrome.runtime.sendMessage({ message: "trigger schedule" }); 253 | }); 254 | }); 255 | } 256 | 257 | // Add/Remove Schedule 258 | 259 | function _addremoveSchedule(choice) { 260 | chrome.storage.sync.get({ VFM_SCHEDULE: "" }, function (get) { 261 | let schedule = get.VFM_SCHEDULE; 262 | if (choice === 1) { 263 | const as = { theme: "vfm-vivaldi_light", time: "00:00" }; 264 | schedule.schedule.unshift(as); 265 | } else { 266 | if (schedule.schedule.length > 2) schedule.schedule.shift(); 267 | else return; 268 | } 269 | chrome.storage.sync.set({ VFM_SCHEDULE: schedule }, function () { 270 | _restoreSchedule(); 271 | chrome.runtime.sendMessage({ message: "trigger schedule" }); 272 | }); 273 | }); 274 | } 275 | 276 | // Reset Extension 277 | 278 | function _resetOptions() { 279 | if (!resetBtn.classList.contains("confirm")) { 280 | resetBtn.classList.add("confirm"); 281 | _status.style.opacity = "0"; 282 | _status.innerText = chrome.i18n.getMessage("confirmReset"); 283 | _fade(); 284 | setTimeout(function () { 285 | if (_status.innerText === chrome.i18n.getMessage("confirmReset")) { 286 | _status.style.opacity = "0"; 287 | _status.innerText = chrome.i18n.getMessage("cancelReset"); 288 | _fade(); 289 | } 290 | resetBtn.removeAttribute("class"); 291 | }, 8000); 292 | } else { 293 | resetBtn.removeAttribute("class"); 294 | chrome.storage.sync.clear(function () { 295 | chrome.storage.local.clear(function () { 296 | selectMods.forEach(function (mod) { 297 | if (mod.classList.contains("selected")) { 298 | mod.removeAttribute("class"); 299 | } 300 | }); 301 | const ct = document.querySelectorAll( 302 | '#themeMachine button[id^="vfm_"]' 303 | ); 304 | for (let i = 0; i < ct.length; i++) { 305 | ct[i].parentNode.removeChild(ct[i]); 306 | } 307 | chrome.runtime.sendMessage({ message: "reset" }, function () { 308 | _restore(); 309 | _showThemes(); 310 | changeMessage = true; 311 | _status.style.opacity = "0"; 312 | _status.innerText = chrome.i18n.getMessage("optionsReset"); 313 | _fade(); 314 | }); 315 | }); 316 | }); 317 | } 318 | } 319 | 320 | // Navigation 321 | 322 | function _showThemes() { 323 | document.querySelector(".view").removeAttribute("class"); 324 | btnThemes.classList.add("view"); 325 | navThemes.style.display = "block"; 326 | navModifications.style.display = "none"; 327 | navInfo.style.display = "none"; 328 | _status.style.opacity = "0"; 329 | _status.innerText = chrome.i18n.getMessage("statusThemes"); 330 | _fade(); 331 | } 332 | function _showModifications() { 333 | document.querySelector(".view").removeAttribute("class"); 334 | btnModifications.classList.add("view"); 335 | navThemes.style.display = "none"; 336 | navModifications.style.display = "block"; 337 | navInfo.style.display = "none"; 338 | _status.style.opacity = "0"; 339 | _status.innerText = chrome.i18n.getMessage("statusModifications"); 340 | _fade(); 341 | } 342 | function _showInfo() { 343 | document.querySelector(".view").removeAttribute("class"); 344 | btnInfo.classList.add("view"); 345 | navThemes.style.display = "none"; 346 | navModifications.style.display = "none"; 347 | navInfo.style.display = "block"; 348 | _status.style.opacity = "0"; 349 | _status.innerText = chrome.i18n.getMessage("statusInfo"); 350 | _fade(); 351 | } 352 | 353 | const navThemes = document.getElementById("themes"); 354 | const navModifications = document.getElementById("modifications"); 355 | const navInfo = document.getElementById("info"); 356 | const btnThemes = document.getElementById("themes-btn"); 357 | const btnModifications = document.getElementById("modifications-btn"); 358 | const btnInfo = document.getElementById("info-btn"); 359 | const selectMods = document.querySelectorAll("#selectMods > p > span"); 360 | const textarea = document.querySelector("textarea"); 361 | const toggleBtn = document.getElementById("css-toggle"); 362 | const save2Btn = document.getElementById("css-save"); 363 | const resetBtn = document.getElementById("reset-btn"); 364 | const toggleSchedule = document.getElementById("schedule-toggle"); 365 | const listSchedule = document.querySelector(".listSchedule"); 366 | const addSchedule = document.getElementById("addSchedule"); 367 | const removeSchedule = document.getElementById("removeSchedule"); 368 | let changeMessage = false; 369 | 370 | btnThemes.addEventListener("click", _showThemes); 371 | btnModifications.addEventListener("click", _showModifications); 372 | btnInfo.addEventListener("click", _showInfo); 373 | selectMods.forEach(function (mod) { 374 | mod.addEventListener("click", _selectMods); 375 | }); 376 | textarea.addEventListener("keydown", _tabSpaces); 377 | toggleBtn.addEventListener("click", _toggleUserCSS); 378 | save2Btn.addEventListener("click", _saveUserCSS); 379 | toggleSchedule.addEventListener("click", _toggleSchedule); 380 | addSchedule.addEventListener("click", function () { 381 | _addremoveSchedule(1); 382 | }); 383 | removeSchedule.addEventListener("click", function () { 384 | _addremoveSchedule(0); 385 | }); 386 | resetBtn.addEventListener("click", _resetOptions); 387 | 388 | chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { 389 | if (request.message === "options apply theme") { 390 | _loadTheme(); 391 | } 392 | if (request.message === "options update theme") { 393 | document 394 | .querySelector("#themeMachine .themebox.active") 395 | .classList.remove("active"); 396 | const ct = document.querySelectorAll('#themeMachine button[id^="vfm_"]'); 397 | for (let i = 0; i < ct.length; i++) { 398 | ct[i].parentNode.removeChild(ct[i]); 399 | } 400 | _restoreThemes(); 401 | _restoreSchedule(); 402 | } 403 | }); 404 | 405 | _loadTheme(); 406 | _restore(); 407 | -------------------------------------------------------------------------------- /serviceworker.js: -------------------------------------------------------------------------------- 1 | // Default Setup 2 | 3 | function defaultSetup() { 4 | chrome.storage.sync.set( 5 | { 6 | VFM_CURRENT_THEME: { 7 | selected: "vfm-vivaldi_light", 8 | colors: { 9 | colorBg: "", 10 | colorFg: "", 11 | colorAc: "", 12 | colorHi: "", 13 | colorLi: "", 14 | colorCo: "", 15 | colorDd: "", 16 | colorBgD: "", 17 | colorBgC: "", 18 | colorBgL: "", 19 | colorBgM: "", 20 | colorBgH: "", 21 | colorFg2: "", 22 | colorAcFg: "", 23 | colorLi2: "", 24 | colorCo2: "", 25 | colorDdFg: "", 26 | colorDdL: "", 27 | colorDdM: "", 28 | colorDdH: "", 29 | }, 30 | }, 31 | VFM_THEMES: [ 32 | { 33 | themeName: "vfm_Ayu", 34 | colorBg: "#fafafa", 35 | colorFg: "#5c6773", 36 | colorHi: "#36a3d9", 37 | colorAc: "#d9d8d7", 38 | colorLi: "#f29718", 39 | colorCo: "#86b300", 40 | colorDd: "#f0eee4", 41 | }, 42 | { 43 | themeName: "vfm_Dracula", 44 | colorBg: "#282a36", 45 | colorFg: "#f8f8f2", 46 | colorHi: "#50fa7b", 47 | colorAc: "#44475a", 48 | colorLi: "#ff79c6", 49 | colorCo: "#bd93f9", 50 | colorDd: "#6272a4", 51 | }, 52 | { 53 | themeName: "vfm_Everforest_Light", 54 | colorBg: "#efebd4", 55 | colorFg: "#5c6a72", 56 | colorHi: "#f57d26", 57 | colorAc: "#8da101", 58 | colorLi: "#8da101", 59 | colorCo: "#dfa000", 60 | colorDd: "#bdc3af", 61 | }, 62 | { 63 | themeName: "vfm_Everforest_Dark", 64 | colorBg: "#232a2e", 65 | colorFg: "#d3c6aa", 66 | colorHi: "#e69875", 67 | colorAc: "#a7c080", 68 | colorLi: "#a7c080", 69 | colorCo: "#dbbc7f", 70 | colorDd: "#56635f", 71 | }, 72 | { 73 | themeName: "vfm_GitLook_Light", 74 | colorBg: "#ffffff", 75 | colorFg: "#24292f", 76 | colorHi: "#fd8c73", 77 | colorAc: "#dbe9f9", 78 | colorLi: "#0969da", 79 | colorCo: "#2da44e", 80 | colorDd: "#e6e6e6", 81 | }, 82 | { 83 | themeName: "vfm_GitLook_Dark", 84 | colorBg: "#0d1117", 85 | colorFg: "#c9d1d9", 86 | colorHi: "#e37861", 87 | colorAc: "#13233a", 88 | colorLi: "#58a6ff", 89 | colorCo: "#99c8ff", 90 | colorDd: "#161b22", 91 | }, 92 | { 93 | themeName: "vfm_Iceberg", 94 | colorBg: "#e8e9ec", 95 | colorFg: "#33374c", 96 | colorHi: "#6869ec", 97 | colorAc: "#757ca3", 98 | colorLi: "#2d5396", 99 | colorCo: "#3f83a6", 100 | colorDd: "#cad0de", 101 | }, 102 | { 103 | themeName: "vfm_Kanagawa", 104 | colorBg: "#1f1f28", 105 | colorFg: "#dcd7ba", 106 | colorHi: "#6a9589", 107 | colorAc: "#2a2a37", 108 | colorLi: "#658594", 109 | colorCo: "#e6c384", 110 | colorDd: "#223249", 111 | }, 112 | { 113 | themeName: "vfm_Palenight", 114 | colorBg: "#292d3e", 115 | colorFg: "#a6accd", 116 | colorHi: "#ff869a", 117 | colorAc: "#3b4084", 118 | colorLi: "#82b1ff", 119 | colorCo: "#c3e88d", 120 | colorDd: "#333747", 121 | }, 122 | { 123 | themeName: "vfm_PaperColor_Light", 124 | colorBg: "#eeeeee", 125 | colorFg: "#444444", 126 | colorHi: "#d75f00", 127 | colorAc: "#005f87", 128 | colorLi: "#005faf", 129 | colorCo: "#d70087", 130 | colorDd: "#005f87", 131 | }, 132 | { 133 | themeName: "vfm_PaperColor_Dark", 134 | colorBg: "#1c1c1c", 135 | colorFg: "#d0d0d0", 136 | colorHi: "#afd700", 137 | colorAc: "#5f8787", 138 | colorLi: "#00afaf", 139 | colorCo: "#ff5faf", 140 | colorDd: "#5f8787", 141 | }, 142 | { 143 | themeName: "vfm_Rigel", 144 | colorBg: "#002635", 145 | colorFg: "#e6e6dc", 146 | colorHi: "#00cccc", 147 | colorAc: "#1c8db2", 148 | colorLi: "#1c8db2", 149 | colorCo: "#7eb2dd", 150 | colorDd: "#517f8d", 151 | }, 152 | { 153 | themeName: "vfm_Solarized_Light", 154 | colorBg: "#fdf6e3", 155 | colorFg: "#586e75", 156 | colorHi: "#af8700", 157 | colorAc: "#eee8d5", 158 | colorLi: "#268bd2", 159 | colorCo: "#2aa198", 160 | colorDd: "#eee8d5", 161 | }, 162 | { 163 | themeName: "vfm_Solarized_Dark", 164 | colorBg: "#002b36", 165 | colorFg: "#93a1a1", 166 | colorHi: "#af8700", 167 | colorAc: "#073642", 168 | colorLi: "#268bd2", 169 | colorCo: "#2aa198", 170 | colorDd: "#073642", 171 | }, 172 | { 173 | themeName: "vfm_Tokyo_Night", 174 | colorBg: "#1a1b26", 175 | colorFg: "#a9b1d6", 176 | colorHi: "#ff9e64", 177 | colorAc: "#2f334d", 178 | colorLi: "#f7768e", 179 | colorCo: "#7aa2f7", 180 | colorDd: "#1f2335", 181 | }, 182 | { 183 | themeName: "vfm_Zenburn", 184 | colorBg: "#3f3f3f", 185 | colorFg: "#dcdccc", 186 | colorHi: "#8faf9f", 187 | colorAc: "#2e3330", 188 | colorLi: "#ffd7a7", 189 | colorCo: "#dca3a3", 190 | colorDd: "#2c2e2e", 191 | }, 192 | ], 193 | VFM_MODS: { 194 | advancedFormatting: false, 195 | headerScroll: false, 196 | bookmarks: false, 197 | compactPosts: false, 198 | notificationIcons: false, 199 | userID: false, 200 | signatureMod: false, 201 | square: false, 202 | systemEmoji: false, 203 | }, 204 | VFM_USER_CSS: false, 205 | VFM_SCHEDULE: { 206 | activated: false, 207 | schedule: [ 208 | { time: "06:00", theme: "vfm_PaperColor_Light" }, 209 | { time: "18:00", theme: "vfm_PaperColor_Dark" }, 210 | ], 211 | }, 212 | }, 213 | function () { 214 | chrome.runtime.openOptionsPage(); 215 | } 216 | ); 217 | } 218 | 219 | // Activate Theme 220 | 221 | let RGB = (hex) => 222 | hex 223 | .replace( 224 | /^#?([a-f\d])([a-f\d])([a-f\d])$/i, 225 | (m, r, g, b) => "#" + r + r + g + g + b + b 226 | ) 227 | .substring(1) 228 | .match(/.{2}/g) 229 | .map((x) => parseInt(x, 16)); 230 | 231 | let lum = (r, g, b) => { 232 | let a = [r, g, b].map(function (v) { 233 | v /= 255; 234 | return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); 235 | }); 236 | return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722; 237 | }; 238 | 239 | let contrast = (lum1, lum2) => { 240 | const bright = Math.max(lum1, lum2); 241 | const dark = Math.min(lum1, lum2); 242 | return (bright + 0.05) / (dark + 0.05); 243 | }; 244 | 245 | let shade = (color, percent) => { 246 | let f = parseInt(color.slice(1), 16), 247 | t = percent < 0 ? 0 : 255, 248 | p = percent < 0 ? percent * -1 : percent, 249 | R = f >> 16, 250 | G = (f >> 8) & 0x00ff, 251 | B = f & 0x0000ff; 252 | return ( 253 | "#" + 254 | ( 255 | 0x1000000 + 256 | (Math.round((t - R) * p) + R) * 0x10000 + 257 | (Math.round((t - G) * p) + G) * 0x100 + 258 | (Math.round((t - B) * p) + B) 259 | ) 260 | .toString(16) 261 | .slice(1) 262 | ); 263 | }; 264 | 265 | function activateTheme() { 266 | chrome.storage.sync.get( 267 | { 268 | VFM_THEMES: "", 269 | VFM_CURRENT_THEME: "", 270 | }, 271 | (get) => { 272 | const vt = get.VFM_THEMES; 273 | const vct = get.VFM_CURRENT_THEME; 274 | if (vct.selected.startsWith("vfm_")) { 275 | let co = vct.colors; 276 | const index = vt.findIndex((x) => x.themeName === vct.selected); 277 | co.colorBg = vt[index].colorBg; 278 | co.colorFg = vt[index].colorFg; 279 | co.colorHi = vt[index].colorHi; 280 | co.colorCo = vt[index].colorCo; 281 | co.colorDd = vt[index].colorDd; 282 | co.colorLi = vt[index].colorLi; 283 | co.colorAc = vt[index].colorAc; 284 | // background 285 | const rgbBg = RGB(co.colorBg); 286 | const lumBg = lum(rgbBg[0], rgbBg[1], rgbBg[2]); 287 | if (lumBg <= 0.5) { 288 | if (lumBg < 0.01) co.colorBgC = shade(co.colorBg, 0.1); 289 | else co.colorBgC = shade(co.colorBg, -0.2); 290 | co.colorBgD = shade(co.colorBg, 0.05); 291 | co.colorBgL = shade(co.colorBg, 0.1); 292 | co.colorBgM = shade(co.colorBg, 0.2); 293 | co.colorBgH = shade(co.colorBg, 0.4); 294 | } else { 295 | co.colorBgC = shade(co.colorBg, -0.05); 296 | co.colorBgD = shade(co.colorBg, -0.025); 297 | co.colorBgL = shade(co.colorBg, -0.05); 298 | co.colorBgM = shade(co.colorBg, -0.1); 299 | co.colorBgH = shade(co.colorBg, -0.2); 300 | } 301 | // foreground 302 | const rgbFg = RGB(co.colorFg); 303 | const lumFg = lum(rgbFg[0], rgbFg[1], rgbFg[2]); 304 | if (lumBg > 0.5) co.colorFg2 = shade(co.colorFg, 0.25); 305 | else co.colorFg2 = shade(co.colorFg, -0.12); 306 | // accent 307 | const rgbAc = RGB(co.colorAc); 308 | const lumAc = lum(rgbAc[0], rgbAc[1], rgbAc[2]); 309 | const conAc1 = contrast(lumAc, lumBg); 310 | const conAc2 = contrast(lumAc, lumFg); 311 | if (conAc1 >= conAc2) co.colorAcFg = co.colorBg; 312 | else co.colorAcFg = co.colorFg; 313 | // link 314 | if (lumBg > 0.5) co.colorLi2 = shade(co.colorLi, 0.25); 315 | else co.colorLi2 = shade(co.colorLi, -0.12); 316 | // code 317 | if (lumBg > 0.5) co.colorCo2 = shade(co.colorCo, 0.25); 318 | else co.colorCo2 = shade(co.colorCo, -0.12); 319 | // dropdown 320 | const rgbDd = RGB(co.colorDd); 321 | const lumDd = lum(rgbDd[0], rgbDd[1], rgbDd[2]); 322 | const conDd1 = contrast(lumDd, lumBg); 323 | const conDd2 = contrast(lumDd, lumFg); 324 | if (conDd1 >= conDd2) co.colorDdFg = co.colorBg; 325 | else co.colorDdFg = co.colorFg; 326 | if (lumDd <= 0.5) { 327 | co.colorDdL = shade(co.colorDd, 0.1); 328 | co.colorDdM = shade(co.colorDd, 0.2); 329 | co.colorDdH = shade(co.colorDd, 0.4); 330 | } else { 331 | co.colorDdL = shade(co.colorDd, -0.05); 332 | co.colorDdM = shade(co.colorDd, -0.1); 333 | co.colorDdH = shade(co.colorDd, -0.2); 334 | } 335 | // store custom theme 336 | chrome.storage.sync.set({ VFM_CURRENT_THEME: vct }, () => { 337 | sendToTabs("update theme"); 338 | chrome.runtime.sendMessage({ message: "options apply theme" }); 339 | }); 340 | } else { 341 | sendToTabs("update theme"); 342 | chrome.runtime.sendMessage({ message: "options apply theme" }); 343 | } 344 | } 345 | ); 346 | } 347 | 348 | // Import from theme preview 349 | 350 | function importFromForum() { 351 | let code = arguments[0].theme; 352 | chrome.storage.sync.get( 353 | { 354 | VFM_THEMES: "", 355 | VFM_CURRENT_THEME: "", 356 | }, 357 | function (get) { 358 | let vt = get.VFM_THEMES; 359 | let vct = get.VFM_CURRENT_THEME; 360 | let nameCheck = /^[a-zA-Z0-9- ]*$/.test(code.themeName); 361 | if (nameCheck === true && code.themeName.length < 26) { 362 | code.themeName = "vfm_" + code.themeName.replace(/ /g, "_").trim(); 363 | let index = vt.findIndex( 364 | (x) => x.themeName.toLowerCase() === code.themeName.toLowerCase() 365 | ); 366 | if (index !== -1) { 367 | code.themeName = "vfm_" + Date.now(); 368 | } 369 | } else { 370 | code.themeName = "vfm_" + Date.now(); 371 | } 372 | vct.selected = code.themeName; 373 | vt.push(code); 374 | chrome.storage.sync.set( 375 | { 376 | VFM_THEMES: vt, 377 | VFM_CURRENT_THEME: vct, 378 | }, 379 | function () { 380 | activateTheme(); 381 | chrome.runtime.sendMessage({ message: "options update theme" }); 382 | } 383 | ); 384 | } 385 | ); 386 | } 387 | 388 | // Update Tabs 389 | 390 | function sendToTabs(reason) { 391 | chrome.storage.local.get({ tabIDs: [] }, function (get) { 392 | let tabIDs = get.tabIDs; 393 | tabIDs.forEach(function (id) { 394 | chrome.tabs.sendMessage(id, { message: reason }, function () { 395 | if (chrome.runtime.lastError) { 396 | let del = tabIDs.indexOf(id); 397 | tabIDs.splice(del, 1); 398 | chrome.storage.local.set({ tabIDs: tabIDs }); 399 | } 400 | }); 401 | }); 402 | }); 403 | } 404 | 405 | // Scheduled Theming 406 | 407 | function setSchedule() { 408 | chrome.storage.sync.get( 409 | { 410 | VFM_CURRENT_THEME: "", 411 | VFM_SCHEDULE: "", 412 | }, 413 | function (get) { 414 | const sc = get.VFM_SCHEDULE; 415 | if (sc.activated === true) { 416 | const vct = get.VFM_CURRENT_THEME; 417 | const epoch = Date.now(); 418 | const time = new Date(epoch); 419 | const hours = time.getHours(); 420 | const minutes = time.getMinutes(); 421 | const clock = 422 | String(hours).padStart(2, 0) + ":" + String(minutes).padStart(2, 0); 423 | const index = sc.schedule.findIndex((x) => x.time > clock); 424 | if (index === -1) { 425 | var diff = 426 | (86400 - 427 | (hours * 3600 + minutes * 60) + 428 | Number(sc.schedule[0].time.substring(0, 2)) * 3600 + 429 | Number(sc.schedule[0].time.substring(3, 5)) * 60) * 430 | 1000; 431 | } else { 432 | var diff = 433 | (Number(sc.schedule[index].time.substring(0, 2)) * 3600 + 434 | Number(sc.schedule[index].time.substring(3, 5)) * 60 - 435 | (hours * 3600 + minutes * 60)) * 436 | 1000; 437 | } 438 | if (index === -1 || index === 0) { 439 | var changeTo = sc.schedule[sc.schedule.length - 1].theme; 440 | } else { 441 | var changeTo = sc.schedule[index - 1].theme; 442 | } 443 | if (vct.selected !== changeTo) { 444 | vct.selected = changeTo; 445 | chrome.storage.sync.set({ VFM_CURRENT_THEME: vct }, function () { 446 | activateTheme(); 447 | chrome.runtime.sendMessage({ message: "options update theme" }); 448 | }); 449 | } 450 | chrome.alarms.create("themeChange", { 451 | when: Math.floor(epoch / 60000) * 60000 + diff, 452 | }); 453 | } 454 | } 455 | ); 456 | } 457 | 458 | // Advanced Formatting 459 | // In case item orders change from one instance to next, put them all in order 460 | // and re-number any not hidden starting from 1. If this update has support for 461 | // new buttons, mark them as disabled 462 | 463 | function normaliseFormattingToolbarOrders() { 464 | chrome.storage.sync.get( 465 | { 466 | VFM_FORMAT: "", 467 | }, 468 | (settings) => { 469 | if (settings.VFM_FORMAT === "") { 470 | return; 471 | } 472 | const possibleButtons = [ 473 | "bold", 474 | "italic", 475 | "list", 476 | "strikethrough", 477 | "link", 478 | "picture-o", 479 | "zen", 480 | "picture", 481 | "heart-o", 482 | "emoji-add-emoji", 483 | "header", 484 | "window-minimize", 485 | "quote-right", 486 | "code", 487 | "file-code-o", 488 | "th-large", 489 | "list-ol", 490 | "shield", 491 | ]; 492 | const normalisedOrder = {}; 493 | let outOfOrder = Object.entries(settings.VFM_FORMAT); 494 | outOfOrder.sort((a, b) => Number(a[1]) - Number(b[1])); 495 | let orderCounter = 1; 496 | for (let index = 0; index < outOfOrder.length; index++) { 497 | const key = outOfOrder[index][0]; 498 | const order = outOfOrder[index][1]; 499 | if (possibleButtons.indexOf(key) === -1) { 500 | continue; 501 | } 502 | if (order === -1) { 503 | normalisedOrder[key] = -1; 504 | } else { 505 | normalisedOrder[key] = orderCounter++; 506 | } 507 | } 508 | const existingButtons = Object.keys(settings.VFM_FORMAT); 509 | const newButtons = possibleButtons.filter( 510 | (x) => existingButtons.indexOf(x) === -1 511 | ); 512 | for (let index = 0; index < newButtons.length; index++) { 513 | normalisedOrder[newButtons[index]] = orderCounter++; 514 | } 515 | chrome.storage.sync.set({ VFM_FORMAT: normalisedOrder }); 516 | } 517 | ); 518 | } 519 | 520 | chrome.runtime.onStartup.addListener(function () { 521 | setSchedule(); 522 | }); 523 | chrome.runtime.onInstalled.addListener(function (details) { 524 | if (details.reason === "update") normaliseFormattingToolbarOrders(); 525 | if (details.reason === "install" || details.previousVersion * 1 < 3) 526 | defaultSetup(); 527 | }); 528 | chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { 529 | if (request.message === "options pls") chrome.runtime.openOptionsPage(); 530 | if (request.message === "whoami") { 531 | chrome.storage.local.get({ tabIDs: [] }, function (get) { 532 | let tabIDs = get.tabIDs; 533 | let index = tabIDs.findIndex((x) => x === sender.tab.id); 534 | if (index === -1) { 535 | tabIDs.push(sender.tab.id); 536 | chrome.storage.local.set({ tabIDs: tabIDs }); 537 | } 538 | sendResponse({ message: "akn" }); 539 | chrome.storage.sync.get({ VFM_SCHEDULE: "" }, (get) => { 540 | if (get.VFM_SCHEDULE.activated === true) { 541 | chrome.alarms.get("themeChange", (alarm) => { 542 | setTimeout(() => { 543 | if (Date.now() > alarm.scheduledTime) setSchedule(); 544 | }, 3000); 545 | }); 546 | } 547 | }); 548 | }); 549 | } 550 | if (request.message === "trigger theme") activateTheme(); 551 | if (request.message === "trigger schedule") setSchedule(); 552 | if (request.message === "clear alarm") chrome.alarms.clear("themeChange"); 553 | if (request.message === "trigger usercss") sendToTabs("change usercss"); 554 | if (request.theme) importFromForum.apply(this, arguments); 555 | if (request.message === "reset") { 556 | defaultSetup(); 557 | sendResponse({ message: "akn" }); 558 | } 559 | }); 560 | chrome.alarms.onAlarm.addListener(function (alarm) { 561 | if (alarm.name === "themeChange") { 562 | setSchedule(); 563 | } 564 | }); 565 | -------------------------------------------------------------------------------- /theme.js: -------------------------------------------------------------------------------- 1 | // Load stylesheets 2 | 3 | function loadFile(filename, id) { 4 | let head = document.getElementsByTagName("head")[0]; 5 | let check = document.getElementById("vfmUSERCSS"); 6 | let style = document.createElement("link"); 7 | if (id) { 8 | style.setAttribute("id", id); 9 | } 10 | style.setAttribute("rel", "stylesheet"); 11 | style.setAttribute("type", "text/css"); 12 | style.setAttribute("href", chrome.runtime.getURL(filename)); 13 | if (check) { 14 | head.insertBefore(style, check); 15 | } else { 16 | head.appendChild(style); 17 | } 18 | } 19 | 20 | // Wait function 21 | 22 | function _async() { 23 | return new Promise((resolve) => { 24 | requestAnimationFrame(resolve); 25 | }); 26 | } 27 | async function _wait() { 28 | while (!document.body) { 29 | await _async(); 30 | } 31 | return true; 32 | } 33 | 34 | // Load Theme 35 | 36 | function loadTheme() { 37 | chrome.storage.sync.get({ VFM_CURRENT_THEME: "" }, function (get) { 38 | let theme = get.VFM_CURRENT_THEME.selected; 39 | if (theme.startsWith("vfm_")) { 40 | _wait().then(() => { 41 | let colors = get.VFM_CURRENT_THEME.colors; 42 | for (const [key, value] of Object.entries(colors)) { 43 | document.body.style.setProperty("--" + key, value); 44 | } 45 | }); 46 | loadFile("themes/custom.css", "vfmTheme"); 47 | } else { 48 | if (theme === "vfm-vivaldi_light") { 49 | loadFile("themes/vivaldi-light.css", "vfmTheme"); 50 | } else { 51 | loadFile("themes/vivaldi-dark.css", "vfmTheme"); 52 | } 53 | } 54 | // introduce theme name as class in body 55 | _wait().then(() => { 56 | document.body.classList.add(theme); 57 | }); 58 | }); 59 | } 60 | 61 | // Load User CSS 62 | 63 | function loadUserCSS() { 64 | chrome.storage.sync.get({ VFM_USER_CSS: "" }, function (get) { 65 | if (get.VFM_USER_CSS === true) { 66 | chrome.storage.local.get({ userCSS: "" }, function (local) { 67 | if (local.userCSS !== "") { 68 | let activateUserCSS = document.createElement("style"); 69 | activateUserCSS.id = "vfmUSERCSS"; 70 | activateUserCSS.type = "text/css"; 71 | activateUserCSS.innerHTML = local.userCSS; 72 | document.getElementsByTagName("head")[0].appendChild(activateUserCSS); 73 | } 74 | }); 75 | } 76 | }); 77 | } 78 | 79 | // Update Tab 80 | 81 | function updateTheme() { 82 | let theme = document.getElementById("vfmTheme"); 83 | if (theme) { 84 | theme.disabled = true; 85 | theme.parentNode.removeChild(theme); 86 | } 87 | document.body.className = document.body.className.replace( 88 | /(^|\s)vfm\S+/g, 89 | "" 90 | ); 91 | loadTheme(); 92 | } 93 | 94 | function updateUserCSS() { 95 | let del = document.getElementById("vfmUSERCSS"); 96 | if (del) { 97 | del.disabled = true; 98 | del.parentNode.removeChild(del); 99 | } 100 | loadUserCSS(); 101 | } 102 | 103 | navigator.serviceWorker.register("/serviceworker.js"); 104 | loadTheme(); 105 | loadUserCSS(); 106 | chrome.runtime.sendMessage({ message: "whoami" }, function () { 107 | if (chrome.runtime.lastError) { 108 | setTimeout(function () { 109 | chrome.runtime.sendMessage({ message: "whoami" }); 110 | }, 3000); 111 | } 112 | }); 113 | chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { 114 | if (request.message === "update theme") { 115 | updateTheme(); 116 | sendResponse({ message: "akn" }); 117 | } 118 | if (request.message === "change usercss") { 119 | updateUserCSS(); 120 | sendResponse({ message: "akn" }); 121 | } 122 | }); 123 | -------------------------------------------------------------------------------- /themes/vivaldi-dark.css: -------------------------------------------------------------------------------- 1 | /* Theme Vivaldi Dark */ 2 | /* Additional code to ensure compatibility with Forum mod features. */ 3 | 4 | /* Standard settings for header */ 5 | a#vlogo { 6 | height: 32px; 7 | width: 32px; 8 | margin-top: 0px; 9 | } 10 | .skin-dark #vlogo { 11 | background: unset; 12 | } 13 | #vivaldinav { 14 | left: 55px; 15 | } 16 | #communitysubmenu { 17 | display: none; 18 | } 19 | @media (min-width: 960px) { 20 | #submenu, 21 | #submenu.isfixed { 22 | top: 64px !important; 23 | position: fixed; 24 | } 25 | main#panel { 26 | margin-top: -70px; 27 | } 28 | .topic .topic-header { 29 | position: unset; 30 | } 31 | .chats-full { 32 | padding-top: 20px; 33 | } 34 | } 35 | 36 | /* Header */ 37 | #vlogo { 38 | fill: #4c70f0; 39 | } 40 | 41 | /* Advanced formatting mod */ 42 | .vivaldi-mod-modal-box { 43 | background: #141414; 44 | border-color: #434343; 45 | } 46 | .vivaldi-mod-modal-box-control-bar { 47 | background: #434343; 48 | color: #fff; 49 | } 50 | .dropmarker, 51 | .dropmarker:after { 52 | background: #4c70f0; 53 | } 54 | .dropmarker:before { 55 | border-color: #4c70f0; 56 | } 57 | #toolbar-custom ul li:hover { 58 | background-color: #2c2c2c; 59 | } 60 | 61 | /* Copy all code button */ 62 | .copy-all-code-button { 63 | background-color: #4c70f0; 64 | color: #fff; 65 | } 66 | .copy-all-code-button:hover { 67 | background-color: #4363d3; 68 | } 69 | 70 | /* Highlight post-tools link button on click */ 71 | small.pull-right a.vfm-highlight { 72 | color: #c91106 !important; 73 | } 74 | 75 | /* Notification icons */ 76 | #menu .notification-list li::before, 77 | .header .notification-list li::before, 78 | #menu .notification-list li .mark-read, 79 | .header .notification-list li .mark-read { 80 | color: #fff !important; 81 | } 82 | 83 | /* Theme preview */ 84 | .themebox-title { 85 | color: #fff; 86 | } 87 | -------------------------------------------------------------------------------- /themes/vivaldi-light.css: -------------------------------------------------------------------------------- 1 | /* Theme Vivaldi Light */ 2 | /* Additional code to ensure compatibility with Forum mod features. */ 3 | 4 | /* Standard settings for header */ 5 | a#vlogo { 6 | height: 32px; 7 | width: 32px; 8 | margin-top: 0px; 9 | } 10 | #vlogo img { 11 | display: none; 12 | } 13 | #vivaldinav { 14 | left: 55px; 15 | } 16 | #communitysubmenu { 17 | display: none; 18 | } 19 | @media (min-width: 960px) { 20 | #submenu, 21 | #submenu.isfixed { 22 | top: 64px !important; 23 | position: fixed; 24 | } 25 | main#panel { 26 | margin-top: -70px; 27 | } 28 | .topic .topic-header { 29 | position: unset; 30 | } 31 | .chats-full { 32 | padding-top: 20px; 33 | } 34 | } 35 | 36 | /* Header */ 37 | #vlogo { 38 | fill: #4c70f0; 39 | } 40 | 41 | /* Advanced formatting mod */ 42 | .vivaldi-mod-modal-box { 43 | background: #fff; 44 | border-color: #e6e6e6; 45 | } 46 | .vivaldi-mod-modal-box-control-bar { 47 | background: #e6e6e6; 48 | color: #212121; 49 | } 50 | .dropmarker, 51 | .dropmarker:after { 52 | background: #4c70f0; 53 | } 54 | .dropmarker:before { 55 | border-color: #4c70f0; 56 | } 57 | #toolbar-custom ul li:hover { 58 | background-color: #f2f2f2; 59 | } 60 | 61 | /* Copy all code button */ 62 | .copy-all-code-button { 63 | background-color: #4c70f0; 64 | color: #fff; 65 | } 66 | .copy-all-code-button:hover { 67 | background-color: #7994f4; 68 | } 69 | 70 | /* Highlight post-tools link button on click */ 71 | small.pull-right a.vfm-highlight { 72 | color: #c91106 !important; 73 | } 74 | 75 | /* Notification icons */ 76 | #menu .notification-list li::before, 77 | .header .notification-list li::before, 78 | #menu .notification-list li .mark-read, 79 | .header .notification-list li .mark-read { 80 | color: #212121 !important; 81 | } 82 | 83 | /* Theme preview */ 84 | .themebox-title { 85 | color: #212121; 86 | } 87 | --------------------------------------------------------------------------------