forked from FoundKeyGang/FoundKey
Compare commits
1 commit
main
...
chore/acti
Author | SHA1 | Date | |
---|---|---|---|
555699635f |
95 changed files with 8921 additions and 448 deletions
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -15,24 +15,14 @@ For older Misskey versions, see [CHANGELOG-OLD.md](./CHANGELOG-OLD.md).
|
|||
### Changed
|
||||
- Client: Use consistent date formatting based on language setting
|
||||
- Client: Add threshold to reduce occurances of "future" timestamps
|
||||
- Pages have been considerably simplified, several of the very complex features have been removed.
|
||||
Pages are now MFM only.
|
||||
**For admins:** There is a migration in place to convert page contents to text, but not everything can be migrated.
|
||||
You might want to check if you have any more complex pages on your instance and ask users to migrate them by hand.
|
||||
Or generally advise all users to simplify their pages to only text.
|
||||
|
||||
### Removed
|
||||
- Okteto config and Helm chart
|
||||
- Client: acrylic styling
|
||||
- Client: Twitter embeds, the standard URL preview is used instead.
|
||||
- Promotion entities and endpoints
|
||||
|
||||
### Fixed
|
||||
- Server: Blocking remote accounts
|
||||
|
||||
### Security
|
||||
- Server: Update `multer` dependency to resolve [CVE-2022-24434](https://nvd.nist.gov/vuln/detail/CVE-2022-24434)
|
||||
|
||||
## 13.0.0-preview1 - 2022-08-05
|
||||
### Added
|
||||
- Server: Replies can now be fetched recursively.
|
||||
|
|
|
@ -465,6 +465,8 @@ dayOverDayChanges: "يوميا"
|
|||
appearance: "المظهر"
|
||||
clientSettings: "إعدادات العميل"
|
||||
accountSettings: "إعدادات الحساب"
|
||||
promotion: "ترقية"
|
||||
promote: "روِّج"
|
||||
numberOfDays: "عدد الأيام"
|
||||
hideThisNote: "إخفاء هذه الملاحظة"
|
||||
showFeaturedNotesInTimeline: "أظهر الملاحظات الشائعة في الخيط الزمني"
|
||||
|
@ -529,6 +531,7 @@ poll: "استطلاع رأي"
|
|||
useCw: "إخفاء المحتوى"
|
||||
enablePlayer: "افتح مشغل الفيديو"
|
||||
disablePlayer: "أغلق مشغل الفيديو"
|
||||
expandTweet: "وسّع التغريدة"
|
||||
themeEditor: "مصمم القوالب"
|
||||
description: "الوصف"
|
||||
describeFile: "أضف تعليقًا توضيحيًا"
|
||||
|
@ -1229,6 +1232,7 @@ _pages:
|
|||
liked: "الصفحات المُعجب بها"
|
||||
featured: "الأكثر شعبية"
|
||||
contents: "المحتوى"
|
||||
variables: "متغيّرات"
|
||||
title: "العنوان"
|
||||
url: "رابط الصفحة"
|
||||
summary: "ملخص الصفحة"
|
||||
|
@ -1239,6 +1243,238 @@ _pages:
|
|||
fontSansSerif: "Sans Serif"
|
||||
eyeCatchingImageSet: "عيّن صورة مصغّرة"
|
||||
eyeCatchingImageRemove: "احذف صورة مصغّرة"
|
||||
chooseBlock: "إضافة كتلة"
|
||||
selectType: "اختر النوع"
|
||||
enterVariableName: "أدخل اسم المتغيّر"
|
||||
variableNameIsAlreadyUsed: "هذا الاسم محجوز"
|
||||
contentBlocks: "المحتوى"
|
||||
inputBlocks: "مُدخل"
|
||||
specialBlocks: "خاص"
|
||||
blocks:
|
||||
text: "نص"
|
||||
textarea: "حقل نصي"
|
||||
section: "قسم"
|
||||
image: "الصور"
|
||||
button: "زرّ"
|
||||
_if:
|
||||
variable: "متغيّر"
|
||||
post: "أنشئ ملاحظة"
|
||||
_post:
|
||||
text: "المحتوى"
|
||||
textInput: "مُدخل نصي"
|
||||
_textInput:
|
||||
name: "اسم المتغير"
|
||||
text: "العنوان"
|
||||
default: "القيمة الافتراضية"
|
||||
textareaInput: "مدخل نصي متعدد الأسطر"
|
||||
_textareaInput:
|
||||
name: "اسم المتغير"
|
||||
text: "العنوان"
|
||||
default: "القيمة الافتراضية"
|
||||
numberInput: "مُدخل رقمي"
|
||||
_numberInput:
|
||||
name: "اسم المتغير"
|
||||
text: "العنوان"
|
||||
default: "القيمة الافتراضية"
|
||||
_canvas:
|
||||
width: "العُرض"
|
||||
height: "الإرتفاع"
|
||||
note: "ملاحظة مضمّنة"
|
||||
_note:
|
||||
id: "معرّف الملاحظة"
|
||||
idDescription: "كبديل يمكنك إدخال رابك الملاحظة هنا"
|
||||
detailed: "عرض مفصّل"
|
||||
switch: "بدّل"
|
||||
_switch:
|
||||
name: "اسم المتغير"
|
||||
text: "العنوان"
|
||||
default: "القيمة الافتراضية"
|
||||
counter: "العداد"
|
||||
_counter:
|
||||
name: "اسم المتغير"
|
||||
text: "العنوان"
|
||||
inc: "زِد"
|
||||
_button:
|
||||
text: "العنوان"
|
||||
colored: "ملوّن"
|
||||
action: "الإجراء عند ضغط الزّر"
|
||||
_action:
|
||||
dialog: "أظهر مربع حوار"
|
||||
_dialog:
|
||||
content: "المحتوى"
|
||||
resetRandom: "صفِّر البذرة"
|
||||
pushEvent: "أرسل حدثًا"
|
||||
_pushEvent:
|
||||
event: "اسم الحدث"
|
||||
message: "إظهار رسالة عند التفعيل"
|
||||
variable: "أرسل المتغيّر"
|
||||
no-variable: "لا شيء"
|
||||
_callAiScript:
|
||||
functionName: "اسم الدالة"
|
||||
radioButton: "الخيار "
|
||||
_radioButton:
|
||||
name: "اسم المتغير"
|
||||
title: "العنوان"
|
||||
values: "قائمة الخيارات (كل خيار في سطر لوحده)"
|
||||
default: "القيمة الافتراضية"
|
||||
script:
|
||||
categories:
|
||||
logical: "عمليّة منطقيّة"
|
||||
operation: "حساب"
|
||||
comparison: "مقارنة"
|
||||
random: "عشوائي"
|
||||
value: "القيم"
|
||||
fn: "دوال"
|
||||
text: "إجراءات على النصوص"
|
||||
convert: "تحويل"
|
||||
list: "القوائم"
|
||||
blocks:
|
||||
text: "نص"
|
||||
textList: "قائمة نصية"
|
||||
_textList:
|
||||
info: "اجعل كل مدخل في سطر لوحده"
|
||||
strLen: "طول النص"
|
||||
_strLen:
|
||||
arg1: "نص"
|
||||
strPick: "استخرج محرفًا"
|
||||
_strPick:
|
||||
arg1: "نص"
|
||||
arg2: "موضع المحرف"
|
||||
strReplace: "استبدال النّص"
|
||||
_strReplace:
|
||||
arg1: "نص"
|
||||
arg2: "استُبدِل بـ"
|
||||
arg3: "استُبدِل بـ"
|
||||
strReverse: "اقلب النص"
|
||||
_strReverse:
|
||||
arg1: "نص"
|
||||
_join:
|
||||
arg1: "القوائم"
|
||||
arg2: "فاصل"
|
||||
add: "إضافة"
|
||||
_add:
|
||||
arg1: "أ"
|
||||
arg2: "ب"
|
||||
subtract: "اطرح"
|
||||
_subtract:
|
||||
arg1: "أ"
|
||||
arg2: "ب"
|
||||
multiply: "اضرب"
|
||||
_multiply:
|
||||
arg1: "أ"
|
||||
arg2: "ب"
|
||||
divide: "اقسم"
|
||||
_divide:
|
||||
arg1: "أ"
|
||||
arg2: "ب"
|
||||
mod: "الباقي"
|
||||
_mod:
|
||||
arg1: "أ"
|
||||
arg2: "ب"
|
||||
round: "تقريب عدد عشري"
|
||||
_round:
|
||||
arg1: "رقم"
|
||||
eq: "أ و ب متساويان"
|
||||
_eq:
|
||||
arg1: "أ"
|
||||
arg2: "ب"
|
||||
notEq: "أ و ب مختلفان"
|
||||
_notEq:
|
||||
arg1: "أ"
|
||||
arg2: "ب"
|
||||
and: "أ و ب"
|
||||
_and:
|
||||
arg1: "أ"
|
||||
arg2: "ب"
|
||||
or: "أ أو ب"
|
||||
_or:
|
||||
arg1: "أ"
|
||||
arg2: "ب"
|
||||
lt: "أ أصغر من ب"
|
||||
_lt:
|
||||
arg1: "أ"
|
||||
arg2: "ب"
|
||||
gt: "أ أكبر من ب"
|
||||
_gt:
|
||||
arg1: "أ"
|
||||
arg2: "ب"
|
||||
ltEq: "أ أصغر من أو يساوي ب"
|
||||
_ltEq:
|
||||
arg1: "أ"
|
||||
arg2: "ب"
|
||||
gtEq: "أ أكبر من أو يساوي ب"
|
||||
_gtEq:
|
||||
arg1: "أ"
|
||||
arg2: "ب"
|
||||
if: "فرع"
|
||||
random: "عشوائي"
|
||||
rannum: "رقم عشوائي"
|
||||
_rannum:
|
||||
arg1: "أدنى قيمة"
|
||||
arg2: "أقصى قيمة"
|
||||
randomPick: "اختر عشوائيًا من القائمة"
|
||||
_randomPick:
|
||||
arg1: "القوائم"
|
||||
dailyRandom: "عشوائي (يتغير مرة يوميًا لكل مستخدم)"
|
||||
dailyRannum: "رقم عشوائي (يتغير مرة يوميًا لكل مستخدم)"
|
||||
_dailyRannum:
|
||||
arg1: "أدنى قيمة"
|
||||
arg2: "أقصى قيمة"
|
||||
dailyRandomPick: "اختيار عشوائي من قائمة (يتغير مرة يوميًا لكل مستخدم)"
|
||||
_dailyRandomPick:
|
||||
arg1: "القوائم"
|
||||
seedRandom: "عشوائي (عبر بذرة)"
|
||||
_seedRandom:
|
||||
arg1: "البذرة"
|
||||
seedRannum: "رقم عشوائي (عبر بذرة)"
|
||||
_seedRannum:
|
||||
arg1: "البذرة"
|
||||
arg2: "أدنى قيمة"
|
||||
arg3: "أقصى قيمة"
|
||||
seedRandomPick: "اختيار عشوائي من القائمة (عبر بذرة)"
|
||||
_seedRandomPick:
|
||||
arg1: "البذرة"
|
||||
arg2: "القوائم"
|
||||
DRPWPM: "اختيار عشوائي من قائمة الاحتمالات (تتغير مرة يوميًا لكل مستخدم)"
|
||||
_DRPWPM:
|
||||
arg1: "قائمة نصية"
|
||||
pick: "اختر من القائمة"
|
||||
_pick:
|
||||
arg1: "القوائم"
|
||||
arg2: "الموضع"
|
||||
listLen: "طول القائمة"
|
||||
_listLen:
|
||||
arg1: "القوائم"
|
||||
number: "رقم"
|
||||
stringToNumber: "حوّل نصًا إلى رقم"
|
||||
_stringToNumber:
|
||||
arg1: "نص"
|
||||
numberToString: "حوّل رقمًا إلى نص"
|
||||
_numberToString:
|
||||
arg1: "رقم"
|
||||
_splitStrByLine:
|
||||
arg1: "نص"
|
||||
ref: "متغيّر"
|
||||
aiScriptVar: "متغيّر AiScript"
|
||||
fn: "دالة"
|
||||
_fn:
|
||||
slots: "خانات"
|
||||
arg1: "المُخرج"
|
||||
for: "حلقة تكرار"
|
||||
_for:
|
||||
arg1: "عدد مرات التكرار"
|
||||
arg2: "الإجراء"
|
||||
typeError: "الخانة {slot} تقبل \"{expect}\" لكن القيمة المعطاة هي \"{actual}\"!"
|
||||
thereIsEmptySlot: "الخانة {slot} فارغة!"
|
||||
types:
|
||||
string: "نص"
|
||||
number: "رقم"
|
||||
array: "القوائم"
|
||||
stringArray: "قائمة نصية"
|
||||
emptySlot: "خانة فارغة"
|
||||
enviromentVariables: "متغيرات البيئة"
|
||||
pageVariables: "متغيرات الصفحة"
|
||||
argVariables: "خانة إدخال"
|
||||
_relayStatus:
|
||||
requesting: "مُعلّق"
|
||||
accepted: "مقبول"
|
||||
|
|
|
@ -472,6 +472,8 @@ dayOverDayChanges: "গতকাল"
|
|||
appearance: "অবয়ব"
|
||||
clientSettings: "ক্লায়েন্ট সেটিংস"
|
||||
accountSettings: "অ্যাকাউন্ট সেটিংস"
|
||||
promotion: "প্রমোশন"
|
||||
promote: "প্রচার করুন"
|
||||
numberOfDays: "দিনের সংখ্যা"
|
||||
hideThisNote: "নোটটি লুকান"
|
||||
showFeaturedNotesInTimeline: "টাইমলাইনে সুপারিশকৃত নোটগুলি দেখান"
|
||||
|
@ -547,6 +549,7 @@ poll: "জরিপ"
|
|||
useCw: "কন্টেন্ট লুকান"
|
||||
enablePlayer: "ভিডিও প্লেয়ার খুলুন"
|
||||
disablePlayer: "ভিডিও প্লেয়ার বন্ধ করুন"
|
||||
expandTweet: "টুইট বিস্তারিত করুন"
|
||||
themeEditor: "থিম সম্পাদক"
|
||||
description: "বর্ণনা"
|
||||
describeFile: "ক্যাপশন যোগ করুন"
|
||||
|
@ -1321,7 +1324,10 @@ _pages:
|
|||
my: "আমার পৃষ্ঠাগুলি"
|
||||
liked: "পছন্দ করা পৃষ্ঠাগুলি"
|
||||
featured: "জনপ্রিয়"
|
||||
inspector: "ইনিস্পেক্টর"
|
||||
contents: "বিষয়বস্তু"
|
||||
content: "পৃষ্ঠার ব্লক"
|
||||
variables: "চলকগুলি"
|
||||
title: "শিরোনাম"
|
||||
url: "পৃষ্ঠার URL"
|
||||
summary: "পৃষ্ঠার বর্ণনা"
|
||||
|
@ -1332,6 +1338,262 @@ _pages:
|
|||
fontSansSerif: "স্যান্স সেরিফ"
|
||||
eyeCatchingImageSet: "থাম্বনেইল সেট করুন"
|
||||
eyeCatchingImageRemove: "থাম্বনেইল সরান"
|
||||
chooseBlock: "ব্লক যোগ করুন"
|
||||
selectType: "ধরন নির্বাচন করুন"
|
||||
enterVariableName: "চলকের নাম লিখুন"
|
||||
variableNameIsAlreadyUsed: "চলকের নামটি ইতিপূর্বে ব্যাবহৃত হয়েছে"
|
||||
contentBlocks: "বিষয়বস্তু"
|
||||
inputBlocks: "ইনপুট"
|
||||
specialBlocks: "বিশেষ"
|
||||
blocks:
|
||||
text: "লেখা"
|
||||
textarea: "টেক্সট এরিয়া"
|
||||
section: "বিভাগ"
|
||||
image: "ছবি"
|
||||
button: "বাটন"
|
||||
if: "যদি"
|
||||
_if:
|
||||
variable: "চলকগুলি"
|
||||
post: "নোট লিখুন"
|
||||
_post:
|
||||
text: "বিষয়বস্তু"
|
||||
attachCanvasImage: "ক্যানভাস ছবিসহ পোস্ট করুন"
|
||||
canvasId: "ক্যানভাস ID"
|
||||
textInput: "টেক্সট ইনপুট"
|
||||
_textInput:
|
||||
name: "চলকের নাম"
|
||||
text: "শিরোনাম"
|
||||
default: "ডিফল্ট মান"
|
||||
textareaInput: "একাধিক লাইনের টেক্সট ইনপুট"
|
||||
_textareaInput:
|
||||
name: "চলকের নাম"
|
||||
text: "শিরোনাম"
|
||||
default: "ডিফল্ট মান"
|
||||
numberInput: "সংখ্যা ইনপুট"
|
||||
_numberInput:
|
||||
name: "চলকের নাম"
|
||||
text: "শিরোনাম"
|
||||
default: "ডিফল্ট মান"
|
||||
canvas: "ক্যানভাস"
|
||||
_canvas:
|
||||
id: "ক্যানভাস ID"
|
||||
width: "প্রস্থ"
|
||||
height: "উচ্চতা"
|
||||
note: "এম্বেড নোট"
|
||||
_note:
|
||||
id: "নোট ID"
|
||||
idDescription: "আপনি এর বদলে নোটের URL পেস্ট করতে পারেন."
|
||||
detailed: "বিস্তারিত দেখুন"
|
||||
switch: "সুইচ"
|
||||
_switch:
|
||||
name: "চলকের নাম"
|
||||
text: "শিরোনাম"
|
||||
default: "ডিফল্ট মান"
|
||||
counter: "কাউন্টার"
|
||||
_counter:
|
||||
name: "চলকের নাম"
|
||||
text: "শিরোনাম"
|
||||
inc: "এভাবে মান বাড়ান"
|
||||
_button:
|
||||
text: "শিরোনাম"
|
||||
colored: "রঙ্গিন"
|
||||
action: "বাটনে ক্লিক করলে যা হবে"
|
||||
_action:
|
||||
dialog: "ডায়ালগ দেখান "
|
||||
_dialog:
|
||||
content: "বিষয়বস্তু"
|
||||
resetRandom: "র্যানডম সিড রিসেট করুন"
|
||||
pushEvent: "ইভেন্ট পাঠান"
|
||||
_pushEvent:
|
||||
event: "ইভেন্টের নাম"
|
||||
message: "চালু হলে প্রদর্শনের জন্য বার্তা"
|
||||
variable: "পাঠানো চলক"
|
||||
no-variable: "কিছুই না"
|
||||
callAiScript: "AiScript চালান"
|
||||
_callAiScript:
|
||||
functionName: "ফাংশনের নাম"
|
||||
radioButton: "বহুনির্বাচনী"
|
||||
_radioButton:
|
||||
name: "চলকের নাম"
|
||||
title: "শিরোনাম"
|
||||
values: "বিকল্পগুলিকে আলাদা লাইনে লিখুন"
|
||||
default: "ডিফল্ট মান"
|
||||
script:
|
||||
categories:
|
||||
flow: "নিয়ন্ত্রণ"
|
||||
logical: "লজিক্যাল অপারেশন"
|
||||
operation: "হিসাব-নিকাশ"
|
||||
comparison: "তুলনা"
|
||||
random: "র্যান্ডম"
|
||||
value: "মান"
|
||||
fn: "ফাংশন"
|
||||
text: "টেক্সট ম্যানিপুলেশন"
|
||||
convert: "রুপান্তর"
|
||||
list: "লিস্ট"
|
||||
blocks:
|
||||
text: "লেখা"
|
||||
multiLineText: "লেখা (একাধিক লাইন)"
|
||||
textList: "লেখার লিস্ট"
|
||||
_textList:
|
||||
info: "প্রতিটি এন্ট্রিকে আলাদা লাইনে লিখুন"
|
||||
strLen: "লেখার দৈর্ঘ্য"
|
||||
_strLen:
|
||||
arg1: "লেখা"
|
||||
strPick: "অক্ষর বের করে আনুন"
|
||||
_strPick:
|
||||
arg1: "লেখা"
|
||||
arg2: "অক্ষরের অবস্থান"
|
||||
strReplace: "লেখা প্রতিস্থাপন"
|
||||
_strReplace:
|
||||
arg1: "লেখা"
|
||||
arg2: "যে লেখা প্রতিস্থাপন করা হবে"
|
||||
arg3: "যা দ্বারা প্রতিস্থাপন করা হবে"
|
||||
strReverse: "লেখা উল্টান"
|
||||
_strReverse:
|
||||
arg1: "লেখা"
|
||||
join: "লেখা যুক্ত করুন"
|
||||
_join:
|
||||
arg1: "লিস্ট"
|
||||
arg2: "বিভাজক"
|
||||
add: "যোগ"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "বিয়োগ"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "গুন"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "ভাগ"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "ভাগশেষ"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "দশমিক রাউন্ড করুন"
|
||||
_round:
|
||||
arg1: "সংখ্যা"
|
||||
eq: "A ও B সমান"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A ও B সমান না"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A এবং B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A অথবা B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A , B হতে কম"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A , B হতে বেশী"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A , B হতে কম বা সমান"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A , B হতে বেশী বা সমান"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "যদি"
|
||||
_if:
|
||||
arg1: "যদি"
|
||||
arg2: "তাহলে"
|
||||
arg3: "তাছাড়া"
|
||||
not: "না"
|
||||
_not:
|
||||
arg1: "না"
|
||||
random: "র্যান্ডম"
|
||||
_random:
|
||||
arg1: "সম্ভাব্যতা"
|
||||
rannum: "র্যানডম সংখ্যা"
|
||||
_rannum:
|
||||
arg1: "ন্যূনতম মান"
|
||||
arg2: "সর্বোচ্চ মান"
|
||||
randomPick: "তালিকা থেকে দৈবচয়ন করুন"
|
||||
_randomPick:
|
||||
arg1: "লিস্ট"
|
||||
dailyRandom: "র্যান্ডম সংখ্যা (প্রতিটি ব্যবহারকারীর জন্য প্রতিদিন পরিবর্তীত হয়)"
|
||||
_dailyRandom:
|
||||
arg1: "সম্ভাব্যতা"
|
||||
dailyRannum: "র্যান্ডম সংখ্যা (প্রতিটি ব্যবহারকারীর জন্য প্রতিদিন পরিবর্তীত হয়)"
|
||||
_dailyRannum:
|
||||
arg1: "ন্যূনতম মান"
|
||||
arg2: "সর্বোচ্চ মান"
|
||||
dailyRandomPick: "তালিকা থেকে এলোমেলোভাবে নির্বাচন করুন (প্রতিটি ব্যবহারকারীর জন্য প্রতিদিন পরিবর্তীত হয়)"
|
||||
_dailyRandomPick:
|
||||
arg1: "লিস্ট"
|
||||
seedRandom: "র্যানডম (সীড দ্বারা)"
|
||||
_seedRandom:
|
||||
arg1: "সীড"
|
||||
arg2: "সম্ভাব্যতা"
|
||||
seedRannum: "র্যানডম সংখ্যা (সীড দ্বারা)"
|
||||
_seedRannum:
|
||||
arg1: "সীড"
|
||||
arg2: "ন্যূনতম মান"
|
||||
arg3: "সর্বোচ্চ মান"
|
||||
seedRandomPick: "তালিকা থেকে দৈবচয়ন করুন (সীড দ্বারা)"
|
||||
_seedRandomPick:
|
||||
arg1: "সীড"
|
||||
arg2: "লিস্ট"
|
||||
DRPWPM: "সম্ভাব্যতা সহ একটি তালিকা থেকে এলোমেলোভাবে নির্বাচন করুন (প্রতিটি ব্যবহারকারীর জন্য প্রতিদিন)"
|
||||
_DRPWPM:
|
||||
arg1: "লেখার লিস্ট"
|
||||
pick: "তালিকা থেকে নির্বাচন করুন"
|
||||
_pick:
|
||||
arg1: "লিস্ট"
|
||||
arg2: "অবস্থান"
|
||||
listLen: "লিস্টের দৈর্ঘ্য পান"
|
||||
_listLen:
|
||||
arg1: "লিস্ট"
|
||||
number: "সংখ্যা"
|
||||
stringToNumber: "পাঠ্য থেকে সংখ্যা"
|
||||
_stringToNumber:
|
||||
arg1: "লেখা"
|
||||
numberToString: "সংখ্যা থেকে পাঠ্য"
|
||||
_numberToString:
|
||||
arg1: "সংখ্যা"
|
||||
splitStrByLine: "পাঠ্যকে লাইনে বিভক্ত করুন"
|
||||
_splitStrByLine:
|
||||
arg1: "লেখা"
|
||||
ref: "চলক"
|
||||
aiScriptVar: "AiScript চলক"
|
||||
fn: "ফাংশন"
|
||||
_fn:
|
||||
slots: "স্লটগুলি"
|
||||
slots-info: "প্রতিটি স্লটকে আলাদা লাইনে লিখুন"
|
||||
arg1: "আউটপুট"
|
||||
for: "for-লুপ"
|
||||
_for:
|
||||
arg1: "কতবার চলবে"
|
||||
arg2: "অ্যাকশন"
|
||||
typeError: "স্লট {slot}, {expect} ধরনের মান গ্রহণ করে, কিন্তু {actual} ধরনের মান দেওয়া হয়েছে!"
|
||||
thereIsEmptySlot: "স্লট {slot} খালি!"
|
||||
types:
|
||||
string: "লেখা"
|
||||
number: "সংখ্যা"
|
||||
boolean: "ফ্ল্যাগ"
|
||||
array: "লিস্ট"
|
||||
stringArray: "লেখার লিস্ট"
|
||||
emptySlot: "খালি স্লট"
|
||||
enviromentVariables: "এনভাইরনমেন্ট ভ্যারিয়েবল"
|
||||
pageVariables: "পেজের চলক"
|
||||
argVariables: "ইনপুটের জায়গা"
|
||||
_relayStatus:
|
||||
requesting: "অপেক্ষমান"
|
||||
accepted: "অনুমোদিত"
|
||||
|
|
|
@ -147,6 +147,25 @@ _profile:
|
|||
_exportOrImport:
|
||||
followingList: "Seguint"
|
||||
userLists: "Llistes"
|
||||
_pages:
|
||||
script:
|
||||
categories:
|
||||
list: "Llistes"
|
||||
blocks:
|
||||
_join:
|
||||
arg1: "Llistes"
|
||||
_randomPick:
|
||||
arg1: "Llistes"
|
||||
_dailyRandomPick:
|
||||
arg1: "Llistes"
|
||||
_seedRandomPick:
|
||||
arg2: "Llistes"
|
||||
_pick:
|
||||
arg1: "Llistes"
|
||||
_listLen:
|
||||
arg1: "Llistes"
|
||||
types:
|
||||
array: "Llistes"
|
||||
_notification:
|
||||
youWereFollowed: "t'ha seguit"
|
||||
_types:
|
||||
|
|
|
@ -406,6 +406,8 @@ dayOverDayChanges: "Denně"
|
|||
appearance: "Vzhled"
|
||||
clientSettings: "Nastavení klienta"
|
||||
accountSettings: "Nastavení účtu"
|
||||
promotion: "Propagace"
|
||||
promote: "Propagovat"
|
||||
numberOfDays: "Počet dní"
|
||||
deleteAll: "Smazat vše"
|
||||
showFixedPostForm: "Zobrazit formulář pro nové příspěvky nad časovou osou"
|
||||
|
@ -510,6 +512,27 @@ _charts:
|
|||
federation: "Federace"
|
||||
_timelines:
|
||||
home: "Domů"
|
||||
_pages:
|
||||
blocks:
|
||||
image: "Obrázky"
|
||||
script:
|
||||
categories:
|
||||
list: "Seznamy"
|
||||
blocks:
|
||||
_join:
|
||||
arg1: "Seznamy"
|
||||
_randomPick:
|
||||
arg1: "Seznamy"
|
||||
_dailyRandomPick:
|
||||
arg1: "Seznamy"
|
||||
_seedRandomPick:
|
||||
arg2: "Seznamy"
|
||||
_pick:
|
||||
arg1: "Seznamy"
|
||||
_listLen:
|
||||
arg1: "Seznamy"
|
||||
types:
|
||||
array: "Seznamy"
|
||||
_notification:
|
||||
youWereFollowed: "Máte nového následovníka"
|
||||
youWereInvitedToGroup: "Pozvat do skupiny"
|
||||
|
|
|
@ -473,6 +473,8 @@ dayOverDayChanges: "Veränderung zu Gestern"
|
|||
appearance: "Aussehen"
|
||||
clientSettings: "Client-Einstellungen"
|
||||
accountSettings: "Benutzerkonto-Einstellungen"
|
||||
promotion: "Werbung"
|
||||
promote: "Werbung schalten"
|
||||
numberOfDays: "Anzahl der Tage"
|
||||
hideThisNote: "Diese Notiz verstecken"
|
||||
showFeaturedNotesInTimeline: "Beliebte Notizen in der Chronik anzeigen"
|
||||
|
@ -548,6 +550,7 @@ poll: "Umfrage"
|
|||
useCw: "Inhaltswarnung verwenden"
|
||||
enablePlayer: "Video-Player öffnen"
|
||||
disablePlayer: "Video-Player schließen"
|
||||
expandTweet: "Tweet ausklappen"
|
||||
themeEditor: "Farbschema-Editor"
|
||||
description: "Beschreibung"
|
||||
describeFile: "Beschreibung hinzufügen"
|
||||
|
@ -1324,7 +1327,10 @@ _pages:
|
|||
my: "Meine Seiten"
|
||||
liked: "Seiten, die mir gefallen"
|
||||
featured: "Beliebt"
|
||||
inspector: "Inspektor"
|
||||
contents: "Inhalte"
|
||||
content: "Seitenblock"
|
||||
variables: "Variablen"
|
||||
title: "Titel"
|
||||
url: "Seiten-URL"
|
||||
summary: "Zusammenfassung"
|
||||
|
@ -1335,6 +1341,262 @@ _pages:
|
|||
fontSansSerif: "Sans Serif"
|
||||
eyeCatchingImageSet: "Vorschaubild festlegen"
|
||||
eyeCatchingImageRemove: "Vorschaubild entfernen"
|
||||
chooseBlock: "Block hinzufügen"
|
||||
selectType: "Typ auswählen"
|
||||
enterVariableName: "Gib einen Variablennamen ein"
|
||||
variableNameIsAlreadyUsed: "Dieser Name wird bereits von einer anderen Variable verwendet"
|
||||
contentBlocks: "Inhalt"
|
||||
inputBlocks: "Eingabe"
|
||||
specialBlocks: "Spezial"
|
||||
blocks:
|
||||
text: "Text"
|
||||
textarea: "Textfeld"
|
||||
section: "Abschnitt"
|
||||
image: "Bild"
|
||||
button: "Knopf"
|
||||
if: "Falls"
|
||||
_if:
|
||||
variable: "Variable"
|
||||
post: "Notizfenster"
|
||||
_post:
|
||||
text: "Inhalt"
|
||||
attachCanvasImage: "Leinwandbild anfügen"
|
||||
canvasId: "Leinwand-ID"
|
||||
textInput: "Texteingabe"
|
||||
_textInput:
|
||||
name: "Variablenname"
|
||||
text: "Titel"
|
||||
default: "Standardwert"
|
||||
textareaInput: "Mehrzeiliges Texteingabefeld"
|
||||
_textareaInput:
|
||||
name: "Variablenname"
|
||||
text: "Titel"
|
||||
default: "Standardwert"
|
||||
numberInput: "Zahleneingabe"
|
||||
_numberInput:
|
||||
name: "Variablenname"
|
||||
text: "Titel"
|
||||
default: "Standardwert"
|
||||
canvas: "Leinwand"
|
||||
_canvas:
|
||||
id: "Leinwand-ID"
|
||||
width: "Breite"
|
||||
height: "Höhe"
|
||||
note: "Eingebettete Notiz"
|
||||
_note:
|
||||
id: "Notiz-ID"
|
||||
idDescription: "Du kannst alternativ auch die Notiz-URL angeben."
|
||||
detailed: "Detailierte Ansicht"
|
||||
switch: "Fallunterscheidung"
|
||||
_switch:
|
||||
name: "Variablenname"
|
||||
text: "Titel"
|
||||
default: "Standardwert"
|
||||
counter: "Zähler"
|
||||
_counter:
|
||||
name: "Variablenname"
|
||||
text: "Titel"
|
||||
inc: "Schrittgröße"
|
||||
_button:
|
||||
text: "Titel"
|
||||
colored: "Farbig"
|
||||
action: "Aktion, die bei Knopfdruck ausgeführt wird"
|
||||
_action:
|
||||
dialog: "Dialogfenster anzeigen"
|
||||
_dialog:
|
||||
content: "Inhalt"
|
||||
resetRandom: "Zufallswert zurücksetzen"
|
||||
pushEvent: "Ein Event senden"
|
||||
_pushEvent:
|
||||
event: "Eventname"
|
||||
message: "Nachricht, die bei Auslösung des Events angezeigt werden soll"
|
||||
variable: "Variable, die gesendet werden soll"
|
||||
no-variable: "Keine"
|
||||
callAiScript: "AiScript ausführen"
|
||||
_callAiScript:
|
||||
functionName: "Funktionsname"
|
||||
radioButton: "Optionsfeld"
|
||||
_radioButton:
|
||||
name: "Variablenname"
|
||||
title: "Titel"
|
||||
values: "Durch Zeilenümbrüche getrennte Auswahlmöglichkeiten"
|
||||
default: "Standardwert"
|
||||
script:
|
||||
categories:
|
||||
flow: "Steuerung"
|
||||
logical: "Logische Operationen"
|
||||
operation: "Berechnungen"
|
||||
comparison: "Vergleiche"
|
||||
random: "Zufällig"
|
||||
value: "Werte"
|
||||
fn: "Funktionen"
|
||||
text: "Textoperationen"
|
||||
convert: "Konvertierungen"
|
||||
list: "Listen"
|
||||
blocks:
|
||||
text: "Text"
|
||||
multiLineText: "Text (Mehrzeilig)"
|
||||
textList: "Textliste"
|
||||
_textList:
|
||||
info: "Trenne jeden Eintrag mit einem Zeilenumbruch"
|
||||
strLen: "Textlänge"
|
||||
_strLen:
|
||||
arg1: "Text"
|
||||
strPick: "Text extrahieren"
|
||||
_strPick:
|
||||
arg1: "Text"
|
||||
arg2: "Textposition"
|
||||
strReplace: "Textersetzung"
|
||||
_strReplace:
|
||||
arg1: "Text"
|
||||
arg2: "Zu ersetzender Text"
|
||||
arg3: "Ersetzen mit"
|
||||
strReverse: "Text umkehren"
|
||||
_strReverse:
|
||||
arg1: "Text"
|
||||
join: "Text zusammenfügen"
|
||||
_join:
|
||||
arg1: "Liste"
|
||||
arg2: "Trennzeichen"
|
||||
add: "Addieren"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "Subtrahieren"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "Multiplizieren"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "Teilen"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "Rest"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "Rundung von Dezimalstellen"
|
||||
_round:
|
||||
arg1: "Nummer"
|
||||
eq: "A und B sind gleich"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A und B sind nicht gleich"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A UND B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A ODER B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A ist kleiner als B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A ist größer als B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A ist kleiner als oder gleich B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A ist größer als oder gleich B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "Kondition"
|
||||
_if:
|
||||
arg1: "Falls"
|
||||
arg2: "Wenn wahr"
|
||||
arg3: "Sonst"
|
||||
not: "NICHT"
|
||||
_not:
|
||||
arg1: "NICHT"
|
||||
random: "Zufällig"
|
||||
_random:
|
||||
arg1: "Warscheinlichkeit"
|
||||
rannum: "Zufallsnummer"
|
||||
_rannum:
|
||||
arg1: "Minimum"
|
||||
arg2: "Maximum"
|
||||
randomPick: "Zufallswahl aus Liste"
|
||||
_randomPick:
|
||||
arg1: "Liste"
|
||||
dailyRandom: "Zufällig (Pro Nutzer jeden Tag verschieden)"
|
||||
_dailyRandom:
|
||||
arg1: "Warscheinlichkeit"
|
||||
dailyRannum: "Zufallsnummer (Pro Nutzer jeden Tag verschieden)"
|
||||
_dailyRannum:
|
||||
arg1: "Minimum"
|
||||
arg2: "Maximum"
|
||||
dailyRandomPick: "Zufallsauswahl aus einer Liste (Pro Nutzer jeden Tag verschieden)"
|
||||
_dailyRandomPick:
|
||||
arg1: "Liste"
|
||||
seedRandom: "Zufällig (mit Startwert / Seed)"
|
||||
_seedRandom:
|
||||
arg1: "Startwert / Seed"
|
||||
arg2: "Warscheinlichkeit"
|
||||
seedRannum: "Zufallsnummer (mit Startwert / Seed)"
|
||||
_seedRannum:
|
||||
arg1: "Startwert / Seed"
|
||||
arg2: "Minimum"
|
||||
arg3: "Maximum"
|
||||
seedRandomPick: "Zufallsauswahl aus Liste (mit Startwert / Seed)"
|
||||
_seedRandomPick:
|
||||
arg1: "Startwert / Seed"
|
||||
arg2: "Liste"
|
||||
DRPWPM: "Zufallsauswahl aus gewichteter Liste (Pro Nutzer jeden Tag verschieden)"
|
||||
_DRPWPM:
|
||||
arg1: "Textliste"
|
||||
pick: "Aus einer Liste wählen"
|
||||
_pick:
|
||||
arg1: "Liste"
|
||||
arg2: "Position"
|
||||
listLen: "Listenlänge abrufen"
|
||||
_listLen:
|
||||
arg1: "Liste"
|
||||
number: "Nummer"
|
||||
stringToNumber: "Text zu Nummer"
|
||||
_stringToNumber:
|
||||
arg1: "Text"
|
||||
numberToString: "Nummer zu Text"
|
||||
_numberToString:
|
||||
arg1: "Nummer"
|
||||
splitStrByLine: "Text nach Zeilenumbrüchen aufteilen"
|
||||
_splitStrByLine:
|
||||
arg1: "Text"
|
||||
ref: "Variable"
|
||||
aiScriptVar: "AiScript Variable"
|
||||
fn: "Funktion"
|
||||
_fn:
|
||||
slots: "Slots"
|
||||
slots-info: "Trenne jeden Slot mit einem Zeilenumbruch"
|
||||
arg1: "Ausgabe"
|
||||
for: "for-Schleife"
|
||||
_for:
|
||||
arg1: "Anzahl der Schleifendurchläufe"
|
||||
arg2: "Aktion"
|
||||
typeError: "Slot {slot} akzeptiert Werte vom Typ „{expect}“, aber es wurde ein „{actual}“ Wert angegeben!"
|
||||
thereIsEmptySlot: "Slot {slot} ist leer!"
|
||||
types:
|
||||
string: "Text"
|
||||
number: "Nummer"
|
||||
boolean: "Wahrheitswert"
|
||||
array: "Liste"
|
||||
stringArray: "Textliste"
|
||||
emptySlot: "Leerer Slot"
|
||||
enviromentVariables: "Umgebungsvariable"
|
||||
pageVariables: "Seitenelemente"
|
||||
argVariables: "Eingabeslots"
|
||||
_relayStatus:
|
||||
requesting: "Ausstehend"
|
||||
accepted: "Akzeptiert"
|
||||
|
|
|
@ -473,6 +473,8 @@ dayOverDayChanges: "Changes to yesterday"
|
|||
appearance: "Appearance"
|
||||
clientSettings: "Client Settings"
|
||||
accountSettings: "Account Settings"
|
||||
promotion: "Promoted"
|
||||
promote: "Promote"
|
||||
numberOfDays: "Number of days"
|
||||
hideThisNote: "Hide this note"
|
||||
showFeaturedNotesInTimeline: "Show featured notes in timelines"
|
||||
|
@ -548,6 +550,7 @@ poll: "Poll"
|
|||
useCw: "Hide content"
|
||||
enablePlayer: "Open video player"
|
||||
disablePlayer: "Close video player"
|
||||
expandTweet: "Expand tweet"
|
||||
themeEditor: "Theme editor"
|
||||
description: "Description"
|
||||
describeFile: "Add caption"
|
||||
|
@ -1339,7 +1342,10 @@ _pages:
|
|||
my: "My Pages"
|
||||
liked: "Liked Pages"
|
||||
featured: "Popular"
|
||||
inspector: "Inspector"
|
||||
contents: "Contents"
|
||||
content: "Page block"
|
||||
variables: "Variables"
|
||||
title: "Title"
|
||||
url: "Page URL"
|
||||
summary: "Page summary"
|
||||
|
@ -1350,6 +1356,262 @@ _pages:
|
|||
fontSansSerif: "Sans Serif"
|
||||
eyeCatchingImageSet: "Set thumbnail"
|
||||
eyeCatchingImageRemove: "Delete thumbnail"
|
||||
chooseBlock: "Add a block"
|
||||
selectType: "Select a type"
|
||||
enterVariableName: "Enter a variable name"
|
||||
variableNameIsAlreadyUsed: "This variable name is already in use"
|
||||
contentBlocks: "Content"
|
||||
inputBlocks: "Input"
|
||||
specialBlocks: "Special"
|
||||
blocks:
|
||||
text: "Text"
|
||||
textarea: "Text area"
|
||||
section: "Section"
|
||||
image: "Images"
|
||||
button: "Button"
|
||||
if: "If"
|
||||
_if:
|
||||
variable: "Variable"
|
||||
post: "Posting form"
|
||||
_post:
|
||||
text: "Content"
|
||||
attachCanvasImage: "Attach canvas image"
|
||||
canvasId: "Canvas ID"
|
||||
textInput: "Text input"
|
||||
_textInput:
|
||||
name: "Variable name"
|
||||
text: "Title"
|
||||
default: "Default value"
|
||||
textareaInput: "Multiline text input"
|
||||
_textareaInput:
|
||||
name: "Variable name"
|
||||
text: "Title"
|
||||
default: "Default value"
|
||||
numberInput: "Numeric input"
|
||||
_numberInput:
|
||||
name: "Variable name"
|
||||
text: "Title"
|
||||
default: "Default value"
|
||||
canvas: "Canvas"
|
||||
_canvas:
|
||||
id: "Canvas ID"
|
||||
width: "Width"
|
||||
height: "Height"
|
||||
note: "Embedded note"
|
||||
_note:
|
||||
id: "Note ID"
|
||||
idDescription: "You can alternatively paste the note URL here."
|
||||
detailed: "Detailed view"
|
||||
switch: "Switch"
|
||||
_switch:
|
||||
name: "Variable name"
|
||||
text: "Title"
|
||||
default: "Default value"
|
||||
counter: "Counter"
|
||||
_counter:
|
||||
name: "Variable name"
|
||||
text: "Title"
|
||||
inc: "Step"
|
||||
_button:
|
||||
text: "Title"
|
||||
colored: "Colored"
|
||||
action: "Behavior when the button is pressed"
|
||||
_action:
|
||||
dialog: "Show a dialog"
|
||||
_dialog:
|
||||
content: "Content"
|
||||
resetRandom: "Reset the random seed"
|
||||
pushEvent: "Send an event"
|
||||
_pushEvent:
|
||||
event: "Event name"
|
||||
message: "Message to display when activated"
|
||||
variable: "Variable to send"
|
||||
no-variable: "None"
|
||||
callAiScript: "Invoke AiScript"
|
||||
_callAiScript:
|
||||
functionName: "Function name"
|
||||
radioButton: "Choice"
|
||||
_radioButton:
|
||||
name: "Variable name"
|
||||
title: "Title"
|
||||
values: "List of choices separated by line breaks"
|
||||
default: "Default value"
|
||||
script:
|
||||
categories:
|
||||
flow: "Flow control"
|
||||
logical: "Logical operation"
|
||||
operation: "Computation"
|
||||
comparison: "Comparison"
|
||||
random: "Random"
|
||||
value: "Values"
|
||||
fn: "Functions"
|
||||
text: "Text operations"
|
||||
convert: "Transformations"
|
||||
list: "Lists"
|
||||
blocks:
|
||||
text: "Text"
|
||||
multiLineText: "Text (multiline)"
|
||||
textList: "Text list"
|
||||
_textList:
|
||||
info: "Separate each entry with a line break"
|
||||
strLen: "Text length"
|
||||
_strLen:
|
||||
arg1: "Text"
|
||||
strPick: "Extract string"
|
||||
_strPick:
|
||||
arg1: "Text"
|
||||
arg2: "String location"
|
||||
strReplace: "Replacement string"
|
||||
_strReplace:
|
||||
arg1: "Text"
|
||||
arg2: "Text to be replaced"
|
||||
arg3: "Replace with"
|
||||
strReverse: "Flip text"
|
||||
_strReverse:
|
||||
arg1: "Text"
|
||||
join: "Text concatenation"
|
||||
_join:
|
||||
arg1: "Lists"
|
||||
arg2: "Separator"
|
||||
add: "Add"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "Subtract"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "Multiply"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "Divide"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "Remainder"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "Decimal rounding"
|
||||
_round:
|
||||
arg1: "Number"
|
||||
eq: "A and B are equal"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A and B are different"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A AND B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A OR B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A is less than B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A is larger than B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A is less than or equal to B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A is greater than or equal to B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "Branch"
|
||||
_if:
|
||||
arg1: "If"
|
||||
arg2: "Then"
|
||||
arg3: "Else"
|
||||
not: "NOT"
|
||||
_not:
|
||||
arg1: "NOT"
|
||||
random: "Random"
|
||||
_random:
|
||||
arg1: "Probability"
|
||||
rannum: "Random number"
|
||||
_rannum:
|
||||
arg1: "Minimum value"
|
||||
arg2: "Maximum value"
|
||||
randomPick: "Randomly choose from list"
|
||||
_randomPick:
|
||||
arg1: "List"
|
||||
dailyRandom: "Random (Changes once a day for each user)"
|
||||
_dailyRandom:
|
||||
arg1: "Probability"
|
||||
dailyRannum: "Random number (Changes once a day for each user)"
|
||||
_dailyRannum:
|
||||
arg1: "Minimum value"
|
||||
arg2: "Maximum value"
|
||||
dailyRandomPick: "Randomly choose from a list (Changes once a day for each user)"
|
||||
_dailyRandomPick:
|
||||
arg1: "List"
|
||||
seedRandom: "Random (with seed)"
|
||||
_seedRandom:
|
||||
arg1: "Seed"
|
||||
arg2: "Probability"
|
||||
seedRannum: "Random number (with seed)"
|
||||
_seedRannum:
|
||||
arg1: "Seed"
|
||||
arg2: "Minimum value"
|
||||
arg3: "Maximum value"
|
||||
seedRandomPick: "Randomly choose from list (with seed)"
|
||||
_seedRandomPick:
|
||||
arg1: "Seed"
|
||||
arg2: "List"
|
||||
DRPWPM: "Randomly choose from weighted list (Changes once a day for each user)"
|
||||
_DRPWPM:
|
||||
arg1: "Text list"
|
||||
pick: "Select from list"
|
||||
_pick:
|
||||
arg1: "List"
|
||||
arg2: "Position"
|
||||
listLen: "Get length of list"
|
||||
_listLen:
|
||||
arg1: "List"
|
||||
number: "Number"
|
||||
stringToNumber: "Text to number"
|
||||
_stringToNumber:
|
||||
arg1: "Text"
|
||||
numberToString: "Number to text"
|
||||
_numberToString:
|
||||
arg1: "Number"
|
||||
splitStrByLine: "Split text by line breaks"
|
||||
_splitStrByLine:
|
||||
arg1: "Text"
|
||||
ref: "Variable"
|
||||
aiScriptVar: "AiScript Variable"
|
||||
fn: "Function"
|
||||
_fn:
|
||||
slots: "Slots"
|
||||
slots-info: "Separate each slot with a line break"
|
||||
arg1: "Output"
|
||||
for: "for-Loop"
|
||||
_for:
|
||||
arg1: "Number of times to repeat"
|
||||
arg2: "Action"
|
||||
typeError: "Slot {slot} accepts values of type \"{expect}\", but the provided value is of type \"{actual}\"!"
|
||||
thereIsEmptySlot: "Slot {slot} is empty!"
|
||||
types:
|
||||
string: "Text"
|
||||
number: "Number"
|
||||
boolean: "Flag"
|
||||
array: "List"
|
||||
stringArray: "Text list"
|
||||
emptySlot: "Empty slot"
|
||||
enviromentVariables: "Environment variables"
|
||||
pageVariables: "Page variables"
|
||||
argVariables: "Input slots"
|
||||
_relayStatus:
|
||||
requesting: "Pending"
|
||||
accepted: "Accepted"
|
||||
|
|
|
@ -472,6 +472,8 @@ dayOverDayChanges: "Dif diaria"
|
|||
appearance: "Apariencia"
|
||||
clientSettings: "Configuración del cliente"
|
||||
accountSettings: "Ajustes de cuenta"
|
||||
promotion: "Promovido"
|
||||
promote: "Promover"
|
||||
numberOfDays: "Cantidad de dias"
|
||||
hideThisNote: "Ocultar esta nota"
|
||||
showFeaturedNotesInTimeline: "Mostrar notas destacadas en la línea de tiempo"
|
||||
|
@ -547,6 +549,7 @@ poll: "Encuesta"
|
|||
useCw: "Esconder contenidos"
|
||||
enablePlayer: "Abrir reproductor"
|
||||
disablePlayer: "Cerrar reproductor"
|
||||
expandTweet: "Expandir tweet"
|
||||
themeEditor: "Editor de temas"
|
||||
description: "Descripción"
|
||||
describeFile: "Añade una descripción"
|
||||
|
@ -1204,7 +1207,10 @@ _pages:
|
|||
unlike: "Quitar me gusta"
|
||||
my: "Mis páginas"
|
||||
liked: "Páginas que me gustan"
|
||||
inspector: "Inspector"
|
||||
contents: "Contenido"
|
||||
content: "Bloque de página"
|
||||
variables: "Variables"
|
||||
title: "Título"
|
||||
url: "URL de la página"
|
||||
summary: "Resumen de la página"
|
||||
|
@ -1215,6 +1221,257 @@ _pages:
|
|||
fontSansSerif: "Sans Serif"
|
||||
eyeCatchingImageSet: "Elegir imagen llamativa"
|
||||
eyeCatchingImageRemove: "Borrar imagen llamativa"
|
||||
chooseBlock: "Agregar bloque"
|
||||
selectType: "Elegir tipo"
|
||||
enterVariableName: "Ingrese el nombre de la variable"
|
||||
variableNameIsAlreadyUsed: "El nombre de la variable ya está en uso"
|
||||
contentBlocks: "Contenido"
|
||||
inputBlocks: "Entrada"
|
||||
specialBlocks: "Especial"
|
||||
blocks:
|
||||
text: "Texto"
|
||||
textarea: "Área de texto"
|
||||
section: "Sección"
|
||||
image: "Imagen"
|
||||
button: "Botón"
|
||||
if: "si"
|
||||
_if:
|
||||
variable: "Variable"
|
||||
post: "Formulario"
|
||||
_post:
|
||||
text: "Contenido"
|
||||
attachCanvasImage: "Nota con lienzo como imagen"
|
||||
canvasId: "Lienzo ID"
|
||||
textInput: "Entrada de texto"
|
||||
_textInput:
|
||||
name: "Nombre de variable"
|
||||
text: "Título"
|
||||
default: "Valor predeterminado"
|
||||
textareaInput: "Entrada de texto en múltiples lineas"
|
||||
_textareaInput:
|
||||
name: "Nombre de variable"
|
||||
text: "Título"
|
||||
default: "Valor predeterminado"
|
||||
numberInput: "Entrada numérica"
|
||||
_numberInput:
|
||||
name: "Nombre de variable"
|
||||
text: "Título"
|
||||
default: "Valor predeterminado"
|
||||
canvas: "Lienzo"
|
||||
_canvas:
|
||||
id: "Lienzo ID"
|
||||
width: "Ancho"
|
||||
height: "Altura"
|
||||
switch: "Interruptor"
|
||||
_switch:
|
||||
name: "Nombre de variable"
|
||||
text: "Título"
|
||||
default: "Valor predeterminado"
|
||||
counter: "Contador"
|
||||
_counter:
|
||||
name: "Nombre de variable"
|
||||
text: "Título"
|
||||
inc: "Aumentar cantidad"
|
||||
_button:
|
||||
text: "Título"
|
||||
colored: "Color"
|
||||
action: "Acción al presionar el botón"
|
||||
_action:
|
||||
dialog: "Mostrar cuadro de diálogo"
|
||||
_dialog:
|
||||
content: "Contenido"
|
||||
resetRandom: "Resetear número aleatorio"
|
||||
pushEvent: "Enviar evento"
|
||||
_pushEvent:
|
||||
event: "Nombre del evento"
|
||||
message: "Mensaje mostrado al apretar"
|
||||
variable: "Variable a enviar"
|
||||
no-variable: "Ninguna"
|
||||
callAiScript: "Invocar AiScript"
|
||||
_callAiScript:
|
||||
functionName: "Nombre de la función"
|
||||
radioButton: "Botón de opción"
|
||||
_radioButton:
|
||||
name: "Nombre de variable"
|
||||
title: "Título"
|
||||
values: "Opciones separadas por una nueva linea"
|
||||
default: "Valor predeterminado"
|
||||
script:
|
||||
categories:
|
||||
flow: "Control de flujo"
|
||||
logical: "Operación lógica"
|
||||
operation: "Cálculo"
|
||||
comparison: "Comparar"
|
||||
random: "Aleatorio"
|
||||
value: "Valores"
|
||||
fn: "funciones"
|
||||
text: "Manejo de texto"
|
||||
convert: "Conversion"
|
||||
list: "Listas"
|
||||
blocks:
|
||||
text: "Texto"
|
||||
multiLineText: "Texto (multilinea)"
|
||||
textList: "Lista de texto"
|
||||
_textList:
|
||||
info: "Separe cada texto con una linea nueva"
|
||||
strLen: "Largo del texto"
|
||||
_strLen:
|
||||
arg1: "Texto"
|
||||
strPick: "Extraer caracteres"
|
||||
_strPick:
|
||||
arg1: "Texto"
|
||||
arg2: "Posición del caracter"
|
||||
strReplace: "Sustituir texto"
|
||||
_strReplace:
|
||||
arg1: "Texto"
|
||||
arg2: "Texto a reemplazar"
|
||||
arg3: "Texto reemplazado"
|
||||
strReverse: "Invertir texto"
|
||||
_strReverse:
|
||||
arg1: "Texto"
|
||||
join: "Concatenar texto"
|
||||
_join:
|
||||
arg1: "Listas"
|
||||
arg2: "Separador"
|
||||
add: "Suma"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "Resta"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "Multiplicación"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "División"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "Resto"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "Redondear decimales"
|
||||
_round:
|
||||
arg1: "Número"
|
||||
eq: "A y B son iguales"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A y B son distintos"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A y B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A o B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A es menor que B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A es mayor que B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A es menor o igual que B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A es mayor o igual que B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "Si"
|
||||
_if:
|
||||
arg1: "si"
|
||||
arg2: "Entonces"
|
||||
arg3: "Si no"
|
||||
not: "Negación"
|
||||
_not:
|
||||
arg1: "Negación"
|
||||
random: "Aleatorio"
|
||||
_random:
|
||||
arg1: "probabilidad"
|
||||
rannum: "Número aleatorio"
|
||||
_rannum:
|
||||
arg1: "Mínimo"
|
||||
arg2: "Máximo"
|
||||
randomPick: "Elegir aleatoriamente de la lista"
|
||||
_randomPick:
|
||||
arg1: "Listas"
|
||||
dailyRandom: "Aleatorio (Diariamente para cada usuario)"
|
||||
_dailyRandom:
|
||||
arg1: "probabilidad"
|
||||
dailyRannum: "Número aleatorio (Diariamente para cada usuario)"
|
||||
_dailyRannum:
|
||||
arg1: "Mínimo"
|
||||
arg2: "Máximo"
|
||||
dailyRandomPick: "Elegir aleatoriamente de la lista (Diariamente para cada usuario)"
|
||||
_dailyRandomPick:
|
||||
arg1: "Listas"
|
||||
seedRandom: "Aleatorio (semilla)"
|
||||
_seedRandom:
|
||||
arg1: "Semilla"
|
||||
arg2: "probabilidad"
|
||||
seedRannum: "Número aleatorio (semilla)"
|
||||
_seedRannum:
|
||||
arg1: "Semilla"
|
||||
arg2: "Mínimo"
|
||||
arg3: "Máximo"
|
||||
seedRandomPick: "Elegir aleatoriamente de la lista (semilla)"
|
||||
_seedRandomPick:
|
||||
arg1: "Semilla"
|
||||
arg2: "Listas"
|
||||
DRPWPM: "Elegir aleatoriamente de la lista ponderada (Diariamente para cada usuario)"
|
||||
_DRPWPM:
|
||||
arg1: "Lista de texto"
|
||||
pick: "Elegir de la lista"
|
||||
_pick:
|
||||
arg1: "Listas"
|
||||
arg2: "Posición"
|
||||
listLen: "Obtener largo de la lista"
|
||||
_listLen:
|
||||
arg1: "Listas"
|
||||
number: "Número"
|
||||
stringToNumber: "De texto a número"
|
||||
_stringToNumber:
|
||||
arg1: "Texto"
|
||||
numberToString: "De número a texto"
|
||||
_numberToString:
|
||||
arg1: "Número"
|
||||
splitStrByLine: "Separar texto en lineas"
|
||||
_splitStrByLine:
|
||||
arg1: "Texto"
|
||||
ref: "Variables"
|
||||
aiScriptVar: "Variable de AiScript"
|
||||
fn: "funciones"
|
||||
_fn:
|
||||
slots: "Slots"
|
||||
slots-info: "Separe cada uno de los slots con una linea nueva"
|
||||
arg1: "Salida"
|
||||
for: "Repetir"
|
||||
_for:
|
||||
arg1: "Cantidad de repeticiones"
|
||||
arg2: "Acción"
|
||||
typeError: "El slot {slot} acepta el tipo {expect} pero fue ingresado el tipo {actual}"
|
||||
thereIsEmptySlot: "El slot {slot} está vacío"
|
||||
types:
|
||||
string: "Texto"
|
||||
number: "Número"
|
||||
boolean: "Booleano"
|
||||
array: "Listas"
|
||||
stringArray: "Lista de texto"
|
||||
emptySlot: "Slot vacío"
|
||||
enviromentVariables: "Variables de entorno"
|
||||
pageVariables: "Items de la página"
|
||||
argVariables: "Slot de entrada"
|
||||
_relayStatus:
|
||||
requesting: "Pendiente"
|
||||
accepted: "Aceptar"
|
||||
|
|
|
@ -469,6 +469,8 @@ dayOverDayChanges: "Journalier"
|
|||
appearance: "Apparence"
|
||||
clientSettings: "Paramètres du client"
|
||||
accountSettings: "Paramètres du compte"
|
||||
promotion: "Promu"
|
||||
promote: "Promouvoir"
|
||||
numberOfDays: "Nombre de jours"
|
||||
hideThisNote: "Masquer cette note"
|
||||
showFeaturedNotesInTimeline: "Afficher les notes des Tendances dans le fil d'actualité"
|
||||
|
@ -544,6 +546,7 @@ poll: "Sondage"
|
|||
useCw: "Masquer le contenu"
|
||||
enablePlayer: "Ouvrir dans le lecteur vidéo"
|
||||
disablePlayer: "Fermer le lecteur vidéo"
|
||||
expandTweet: "Étendre le tweet"
|
||||
themeEditor: "Éditeur de thèmes"
|
||||
description: "Description"
|
||||
describeFile: "Ajouter une description d'image"
|
||||
|
@ -1307,7 +1310,10 @@ _pages:
|
|||
my: "Mes pages"
|
||||
liked: "Pages favorites"
|
||||
featured: "Populaire"
|
||||
inspector: "Inspecteur"
|
||||
contents: "Contenu"
|
||||
content: "Bloc de page"
|
||||
variables: "Variables"
|
||||
title: "Titre"
|
||||
url: "URL de la page"
|
||||
summary: "Résumé de page"
|
||||
|
@ -1318,6 +1324,262 @@ _pages:
|
|||
fontSansSerif: "Sans Serif"
|
||||
eyeCatchingImageSet: "Définir une image attractive"
|
||||
eyeCatchingImageRemove: "Supprimer l'image attractive"
|
||||
chooseBlock: "Ajouter un bloc"
|
||||
selectType: "Choisir un type"
|
||||
enterVariableName: "Veuillez entrer un nom pour votre variable"
|
||||
variableNameIsAlreadyUsed: "Ce nom de variable est déjà utilisé"
|
||||
contentBlocks: "Contenu"
|
||||
inputBlocks: "Blocs d'entrée"
|
||||
specialBlocks: "Spécial"
|
||||
blocks:
|
||||
text: "Texte"
|
||||
textarea: "Zone de texte"
|
||||
section: "Section"
|
||||
image: "Images"
|
||||
button: "Bouton"
|
||||
if: "Si"
|
||||
_if:
|
||||
variable: "Variables"
|
||||
post: "Formulaire de publication"
|
||||
_post:
|
||||
text: "Contenu"
|
||||
attachCanvasImage: "Publier avec Toile comme image"
|
||||
canvasId: "Toile ID"
|
||||
textInput: "Entrée textuelle"
|
||||
_textInput:
|
||||
name: "Nom de la variable"
|
||||
text: "Titre"
|
||||
default: "Valeur par défaut"
|
||||
textareaInput: "Entrée textuelle multi-ligne"
|
||||
_textareaInput:
|
||||
name: "Nom de la variable"
|
||||
text: "Titre"
|
||||
default: "Valeur par défaut"
|
||||
numberInput: "Entrée numérique"
|
||||
_numberInput:
|
||||
name: "Nom de la variable"
|
||||
text: "Titre"
|
||||
default: "Valeur par défaut"
|
||||
canvas: "Toile"
|
||||
_canvas:
|
||||
id: "Toile ID"
|
||||
width: "Largeur"
|
||||
height: "Hauteur"
|
||||
note: "Note intégrée"
|
||||
_note:
|
||||
id: "Identifiant de la note"
|
||||
idDescription: "Pour configurer la note, vous pouvez aussi coller ici l'URL correspondante."
|
||||
detailed: "Afficher les détails"
|
||||
switch: "Interrupteur"
|
||||
_switch:
|
||||
name: "Nom de la variable"
|
||||
text: "Titre"
|
||||
default: "Valeur par défaut"
|
||||
counter: "Compteur"
|
||||
_counter:
|
||||
name: "Nom de la variable"
|
||||
text: "Titre"
|
||||
inc: "Augmenter de"
|
||||
_button:
|
||||
text: "Titre"
|
||||
colored: "Coloré"
|
||||
action: "Opération à effectuer lorsque le bouton est pressé"
|
||||
_action:
|
||||
dialog: "Afficher une fenêtre de dialogue"
|
||||
_dialog:
|
||||
content: "Contenu"
|
||||
resetRandom: "Réinitialiser un nombre aléatoire"
|
||||
pushEvent: "Envoyer un évènement"
|
||||
_pushEvent:
|
||||
event: "Nom de l’évènement"
|
||||
message: "Message à afficher lorsqu’il est activé"
|
||||
variable: "Variable à envoyer"
|
||||
no-variable: "Rien"
|
||||
callAiScript: "Appeler AiScript"
|
||||
_callAiScript:
|
||||
functionName: "Nom de la fonction"
|
||||
radioButton: "Choix"
|
||||
_radioButton:
|
||||
name: "Nom de la variable"
|
||||
title: "Titre"
|
||||
values: "Liste des choix (un par ligne)"
|
||||
default: "Valeur par défaut"
|
||||
script:
|
||||
categories:
|
||||
flow: "Contrôle"
|
||||
logical: "Opération logique"
|
||||
operation: "Calculer"
|
||||
comparison: "Comparer"
|
||||
random: "Aléatoire"
|
||||
value: "Valeur"
|
||||
fn: "Fonction"
|
||||
text: "Manipulation de texte"
|
||||
convert: "Convertir"
|
||||
list: "Listes"
|
||||
blocks:
|
||||
text: "Texte"
|
||||
multiLineText: "Texte (multi-ligne)"
|
||||
textList: "Liste de texte"
|
||||
_textList:
|
||||
info: "Veuillez séparer chaque entrée avec un saut de ligne"
|
||||
strLen: "Longueur du texte"
|
||||
_strLen:
|
||||
arg1: "Texte"
|
||||
strPick: "Extraire un caractère"
|
||||
_strPick:
|
||||
arg1: "Texte"
|
||||
arg2: "Position du joueur"
|
||||
strReplace: "Remplacement de texte"
|
||||
_strReplace:
|
||||
arg1: "Texte"
|
||||
arg2: "Avant le remplacement"
|
||||
arg3: "Après le remplacement"
|
||||
strReverse: "Inverser le texte"
|
||||
_strReverse:
|
||||
arg1: "Texte"
|
||||
join: "Concaténer du texte"
|
||||
_join:
|
||||
arg1: "Listes"
|
||||
arg2: "Séparateur"
|
||||
add: "Ajouter"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "Soustraire"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "Multiplier par"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "Diviser par"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "Reste"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "Arrondir les décimales"
|
||||
_round:
|
||||
arg1: "Numérique"
|
||||
eq: "A et B sont égaux"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A et B sont différents"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A et B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A ou B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "A est inférieur à B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "A est supérieur à B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "A est inférieur ou égal à B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: "A est supérieur ou égal à B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "Branche"
|
||||
_if:
|
||||
arg1: "Si"
|
||||
arg2: "Si"
|
||||
arg3: "Sinon"
|
||||
not: "Nier"
|
||||
_not:
|
||||
arg1: "Nier"
|
||||
random: "Aléatoire"
|
||||
_random:
|
||||
arg1: "Probabilité"
|
||||
rannum: "Nombre aléatoire"
|
||||
_rannum:
|
||||
arg1: "Minimum"
|
||||
arg2: "Maximum"
|
||||
randomPick: "Sélectionner au hasard dans la liste"
|
||||
_randomPick:
|
||||
arg1: "Listes"
|
||||
dailyRandom: "Aléatoire (Quotidien pour chaque utilisateur)"
|
||||
_dailyRandom:
|
||||
arg1: "Probabilité"
|
||||
dailyRannum: "Numéros aléatoires (Quotidien pour chaque utilisateur)"
|
||||
_dailyRannum:
|
||||
arg1: "Minimum"
|
||||
arg2: "Maximum"
|
||||
dailyRandomPick: "Sélectionné au hasard dans la liste (Quotidien pour chaque utilisateur)"
|
||||
_dailyRandomPick:
|
||||
arg1: "Listes"
|
||||
seedRandom: "Aléatoire (graine)"
|
||||
_seedRandom:
|
||||
arg1: "Graine"
|
||||
arg2: "Probabilité"
|
||||
seedRannum: "Nombre aléatoire (Graine)"
|
||||
_seedRannum:
|
||||
arg1: "Graine"
|
||||
arg2: "Minimum"
|
||||
arg3: "Maximum"
|
||||
seedRandomPick: "Sélectionné au hasard dans la liste (graine)"
|
||||
_seedRandomPick:
|
||||
arg1: "Graine"
|
||||
arg2: "Listes"
|
||||
DRPWPM: "Sélectionné au hasard dans une liste de probabilités (Quotidien pour chaque utilisateur)"
|
||||
_DRPWPM:
|
||||
arg1: "Liste de texte"
|
||||
pick: "Sélectionner dans la liste"
|
||||
_pick:
|
||||
arg1: "Listes"
|
||||
arg2: "Position"
|
||||
listLen: "Longueur de la liste"
|
||||
_listLen:
|
||||
arg1: "Listes"
|
||||
number: "Numérique"
|
||||
stringToNumber: "Convertir du texte en numérique"
|
||||
_stringToNumber:
|
||||
arg1: "Texte"
|
||||
numberToString: "Convertir du numérique en texte"
|
||||
_numberToString:
|
||||
arg1: "Numérique"
|
||||
splitStrByLine: "Séparer le texte par des sauts de lignes"
|
||||
_splitStrByLine:
|
||||
arg1: "Texte"
|
||||
ref: "Variables"
|
||||
aiScriptVar: "Variable d'AiScript"
|
||||
fn: "Fonction"
|
||||
_fn:
|
||||
slots: "Slots"
|
||||
slots-info: "Veuillez insérer un seul slot par ligne"
|
||||
arg1: "Sortie"
|
||||
for: "Répéter"
|
||||
_for:
|
||||
arg1: "Compter"
|
||||
arg2: "Action"
|
||||
typeError: "Le slot {slot} accepte \"{expect}\" mais a \"{actual}\" !"
|
||||
thereIsEmptySlot: "Slot {slot} est vide !"
|
||||
types:
|
||||
string: "Texte"
|
||||
number: "Numérique"
|
||||
boolean: "Marqueur"
|
||||
array: "Listes"
|
||||
stringArray: "Liste de texte"
|
||||
emptySlot: "Slot vide"
|
||||
enviromentVariables: "Variables d'environnement"
|
||||
pageVariables: "Élément de page"
|
||||
argVariables: "Entrée slot"
|
||||
_relayStatus:
|
||||
requesting: "En attente"
|
||||
accepted: "Accepté"
|
||||
|
|
|
@ -472,6 +472,8 @@ dayOverDayChanges: "Harian"
|
|||
appearance: "Tampilan"
|
||||
clientSettings: "Pengaturan Klien"
|
||||
accountSettings: "Pengaturan Akun"
|
||||
promotion: "Promosi"
|
||||
promote: "Promosikan"
|
||||
numberOfDays: "Jumlah hari"
|
||||
hideThisNote: "Sembunyikan catatan ini"
|
||||
showFeaturedNotesInTimeline: "Tampilkan catatan yang diunggulkan di linimasa"
|
||||
|
@ -547,6 +549,7 @@ poll: "Angket"
|
|||
useCw: "Sembunyikan konten"
|
||||
enablePlayer: "Buka pemutar video"
|
||||
disablePlayer: "Tutup pemutar video"
|
||||
expandTweet: "Perluas utas"
|
||||
themeEditor: "Penyunting tema"
|
||||
description: "Deskripsi"
|
||||
describeFile: "Tambahkan keterangan"
|
||||
|
@ -1323,7 +1326,10 @@ _pages:
|
|||
my: "Halaman saya"
|
||||
liked: "Halaman yang disukai"
|
||||
featured: "Populer"
|
||||
inspector: "Inspektor"
|
||||
contents: "Konten"
|
||||
content: "Blokir Halaman"
|
||||
variables: "Variabel"
|
||||
title: "Judul"
|
||||
url: "URL Halaman"
|
||||
summary: "Ringkasan Halaman"
|
||||
|
@ -1334,6 +1340,262 @@ _pages:
|
|||
fontSansSerif: "Sans-serif"
|
||||
eyeCatchingImageSet: "Setel gambar yang menarik"
|
||||
eyeCatchingImageRemove: "Hapus gambar yang menarik"
|
||||
chooseBlock: "Tambahkan blokir"
|
||||
selectType: "Pilih jenis"
|
||||
enterVariableName: "Mohon masukkan nama untuk variabel kamu"
|
||||
variableNameIsAlreadyUsed: "Nama ini sudah digunakan oleh variabel lain"
|
||||
contentBlocks: "Konten"
|
||||
inputBlocks: "Masukan"
|
||||
specialBlocks: "Khusus"
|
||||
blocks:
|
||||
text: "Teks"
|
||||
textarea: "Area teks"
|
||||
section: "Bagian"
|
||||
image: "Gambar"
|
||||
button: "Tombol"
|
||||
if: "Jika"
|
||||
_if:
|
||||
variable: "Variabel"
|
||||
post: "Buat catatan"
|
||||
_post:
|
||||
text: "Isi"
|
||||
attachCanvasImage: "Posting dengan kanvas sebagai gambar"
|
||||
canvasId: "ID Kanvas"
|
||||
textInput: "Masukan teks"
|
||||
_textInput:
|
||||
name: "Nama variabel"
|
||||
text: "Judul"
|
||||
default: "Nilai bawaan"
|
||||
textareaInput: "Masukan teks multibaris"
|
||||
_textareaInput:
|
||||
name: "Nama variabel"
|
||||
text: "Judul"
|
||||
default: "Nilai bawaan"
|
||||
numberInput: "Masukan angka"
|
||||
_numberInput:
|
||||
name: "Nama variabel"
|
||||
text: "Judul"
|
||||
default: "Nilai bawaan"
|
||||
canvas: "Kanvas"
|
||||
_canvas:
|
||||
id: "ID Kanvas"
|
||||
width: "Lebar"
|
||||
height: "Tinggi"
|
||||
note: "Catatan yang ditanam"
|
||||
_note:
|
||||
id: "ID Catatan"
|
||||
idDescription: "Kamu dapat menyetel ini dengan menempelkan tautan URL Catatan."
|
||||
detailed: "Tampilan rincian"
|
||||
switch: "Beralih"
|
||||
_switch:
|
||||
name: "Nama variabel"
|
||||
text: "Judul"
|
||||
default: "Nilai bawaan"
|
||||
counter: "Penghitung"
|
||||
_counter:
|
||||
name: "Nama variabel"
|
||||
text: "Judul"
|
||||
inc: "Meningkat dengan"
|
||||
_button:
|
||||
text: "Judul"
|
||||
colored: "Diwarnai"
|
||||
action: "Operasi akan dimulai ketika tombol ditekan"
|
||||
_action:
|
||||
dialog: "Tampilkan dialog"
|
||||
_dialog:
|
||||
content: "Isi"
|
||||
resetRandom: "Atur ulang benih acak"
|
||||
pushEvent: "Kirim event"
|
||||
_pushEvent:
|
||||
event: "Nama event"
|
||||
message: "Pesan yang tampil ketika diaktifkan"
|
||||
variable: "Variable untuk kirim"
|
||||
no-variable: "Tidak ada"
|
||||
callAiScript: "Panggil AiScript"
|
||||
_callAiScript:
|
||||
functionName: "Nama fungsi"
|
||||
radioButton: "Pilihan"
|
||||
_radioButton:
|
||||
name: "Nama variabel"
|
||||
title: "Judul"
|
||||
values: "Daftar pilihan (dipisahkan dengan garis baru)"
|
||||
default: "Nilai bawaan"
|
||||
script:
|
||||
categories:
|
||||
flow: "Arus kendali"
|
||||
logical: "Operasi logis"
|
||||
operation: "Menghitung"
|
||||
comparison: "Membandingkan"
|
||||
random: "Acak"
|
||||
value: "Nilai"
|
||||
fn: "Fungsi"
|
||||
text: "Operasi teks"
|
||||
convert: "Mengubah"
|
||||
list: "Daftar"
|
||||
blocks:
|
||||
text: "Teks"
|
||||
multiLineText: "Teks (multibaris)"
|
||||
textList: "Daftar teks"
|
||||
_textList:
|
||||
info: "Pisahkan setiap entri dengan baris baru"
|
||||
strLen: "Panjang teks"
|
||||
_strLen:
|
||||
arg1: "Teks"
|
||||
strPick: "Ekstrak karakter"
|
||||
_strPick:
|
||||
arg1: "Teks"
|
||||
arg2: "Lokasi karakter"
|
||||
strReplace: "Penggantian teks"
|
||||
_strReplace:
|
||||
arg1: "Teks"
|
||||
arg2: "Teks yang akan diganti"
|
||||
arg3: "Diganti dengan"
|
||||
strReverse: "Balikkan teks"
|
||||
_strReverse:
|
||||
arg1: "Teks"
|
||||
join: "Rangkaian teks"
|
||||
_join:
|
||||
arg1: "Daftar"
|
||||
arg2: "Pemisah"
|
||||
add: "Tambah"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "Kurangi"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "Kali"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "Bagi"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "Sisa"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "Bulat desimal"
|
||||
_round:
|
||||
arg1: "Angka"
|
||||
eq: "A dan B adalah sama"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A dan B adalah berbeda"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A DAN B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A ATAU B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A ikurang dari B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A lebih dari B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A kurang dari sama dengan B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A lebih dari sama dengan B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "Cabang"
|
||||
_if:
|
||||
arg1: "Jika"
|
||||
arg2: "Jika benar"
|
||||
arg3: "Jika salah"
|
||||
not: "BUKAN"
|
||||
_not:
|
||||
arg1: "NOT"
|
||||
random: "Acak"
|
||||
_random:
|
||||
arg1: "Probabilitas"
|
||||
rannum: "Angka acak"
|
||||
_rannum:
|
||||
arg1: "Nilai minimum"
|
||||
arg2: "Nilai maksimum"
|
||||
randomPick: "Pilih secara acak dari daftar"
|
||||
_randomPick:
|
||||
arg1: "Daftar"
|
||||
dailyRandom: "Acak (bertahan sehari)"
|
||||
_dailyRandom:
|
||||
arg1: "Probabilitas"
|
||||
dailyRannum: "Angka acak (bertahan sehari)"
|
||||
_dailyRannum:
|
||||
arg1: "Nilai minimum"
|
||||
arg2: "Nilai maksimum"
|
||||
dailyRandomPick: "Pilih secara acak dari daftar (bertahan sehari)"
|
||||
_dailyRandomPick:
|
||||
arg1: "Daftar"
|
||||
seedRandom: "Acak (dengan seed)"
|
||||
_seedRandom:
|
||||
arg1: "Seed"
|
||||
arg2: "Probabilitas"
|
||||
seedRannum: "Angka acak (dengan seed)"
|
||||
_seedRannum:
|
||||
arg1: "Seed"
|
||||
arg2: "Nilai minimum"
|
||||
arg3: "Nilai maksimum"
|
||||
seedRandomPick: "Pilih secara acak dari daftar (dengan seed)"
|
||||
_seedRandomPick:
|
||||
arg1: "Seed"
|
||||
arg2: "Daftar"
|
||||
DRPWPM: "Pilih secara acak dari daftar berbobot (bertahan sehari)"
|
||||
_DRPWPM:
|
||||
arg1: "Daftar teks"
|
||||
pick: "Pilih dari daftar"
|
||||
_pick:
|
||||
arg1: "Daftar"
|
||||
arg2: "Posisi"
|
||||
listLen: "Dapatkan panjangnya dari daftar"
|
||||
_listLen:
|
||||
arg1: "Daftar"
|
||||
number: "Angka"
|
||||
stringToNumber: "Teks ke angka"
|
||||
_stringToNumber:
|
||||
arg1: "Teks"
|
||||
numberToString: "Angka ke teks"
|
||||
_numberToString:
|
||||
arg1: "Angka"
|
||||
splitStrByLine: "Pisahkan teks dengan baris baru"
|
||||
_splitStrByLine:
|
||||
arg1: "Teks"
|
||||
ref: "Variabel"
|
||||
aiScriptVar: "Variabel AiScript"
|
||||
fn: "Fungsi"
|
||||
_fn:
|
||||
slots: "Slot"
|
||||
slots-info: "Pisahkan setiap slot dengan baris baru"
|
||||
arg1: "Keluaran"
|
||||
for: "Ulangi"
|
||||
_for:
|
||||
arg1: "Jumlah angka untuk diulangi"
|
||||
arg2: "Aksi"
|
||||
typeError: "Slot {slot} menerima tipe \"{expect}\", sayangnya nilai yang disediakan adalah \"{actual}\"!"
|
||||
thereIsEmptySlot: "Slot {slot} kosong!"
|
||||
types:
|
||||
string: "Teks"
|
||||
number: "Angka"
|
||||
boolean: "Markah"
|
||||
array: "Daftar"
|
||||
stringArray: "Daftar teks"
|
||||
emptySlot: "Slot kosong"
|
||||
enviromentVariables: "Variabel Lingkungan"
|
||||
pageVariables: "Elemen halaman"
|
||||
argVariables: "Masukan slot"
|
||||
_relayStatus:
|
||||
requesting: "Menunggu"
|
||||
accepted: "Disetujui"
|
||||
|
|
|
@ -468,6 +468,8 @@ dayOverDayChanges: "Giornaliero"
|
|||
appearance: "Aspetto"
|
||||
clientSettings: "Impostazioni client"
|
||||
accountSettings: "Impostazioni account"
|
||||
promotion: "Promossa"
|
||||
promote: "Pubblicizza"
|
||||
numberOfDays: "Numero di giorni"
|
||||
hideThisNote: "Nasconda la nota"
|
||||
showFeaturedNotesInTimeline: "Mostrare le note di tendenza nella tua timeline"
|
||||
|
@ -543,6 +545,7 @@ poll: "Sondaggio"
|
|||
useCw: "Nascondere media"
|
||||
enablePlayer: "Apri in lettore video"
|
||||
disablePlayer: "Chiudi lettore video"
|
||||
expandTweet: "Espandi tweet"
|
||||
themeEditor: "Editor di temi"
|
||||
description: "Descrizione"
|
||||
describeFile: "Aggiungi una descrizione d'immagine"
|
||||
|
@ -1223,6 +1226,8 @@ _pages:
|
|||
liked: "Pagine che mi piacciono"
|
||||
featured: "Popolari"
|
||||
contents: "Contenuto"
|
||||
content: "Blocco di pagina"
|
||||
variables: "Variabili"
|
||||
title: "Titolo"
|
||||
url: "URL della pagina"
|
||||
summary: "Riassunto di pagina"
|
||||
|
@ -1232,6 +1237,172 @@ _pages:
|
|||
fontSansSerif: "Sans serif"
|
||||
eyeCatchingImageSet: "Imposta un'immagine attrattiva"
|
||||
eyeCatchingImageRemove: "Elimina l'immagine attrattiva"
|
||||
chooseBlock: "Aggiungi blocco"
|
||||
selectType: "Seleziona tipo"
|
||||
enterVariableName: "Digita un nome di variabile"
|
||||
variableNameIsAlreadyUsed: "Esiste già una variabile con lo stesso nome"
|
||||
contentBlocks: "Contenuto"
|
||||
inputBlocks: "Blocchi di input"
|
||||
specialBlocks: "Speciale"
|
||||
blocks:
|
||||
text: "Testo"
|
||||
textarea: "Area di testo"
|
||||
section: "Sezione"
|
||||
image: "Immagini"
|
||||
button: "Pulsante"
|
||||
if: "Se"
|
||||
_if:
|
||||
variable: "Variabili"
|
||||
post: "Finestra di pubblicazione"
|
||||
_post:
|
||||
text: "Contenuto"
|
||||
textInput: "Immissione testo"
|
||||
_textInput:
|
||||
name: "Nome della variabile"
|
||||
text: "Titolo"
|
||||
default: "Valore predefinito"
|
||||
textareaInput: "Immissione testo a più righe"
|
||||
_textareaInput:
|
||||
name: "Nome della variabile"
|
||||
text: "Titolo"
|
||||
default: "Valore predefinito"
|
||||
numberInput: "Immissione numerica"
|
||||
_numberInput:
|
||||
name: "Nome della variabile"
|
||||
text: "Titolo"
|
||||
default: "Valore predefinito"
|
||||
_canvas:
|
||||
width: "Larghezza"
|
||||
height: "Altezza"
|
||||
note: "Nota integrata"
|
||||
_note:
|
||||
id: "ID nota"
|
||||
idDescription: "Qui puoi anche incollare l'URL della nota che vuoi impostare."
|
||||
detailed: "Visualizzazione dettagliata"
|
||||
switch: "Interruttore"
|
||||
_switch:
|
||||
name: "Nome della variabile"
|
||||
text: "Titolo"
|
||||
default: "Valore predefinito"
|
||||
counter: "Contatore"
|
||||
_counter:
|
||||
name: "Nome della variabile"
|
||||
text: "Titolo"
|
||||
inc: "Valore da aggiungere"
|
||||
_button:
|
||||
text: "Titolo"
|
||||
colored: "Colorato"
|
||||
action: "Operazione da eseguire quando viene premuto il pulsante"
|
||||
_action:
|
||||
dialog: "Visualizzare una finestra di dialogo"
|
||||
_dialog:
|
||||
content: "Contenuto"
|
||||
resetRandom: "Ripristinare un numero aleatorio"
|
||||
pushEvent: "Inviare evento"
|
||||
_pushEvent:
|
||||
event: "Nome evento"
|
||||
message: "Messaggio da visualizzare quando abilitato"
|
||||
variable: "Variabile da inviare"
|
||||
no-variable: "Nessun contenuto"
|
||||
callAiScript: "Chiamare AiScript"
|
||||
_callAiScript:
|
||||
functionName: "Nome della funzione"
|
||||
radioButton: "Opzioni"
|
||||
_radioButton:
|
||||
name: "Nome della variabile"
|
||||
title: "Titolo"
|
||||
default: "Valore predefinito"
|
||||
script:
|
||||
categories:
|
||||
comparison: "Metodo comparativo"
|
||||
random: "Aleatorietà"
|
||||
value: "Valore"
|
||||
fn: "Funzione"
|
||||
list: "Liste"
|
||||
blocks:
|
||||
text: "Testo"
|
||||
multiLineText: "Testo (a più righe)"
|
||||
textList: "Lista di testo"
|
||||
_strLen:
|
||||
arg1: "Testo"
|
||||
_strPick:
|
||||
arg1: "Testo"
|
||||
_strReplace:
|
||||
arg1: "Testo"
|
||||
_strReverse:
|
||||
arg1: "Testo"
|
||||
_join:
|
||||
arg1: "Liste"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A e B sono differenti"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A e B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A o B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_if:
|
||||
arg1: "Se"
|
||||
arg2: "Se"
|
||||
random: "Aleatorietà"
|
||||
_randomPick:
|
||||
arg1: "Liste"
|
||||
_dailyRandomPick:
|
||||
arg1: "Liste"
|
||||
_seedRandom:
|
||||
arg2: "Probabilità"
|
||||
_seedRandomPick:
|
||||
arg2: "Liste"
|
||||
_DRPWPM:
|
||||
arg1: "Lista di testo"
|
||||
_pick:
|
||||
arg1: "Liste"
|
||||
_listLen:
|
||||
arg1: "Liste"
|
||||
_stringToNumber:
|
||||
arg1: "Testo"
|
||||
_splitStrByLine:
|
||||
arg1: "Testo"
|
||||
ref: "Variabili"
|
||||
fn: "Funzione"
|
||||
types:
|
||||
string: "Testo"
|
||||
array: "Liste"
|
||||
stringArray: "Lista di testo"
|
||||
_relayStatus:
|
||||
requesting: "In attesa di approvazione"
|
||||
accepted: "Approvato"
|
||||
|
|
|
@ -473,6 +473,8 @@ dayOverDayChanges: "前日比"
|
|||
appearance: "アピアランス"
|
||||
clientSettings: "クライアント設定"
|
||||
accountSettings: "アカウント設定"
|
||||
promotion: "プロモーション"
|
||||
promote: "プロモート"
|
||||
numberOfDays: "日数"
|
||||
hideThisNote: "このノートを非表示"
|
||||
showFeaturedNotesInTimeline: "タイムラインにおすすめのノートを表示する"
|
||||
|
@ -548,6 +550,7 @@ poll: "アンケート"
|
|||
useCw: "内容を隠す"
|
||||
enablePlayer: "プレイヤーを開く"
|
||||
disablePlayer: "プレイヤーを閉じる"
|
||||
expandTweet: "ツイートを展開する"
|
||||
themeEditor: "テーマエディター"
|
||||
description: "説明"
|
||||
describeFile: "キャプションを付ける"
|
||||
|
@ -1380,7 +1383,10 @@ _pages:
|
|||
my: "自分のページ"
|
||||
liked: "いいねしたページ"
|
||||
featured: "人気"
|
||||
inspector: "インスペクター"
|
||||
contents: "コンテンツ"
|
||||
content: "ページブロック"
|
||||
variables: "変数"
|
||||
title: "タイトル"
|
||||
url: "ページURL"
|
||||
summary: "ページの要約"
|
||||
|
@ -1391,6 +1397,274 @@ _pages:
|
|||
fontSansSerif: "サンセリフ"
|
||||
eyeCatchingImageSet: "アイキャッチ画像を設定"
|
||||
eyeCatchingImageRemove: "アイキャッチ画像を削除"
|
||||
chooseBlock: "ブロックを追加"
|
||||
selectType: "種類を選択"
|
||||
enterVariableName: "変数名を決めてください"
|
||||
variableNameIsAlreadyUsed: "その変数名は既に使われています"
|
||||
contentBlocks: "コンテンツ"
|
||||
inputBlocks: "入力"
|
||||
specialBlocks: "特殊"
|
||||
blocks:
|
||||
text: "テキスト"
|
||||
textarea: "テキストエリア"
|
||||
section: "セクション"
|
||||
image: "画像"
|
||||
button: "ボタン"
|
||||
|
||||
if: "もし"
|
||||
_if:
|
||||
variable: "変数"
|
||||
|
||||
post: "投稿フォーム"
|
||||
_post:
|
||||
text: "内容"
|
||||
attachCanvasImage: "キャンバスの画像を添付する"
|
||||
canvasId: "キャンバスID"
|
||||
|
||||
textInput: "テキスト入力"
|
||||
_textInput:
|
||||
name: "変数名"
|
||||
text: "タイトル"
|
||||
default: "デフォルト値"
|
||||
|
||||
textareaInput: "複数行テキスト入力"
|
||||
_textareaInput:
|
||||
name: "変数名"
|
||||
text: "タイトル"
|
||||
default: "デフォルト値"
|
||||
|
||||
numberInput: "数値入力"
|
||||
_numberInput:
|
||||
name: "変数名"
|
||||
text: "タイトル"
|
||||
default: "デフォルト値"
|
||||
|
||||
canvas: "キャンバス"
|
||||
_canvas:
|
||||
id: "キャンバスID"
|
||||
width: "幅"
|
||||
height: "高さ"
|
||||
|
||||
note: "ノート埋め込み"
|
||||
_note:
|
||||
id: "ノートID"
|
||||
idDescription: "ノートURLをペーストして設定することもできます。"
|
||||
detailed: "詳細な表示"
|
||||
|
||||
switch: "スイッチ"
|
||||
_switch:
|
||||
name: "変数名"
|
||||
text: "タイトル"
|
||||
default: "デフォルト値"
|
||||
|
||||
counter: "カウンター"
|
||||
_counter:
|
||||
name: "変数名"
|
||||
text: "タイトル"
|
||||
inc: "増加値"
|
||||
|
||||
_button:
|
||||
text: "タイトル"
|
||||
colored: "色付き"
|
||||
action: "ボタンを押したときの動作"
|
||||
_action:
|
||||
dialog: "ダイアログを表示する"
|
||||
_dialog:
|
||||
content: "内容"
|
||||
resetRandom: "乱数をリセット"
|
||||
pushEvent: "イベントを送信させる"
|
||||
_pushEvent:
|
||||
event: "イベント名"
|
||||
message: "押したときに表示するメッセージ"
|
||||
variable: "送信する変数"
|
||||
no-variable: "なし"
|
||||
callAiScript: "AiScript呼び出し"
|
||||
_callAiScript:
|
||||
functionName: "関数名"
|
||||
|
||||
radioButton: "選択肢"
|
||||
_radioButton:
|
||||
name: "変数名"
|
||||
title: "タイトル"
|
||||
values: "改行で区切った選択肢"
|
||||
default: "デフォルト値"
|
||||
|
||||
script:
|
||||
categories:
|
||||
flow: "制御"
|
||||
logical: "論理演算"
|
||||
operation: "計算"
|
||||
comparison: "比較"
|
||||
random: "ランダム"
|
||||
value: "値"
|
||||
fn: "関数"
|
||||
text: "テキスト操作"
|
||||
convert: "変換"
|
||||
list: "リスト"
|
||||
blocks:
|
||||
text: "テキスト"
|
||||
multiLineText: "テキスト(複数行)"
|
||||
textList: "テキストのリスト"
|
||||
_textList:
|
||||
info: "ひとつひとつを改行で区切ってください"
|
||||
strLen: "テキストの長さ"
|
||||
_strLen:
|
||||
arg1: "テキスト"
|
||||
strPick: "文字取り出し"
|
||||
_strPick:
|
||||
arg1: "テキスト"
|
||||
arg2: "文字の位置"
|
||||
strReplace: "テキスト置き換え"
|
||||
_strReplace:
|
||||
arg1: "テキスト"
|
||||
arg2: "置き換え前"
|
||||
arg3: "置き換え後"
|
||||
strReverse: "テキストを反転"
|
||||
_strReverse:
|
||||
arg1: "テキスト"
|
||||
join: "テキストを連結"
|
||||
_join:
|
||||
arg1: "リスト"
|
||||
arg2: "区切り"
|
||||
add: "足す"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "引く"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "掛ける"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "割る"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "割った余り"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "小数を丸める"
|
||||
_round:
|
||||
arg1: "数値"
|
||||
eq: "AとBが同じ"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "AとBが異なる"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "AかつB"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "AまたはB"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< AがBより小さい"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> AがBより大きい"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= AがBと同じか小さい"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= AがBと同じか大きい"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "分岐"
|
||||
_if:
|
||||
arg1: "もし"
|
||||
arg2: "なら"
|
||||
arg3: "そうでなければ"
|
||||
not: "否定"
|
||||
_not:
|
||||
arg1: "否定"
|
||||
random: "ランダム"
|
||||
_random:
|
||||
arg1: "確率"
|
||||
rannum: "乱数"
|
||||
_rannum:
|
||||
arg1: "最小"
|
||||
arg2: "最大"
|
||||
randomPick: "リストからランダムに選択"
|
||||
_randomPick:
|
||||
arg1: "リスト"
|
||||
dailyRandom: "ランダム (ユーザーごとに日替わり)"
|
||||
_dailyRandom:
|
||||
arg1: "確率"
|
||||
dailyRannum: "乱数 (ユーザーごとに日替わり)"
|
||||
_dailyRannum:
|
||||
arg1: "最小"
|
||||
arg2: "最大"
|
||||
dailyRandomPick: "リストからランダムに選択 (ユーザーごとに日替わり)"
|
||||
_dailyRandomPick:
|
||||
arg1: "リスト"
|
||||
seedRandom: "ランダム (シード)"
|
||||
_seedRandom:
|
||||
arg1: "シード"
|
||||
arg2: "確率"
|
||||
seedRannum: "乱数 (シード)"
|
||||
_seedRannum:
|
||||
arg1: "シード"
|
||||
arg2: "最小"
|
||||
arg3: "最大"
|
||||
seedRandomPick: "リストからランダムに選択 (シード)"
|
||||
_seedRandomPick:
|
||||
arg1: "シード"
|
||||
arg2: "リスト"
|
||||
DRPWPM: "確率付きリストからランダムに選択 (ユーザーごとに日替わり)"
|
||||
_DRPWPM:
|
||||
arg1: "テキストのリスト"
|
||||
pick: "リストから選択"
|
||||
_pick:
|
||||
arg1: "リスト"
|
||||
arg2: "位置"
|
||||
listLen: "リストの長さを取得"
|
||||
_listLen:
|
||||
arg1: "リスト"
|
||||
number: "数値"
|
||||
stringToNumber: "テキストを数値に"
|
||||
_stringToNumber:
|
||||
arg1: "テキスト"
|
||||
numberToString: "数値をテキストに"
|
||||
_numberToString:
|
||||
arg1: "数値"
|
||||
splitStrByLine: "テキストを行で分割"
|
||||
_splitStrByLine:
|
||||
arg1: "テキスト"
|
||||
ref: "変数"
|
||||
aiScriptVar: "AiScript変数"
|
||||
fn: "関数"
|
||||
_fn:
|
||||
slots: "スロット"
|
||||
slots-info: "スロットひとつひとつを改行で区切ってください"
|
||||
arg1: "出力"
|
||||
for: "繰り返し"
|
||||
_for:
|
||||
arg1: "回数"
|
||||
arg2: "処理"
|
||||
typeError: "スロット{slot}は\"{expect}\"を受け付けますが、\"{actual}\"が入れられています!"
|
||||
thereIsEmptySlot: "スロット{slot}が空です!"
|
||||
types:
|
||||
string: "テキスト"
|
||||
number: "数値"
|
||||
boolean: "フラグ"
|
||||
array: "リスト"
|
||||
stringArray: "テキストのリスト"
|
||||
emptySlot: "空のスロット"
|
||||
enviromentVariables: "環境変数"
|
||||
pageVariables: "ページ要素"
|
||||
argVariables: "入力スロット"
|
||||
|
||||
_relayStatus:
|
||||
requesting: "承認待ち"
|
||||
|
|
|
@ -462,6 +462,8 @@ dayOverDayChanges: "前日比"
|
|||
appearance: "見た目"
|
||||
clientSettings: "クライアントの設定"
|
||||
accountSettings: "アカウントの設定"
|
||||
promotion: "宣伝"
|
||||
promote: "宣伝"
|
||||
numberOfDays: "日数"
|
||||
hideThisNote: "このノートは表示せんでいい"
|
||||
showFeaturedNotesInTimeline: "タイムラインにおすすめのノートを表示してや"
|
||||
|
@ -522,6 +524,7 @@ addedRelays: "追加済みのリレー"
|
|||
poll: "アンケート"
|
||||
enablePlayer: "プレイヤーを開く"
|
||||
disablePlayer: "プレイヤーを閉じる"
|
||||
expandTweet: "ツイートを展開する"
|
||||
themeEditor: "テーマエディター"
|
||||
description: "説明"
|
||||
author: "作者"
|
||||
|
@ -932,6 +935,252 @@ _pages:
|
|||
fontSansSerif: "サンセリフ"
|
||||
eyeCatchingImageSet: "アイキャッチ画像を設定"
|
||||
eyeCatchingImageRemove: "アイキャッチ画像を削除"
|
||||
chooseBlock: "ブロックを追加"
|
||||
selectType: "種類を選択"
|
||||
contentBlocks: "コンテンツ"
|
||||
inputBlocks: "入力"
|
||||
specialBlocks: "特殊"
|
||||
blocks:
|
||||
text: "テキスト"
|
||||
textarea: "テキストエリア"
|
||||
section: "セクション"
|
||||
image: "画像"
|
||||
button: "ボタン"
|
||||
if: "もし"
|
||||
_if:
|
||||
variable: "変数"
|
||||
post: "投稿フォーム"
|
||||
_post:
|
||||
text: "内容"
|
||||
canvasId: "キャンバスID"
|
||||
textInput: "テキスト入力"
|
||||
_textInput:
|
||||
name: "変数名"
|
||||
text: "タイトル"
|
||||
default: "デフォルト値"
|
||||
textareaInput: "複数行テキスト入力"
|
||||
_textareaInput:
|
||||
name: "変数名"
|
||||
text: "タイトル"
|
||||
default: "デフォルト値"
|
||||
numberInput: "数値入力"
|
||||
_numberInput:
|
||||
name: "変数名"
|
||||
text: "タイトル"
|
||||
default: "デフォルト値"
|
||||
canvas: "キャンバス"
|
||||
_canvas:
|
||||
id: "キャンバスID"
|
||||
width: "幅"
|
||||
height: "高さ"
|
||||
note: "ノート埋め込み"
|
||||
_note:
|
||||
id: "ノートID"
|
||||
detailed: "詳細な表示"
|
||||
switch: "スイッチ"
|
||||
_switch:
|
||||
name: "変数名"
|
||||
text: "タイトル"
|
||||
default: "デフォルト値"
|
||||
counter: "カウンター"
|
||||
_counter:
|
||||
name: "変数名"
|
||||
text: "タイトル"
|
||||
inc: "増加値"
|
||||
_button:
|
||||
text: "タイトル"
|
||||
colored: "色付き"
|
||||
action: "ボタンを押したときの動作"
|
||||
_action:
|
||||
dialog: "ダイアログを表示する"
|
||||
_dialog:
|
||||
content: "内容"
|
||||
resetRandom: "乱数をリセット"
|
||||
pushEvent: "イベントを送信させる"
|
||||
_pushEvent:
|
||||
event: "イベント名"
|
||||
no-variable: "なし"
|
||||
callAiScript: "AiScript呼び出し"
|
||||
_callAiScript:
|
||||
functionName: "関数名"
|
||||
radioButton: "選択肢"
|
||||
_radioButton:
|
||||
name: "変数名"
|
||||
title: "タイトル"
|
||||
values: "改行で区切った選択肢"
|
||||
default: "デフォルト値"
|
||||
script:
|
||||
categories:
|
||||
flow: "制御"
|
||||
logical: "論理演算"
|
||||
operation: "計算"
|
||||
comparison: "比較"
|
||||
random: "ランダム"
|
||||
value: "値"
|
||||
fn: "関数"
|
||||
text: "関数"
|
||||
convert: "変換"
|
||||
list: "リスト"
|
||||
blocks:
|
||||
text: "テキスト"
|
||||
multiLineText: "テキスト(複数行)"
|
||||
textList: "テキストのリスト"
|
||||
strLen: "テキストの長さ"
|
||||
_strLen:
|
||||
arg1: "テキスト"
|
||||
strPick: "文字取り出し"
|
||||
_strPick:
|
||||
arg1: "テキスト"
|
||||
arg2: "文字の位置"
|
||||
strReplace: "テキスト置き換え"
|
||||
_strReplace:
|
||||
arg1: "テキスト"
|
||||
arg2: "置き換え前"
|
||||
arg3: "置き換え後"
|
||||
strReverse: "テキストを反転"
|
||||
_strReverse:
|
||||
arg1: "テキスト"
|
||||
join: "テキストを連結"
|
||||
_join:
|
||||
arg1: "リスト"
|
||||
arg2: "区切り"
|
||||
add: "足す"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "引く"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "A"
|
||||
multiply: "掛ける"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "割る"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "割った余り"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "小数を丸める"
|
||||
_round:
|
||||
arg1: "数値"
|
||||
eq: "AとBが同じ"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "AとBが異なる"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "AかつB"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "AまたはB"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< AがBより小さい"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> AがBより大きい"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= AがBと同じか小さい"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= AがBと同じか大きい"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "分岐"
|
||||
_if:
|
||||
arg1: "もし"
|
||||
arg2: "なら"
|
||||
arg3: "そうでなければ"
|
||||
not: "否定"
|
||||
_not:
|
||||
arg1: "否定"
|
||||
random: "ランダム"
|
||||
_random:
|
||||
arg1: "確率"
|
||||
rannum: "乱数"
|
||||
_rannum:
|
||||
arg1: "最小"
|
||||
arg2: "最大"
|
||||
randomPick: "リストからランダムに選ぶ"
|
||||
_randomPick:
|
||||
arg1: "リスト"
|
||||
dailyRandom: "ランダム (ユーザーごとに日替わり)"
|
||||
_dailyRandom:
|
||||
arg1: "確率"
|
||||
dailyRannum: "乱数 (ユーザーごとに日替わり)"
|
||||
_dailyRannum:
|
||||
arg1: "最小"
|
||||
arg2: "最大"
|
||||
dailyRandomPick: "リストからランダムに選ぶ (ユーザーごとに日替わり)"
|
||||
_dailyRandomPick:
|
||||
arg1: "リスト"
|
||||
seedRandom: "ランダム (シード)"
|
||||
_seedRandom:
|
||||
arg1: "シード"
|
||||
arg2: "確率"
|
||||
seedRannum: "乱数 (シード)"
|
||||
_seedRannum:
|
||||
arg1: "シード"
|
||||
arg2: "最小"
|
||||
arg3: "最大"
|
||||
seedRandomPick: "リストからランダムに選択 (シード)"
|
||||
_seedRandomPick:
|
||||
arg1: "シード"
|
||||
arg2: "リスト"
|
||||
DRPWPM: "確率付きリストからランダムに選ぶ (ユーザーごとに日替わり)"
|
||||
_DRPWPM:
|
||||
arg1: "テキストのリスト"
|
||||
pick: "リストから選ぶ"
|
||||
_pick:
|
||||
arg1: "リスト"
|
||||
arg2: "位置"
|
||||
listLen: "リストの長さを取得"
|
||||
_listLen:
|
||||
arg1: "リスト"
|
||||
number: "数値"
|
||||
stringToNumber: "テキストを数値に"
|
||||
_stringToNumber:
|
||||
arg1: "テキスト"
|
||||
numberToString: "数値をテキストに"
|
||||
_numberToString:
|
||||
arg1: "数値"
|
||||
splitStrByLine: "テキストを行で分割"
|
||||
_splitStrByLine:
|
||||
arg1: "テキスト"
|
||||
ref: "変数"
|
||||
aiScriptVar: "AiScript変数"
|
||||
fn: "関数"
|
||||
_fn:
|
||||
slots: "スロット"
|
||||
arg1: "出力"
|
||||
for: "繰り返し"
|
||||
_for:
|
||||
arg1: "回数"
|
||||
arg2: "処理"
|
||||
thereIsEmptySlot: "スロット{slot}が空っぽやで!"
|
||||
types:
|
||||
string: "テキスト"
|
||||
number: "数値"
|
||||
boolean: "フラグ"
|
||||
array: "リスト"
|
||||
stringArray: "テキストのリスト"
|
||||
emptySlot: "空のスロット"
|
||||
enviromentVariables: "環境変数"
|
||||
pageVariables: "ページ要素"
|
||||
argVariables: "入力スロット"
|
||||
_notification:
|
||||
fileUploaded: "ファイルが無事アップロードされたで。"
|
||||
youGotMention: "{name}からのメンション"
|
||||
|
|
|
@ -88,6 +88,28 @@ _pages:
|
|||
fontSerif: "Serif"
|
||||
fontSansSerif: "Sans Serif"
|
||||
eyeCatchingImageRemove: "Kkes tugna i d-ijebden"
|
||||
selectType: "Fren anaw"
|
||||
contentBlocks: "Agbur"
|
||||
inputBlocks: "Anekcum"
|
||||
specialBlocks: "Uzzig"
|
||||
script:
|
||||
categories:
|
||||
list: "Tibdarin"
|
||||
blocks:
|
||||
_join:
|
||||
arg1: "Tibdarin"
|
||||
_randomPick:
|
||||
arg1: "Tibdarin"
|
||||
_dailyRandomPick:
|
||||
arg1: "Tibdarin"
|
||||
_seedRandomPick:
|
||||
arg2: "Tibdarin"
|
||||
_pick:
|
||||
arg1: "Tibdarin"
|
||||
_listLen:
|
||||
arg1: "Tibdarin"
|
||||
types:
|
||||
array: "Tibdarin"
|
||||
_notification:
|
||||
youWereFollowed: "Yeṭṭafaṛ-ik·em-id"
|
||||
_types:
|
||||
|
|
|
@ -472,6 +472,8 @@ dayOverDayChanges: "어제보다"
|
|||
appearance: "모양"
|
||||
clientSettings: "클라이언트 설정"
|
||||
accountSettings: "계정 설정"
|
||||
promotion: "프로모션"
|
||||
promote: "프로모션하기"
|
||||
numberOfDays: "며칠동안"
|
||||
hideThisNote: "이 노트를 숨기기"
|
||||
showFeaturedNotesInTimeline: "타임라인에 추천 노트를 표시"
|
||||
|
@ -547,6 +549,7 @@ poll: "투표"
|
|||
useCw: "내용 숨기기"
|
||||
enablePlayer: "플레이어 열기"
|
||||
disablePlayer: "플레이어 닫기"
|
||||
expandTweet: "트윗 확장하기"
|
||||
themeEditor: "테마 에디터"
|
||||
description: "설명"
|
||||
describeFile: "캡션 추가"
|
||||
|
@ -1323,7 +1326,10 @@ _pages:
|
|||
my: "내 페이지"
|
||||
liked: "좋아요한 페이지"
|
||||
featured: "인기"
|
||||
inspector: "인스펙터"
|
||||
contents: "콘텐츠"
|
||||
content: "페이지 블록"
|
||||
variables: "변수"
|
||||
title: "제목"
|
||||
url: "페이지 URL"
|
||||
summary: "페이지 요약"
|
||||
|
@ -1334,6 +1340,262 @@ _pages:
|
|||
fontSansSerif: "고딕체"
|
||||
eyeCatchingImageSet: "아이캐치 이미지를 설정"
|
||||
eyeCatchingImageRemove: "아이캐치 이미지를 삭제"
|
||||
chooseBlock: "블록 추가"
|
||||
selectType: "종류 선택"
|
||||
enterVariableName: "변수명을 지정해주세요"
|
||||
variableNameIsAlreadyUsed: "해당 변수명은 이미 사용중입니다"
|
||||
contentBlocks: "콘텐츠"
|
||||
inputBlocks: "입력"
|
||||
specialBlocks: "특수"
|
||||
blocks:
|
||||
text: "텍스트"
|
||||
textarea: "텍스트 영역"
|
||||
section: "섹션"
|
||||
image: "이미지"
|
||||
button: "버튼"
|
||||
if: "조건문"
|
||||
_if:
|
||||
variable: "변수"
|
||||
post: "글 입력란"
|
||||
_post:
|
||||
text: "내용"
|
||||
attachCanvasImage: "캔버스의 이미지와 함께 게시하기"
|
||||
canvasId: "캔버스 ID"
|
||||
textInput: "텍스트 입력"
|
||||
_textInput:
|
||||
name: "변수명"
|
||||
text: "제목"
|
||||
default: "기본값"
|
||||
textareaInput: "여러 줄 텍스트 입력"
|
||||
_textareaInput:
|
||||
name: "변수명"
|
||||
text: "제목"
|
||||
default: "기본값"
|
||||
numberInput: "수치 입력"
|
||||
_numberInput:
|
||||
name: "변수명"
|
||||
text: "제목"
|
||||
default: "기본값"
|
||||
canvas: "캔버스"
|
||||
_canvas:
|
||||
id: "캔버스 ID"
|
||||
width: "폭"
|
||||
height: "높이"
|
||||
note: "노트필기"
|
||||
_note:
|
||||
id: "노트 ID"
|
||||
idDescription: "노트 URL을 붙여넣어 설정할 수도 있습니다."
|
||||
detailed: "세부 정보 보기"
|
||||
switch: "스위치"
|
||||
_switch:
|
||||
name: "변수명"
|
||||
text: "제목"
|
||||
default: "기본값"
|
||||
counter: "카운터"
|
||||
_counter:
|
||||
name: "변수명"
|
||||
text: "제목"
|
||||
inc: "증가치"
|
||||
_button:
|
||||
text: "제목"
|
||||
colored: "색 입히기"
|
||||
action: "버튼을 눌렀을 때의 동작"
|
||||
_action:
|
||||
dialog: "대화상자를 표시"
|
||||
_dialog:
|
||||
content: "내용"
|
||||
resetRandom: "난수를 초기화"
|
||||
pushEvent: "이벤트 보내기"
|
||||
_pushEvent:
|
||||
event: "이벤트 이름"
|
||||
message: "눌렀을 때 표시할 페이지"
|
||||
variable: "보낼 변수"
|
||||
no-variable: "없음"
|
||||
callAiScript: "AiScript 호출"
|
||||
_callAiScript:
|
||||
functionName: "함수명"
|
||||
radioButton: "선택지"
|
||||
_radioButton:
|
||||
name: "변수명"
|
||||
title: "제목"
|
||||
values: "줄바꿈으로 구분된 선택지"
|
||||
default: "기본값"
|
||||
script:
|
||||
categories:
|
||||
flow: "흐름 제어"
|
||||
logical: "논리 연산"
|
||||
operation: "계산"
|
||||
comparison: "비교"
|
||||
random: "랜덤"
|
||||
value: "값"
|
||||
fn: "함수"
|
||||
text: "텍스트 조작"
|
||||
convert: "변환"
|
||||
list: "리스트"
|
||||
blocks:
|
||||
text: "텍스트"
|
||||
multiLineText: "텍스트 (여러 줄)"
|
||||
textList: "텍스트 목록"
|
||||
_textList:
|
||||
info: "각각을 줄바꿈으로 구분해주세요"
|
||||
strLen: "텍스트의 길이"
|
||||
_strLen:
|
||||
arg1: "텍스트"
|
||||
strPick: "문자 추출"
|
||||
_strPick:
|
||||
arg1: "텍스트"
|
||||
arg2: "문자 위치"
|
||||
strReplace: "텍스트 대체"
|
||||
_strReplace:
|
||||
arg1: "텍스트"
|
||||
arg2: "대체될 텍스트"
|
||||
arg3: "대체할 텍스트"
|
||||
strReverse: "텍스트 뒤집기"
|
||||
_strReverse:
|
||||
arg1: "텍스트"
|
||||
join: "텍스트 합치기"
|
||||
_join:
|
||||
arg1: "리스트"
|
||||
arg2: "구분자"
|
||||
add: "더하기"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "빼기"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "곱하기"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "나누기"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "나눈 나머지"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "소수점을 반올림"
|
||||
_round:
|
||||
arg1: "수치"
|
||||
eq: "A와 B가 동일"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A와 B가 다름"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A와 B가 둘 다 참"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A, B중 하나 이상이 참"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A가 B보다 작음"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A가 B보다 큼"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A가 B보다 작거나 같음"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A가 B보다 크거나 같음"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "분기"
|
||||
_if:
|
||||
arg1: "조건문"
|
||||
arg2: "참일 경우"
|
||||
arg3: "거짓일 경우"
|
||||
not: "부정"
|
||||
_not:
|
||||
arg1: "부정"
|
||||
random: "랜덤"
|
||||
_random:
|
||||
arg1: "확률"
|
||||
rannum: "난수"
|
||||
_rannum:
|
||||
arg1: "최솟값"
|
||||
arg2: "최댓값"
|
||||
randomPick: "목록에서 임의로 선택"
|
||||
_randomPick:
|
||||
arg1: "리스트"
|
||||
dailyRandom: "랜덤 (하루동안 결과 유지)"
|
||||
_dailyRandom:
|
||||
arg1: "확률"
|
||||
dailyRannum: "난수 (하루동안 결과 유지)"
|
||||
_dailyRannum:
|
||||
arg1: "최솟값"
|
||||
arg2: "최댓값"
|
||||
dailyRandomPick: "목록에서 임의로 선택 (하루동안 결과 유지)"
|
||||
_dailyRandomPick:
|
||||
arg1: "리스트"
|
||||
seedRandom: "무작위 (시드)"
|
||||
_seedRandom:
|
||||
arg1: "시드"
|
||||
arg2: "확률"
|
||||
seedRannum: "난수 (시드)"
|
||||
_seedRannum:
|
||||
arg1: "시드"
|
||||
arg2: "최솟값"
|
||||
arg3: "최댓값"
|
||||
seedRandomPick: "목록에서 무작위로 선택 (시드)"
|
||||
_seedRandomPick:
|
||||
arg1: "시드"
|
||||
arg2: "리스트"
|
||||
DRPWPM: "확률형 목록에서 임의로 선택 (하루동안 결과 유지)"
|
||||
_DRPWPM:
|
||||
arg1: "텍스트 목록"
|
||||
pick: "목록에서 선택"
|
||||
_pick:
|
||||
arg1: "리스트"
|
||||
arg2: "위치"
|
||||
listLen: "리스트의 길이 가져오기"
|
||||
_listLen:
|
||||
arg1: "리스트"
|
||||
number: "수치"
|
||||
stringToNumber: "텍스트를 수치로"
|
||||
_stringToNumber:
|
||||
arg1: "텍스트"
|
||||
numberToString: "수치를 텍스트로"
|
||||
_numberToString:
|
||||
arg1: "수치"
|
||||
splitStrByLine: "텍스트를 행 단위로 분할"
|
||||
_splitStrByLine:
|
||||
arg1: "텍스트"
|
||||
ref: "변수"
|
||||
aiScriptVar: "AiScript 변수"
|
||||
fn: "함수"
|
||||
_fn:
|
||||
slots: "슬롯"
|
||||
slots-info: "각 슬롯을 줄바꿈으로 구분하여 주세요"
|
||||
arg1: "출력"
|
||||
for: "반복"
|
||||
_for:
|
||||
arg1: "횟수"
|
||||
arg2: "처리"
|
||||
typeError: "슬롯 {slot}은 \"{expect}\"를 사용할 수 있지만 \"{actual}이 들어있습니다!"
|
||||
thereIsEmptySlot: "슬롯 {slot}이(가) 비었습니다!"
|
||||
types:
|
||||
string: "텍스트"
|
||||
number: "수치"
|
||||
boolean: "플래그"
|
||||
array: "리스트"
|
||||
stringArray: "텍스트 목록"
|
||||
emptySlot: "빈 슬롯"
|
||||
enviromentVariables: "환경 변수"
|
||||
pageVariables: "페이지 요소"
|
||||
argVariables: "입력 슬롯"
|
||||
_relayStatus:
|
||||
requesting: "대기 중"
|
||||
accepted: "승인됨"
|
||||
|
|
|
@ -343,6 +343,27 @@ _charts:
|
|||
federation: "Federatie"
|
||||
_timelines:
|
||||
home: "Startpagina"
|
||||
_pages:
|
||||
blocks:
|
||||
image: "Afbeeldingen"
|
||||
script:
|
||||
categories:
|
||||
list: "Lijsten"
|
||||
blocks:
|
||||
_join:
|
||||
arg1: "Lijsten"
|
||||
_randomPick:
|
||||
arg1: "Lijsten"
|
||||
_dailyRandomPick:
|
||||
arg1: "Lijsten"
|
||||
_seedRandomPick:
|
||||
arg2: "Lijsten"
|
||||
_pick:
|
||||
arg1: "Lijsten"
|
||||
_listLen:
|
||||
arg1: "Lijsten"
|
||||
types:
|
||||
array: "Lijsten"
|
||||
_notification:
|
||||
youWereFollowed: "volgde jou"
|
||||
_types:
|
||||
|
|
|
@ -465,6 +465,8 @@ dayOverDayChanges: "Codziennie"
|
|||
appearance: "Wygląd"
|
||||
clientSettings: "Ustawienia klienta"
|
||||
accountSettings: "Ustawienia konta"
|
||||
promotion: "Promowane"
|
||||
promote: "Promuj"
|
||||
numberOfDays: "Liczba dni"
|
||||
hideThisNote: "Ukryj ten wpis"
|
||||
showFeaturedNotesInTimeline: "Pokazuj wyróżnione wpisy w osi czasu"
|
||||
|
@ -534,6 +536,7 @@ poll: "Ankieta"
|
|||
useCw: "Ukryj zawartość"
|
||||
enablePlayer: "Otwórz odtwarzacz wideo"
|
||||
disablePlayer: "Zamknij odtwarzacz wideo"
|
||||
expandTweet: "Rozwiń tweet"
|
||||
themeEditor: "Edytor motywu"
|
||||
description: "Opis"
|
||||
describeFile: "dodaj podpis"
|
||||
|
@ -1113,7 +1116,10 @@ _pages:
|
|||
my: "Moje strony"
|
||||
liked: "Polubione strony"
|
||||
featured: "Wyróżnione"
|
||||
inspector: "Inspektor"
|
||||
contents: "Zawartość"
|
||||
content: "Blokada strony"
|
||||
variables: "Zmienne"
|
||||
title: "Tytuł"
|
||||
url: "URL strony"
|
||||
summary: "Podsumowanie strony"
|
||||
|
@ -1124,6 +1130,243 @@ _pages:
|
|||
fontSansSerif: "Bezszeryfowa"
|
||||
eyeCatchingImageSet: "Ustaw przyciągające wzrok zdjęcie"
|
||||
eyeCatchingImageRemove: "Usuń przyciągające wzrok zdjęcie"
|
||||
chooseBlock: "Dodaj blok"
|
||||
selectType: "Wybierz typ"
|
||||
enterVariableName: "Wprowadź nazwę dla swojej zmiennej"
|
||||
variableNameIsAlreadyUsed: "Ta nazwa jest już używana przez inną zmienną"
|
||||
contentBlocks: "Zawartość"
|
||||
inputBlocks: "Wejście"
|
||||
specialBlocks: "Specjalne"
|
||||
blocks:
|
||||
text: "Tekst"
|
||||
textarea: "Pole tekstowe"
|
||||
section: "Sekcja"
|
||||
image: "Zdjęcia"
|
||||
button: "Przycisk"
|
||||
if: "Jeżeli"
|
||||
_if:
|
||||
variable: "Zmienna"
|
||||
post: "Utwórz wpis"
|
||||
_post:
|
||||
text: "Treść"
|
||||
textInput: "Pole tekstowe"
|
||||
_textInput:
|
||||
name: "Nazwa zmiennej"
|
||||
text: "Tytuł"
|
||||
default: "Domyślna wartość"
|
||||
textareaInput: "Pole tekstowe na wiele wierszy"
|
||||
_textareaInput:
|
||||
name: "Nazwa zmiennej"
|
||||
text: "Tytuł"
|
||||
default: "Domyślna wartość"
|
||||
numberInput: "Pole na liczbę"
|
||||
_numberInput:
|
||||
name: "Nazwa zmiennej"
|
||||
text: "Tytuł"
|
||||
default: "Domyślna wartość"
|
||||
_canvas:
|
||||
width: "Szerokość"
|
||||
height: "Wysokość"
|
||||
note: "Osadzony wpis"
|
||||
_note:
|
||||
id: "ID wpisu"
|
||||
idDescription: "Możesz też wkleić adres URL wpisu, aby go ustawić."
|
||||
detailed: "Szczegółowy widok"
|
||||
switch: "Przełącznik"
|
||||
_switch:
|
||||
name: "Nazwa zmiennej"
|
||||
text: "Tytuł"
|
||||
default: "Domyślna wartość"
|
||||
counter: "Licznik"
|
||||
_counter:
|
||||
name: "Nazwa zmiennej"
|
||||
text: "Tytuł"
|
||||
inc: "Zwiększ o"
|
||||
_button:
|
||||
text: "Tytuł"
|
||||
colored: "Kolorowe"
|
||||
action: "Działanie wykonywane przy naciśnięciu przycisku"
|
||||
_action:
|
||||
dialog: "Pokazuj okno dialogowe"
|
||||
_dialog:
|
||||
content: "Treść"
|
||||
resetRandom: "Resetuj losowe ziarno"
|
||||
pushEvent: "Wyślij zdarzenie"
|
||||
_pushEvent:
|
||||
event: "Nazwa zdarzenia"
|
||||
message: "Wiadomość do wyświetlenia po aktywowaniu"
|
||||
variable: "Zmienna do wysłania"
|
||||
no-variable: "Brak"
|
||||
callAiScript: "Wywołaj AiScript"
|
||||
_callAiScript:
|
||||
functionName: "Nazwa funkcji"
|
||||
radioButton: "Wybór"
|
||||
_radioButton:
|
||||
name: "Nazwa zmiennej"
|
||||
title: "Tytuł"
|
||||
values: "Lista wyborów (oddzielonych znakiem nowego wiersza)"
|
||||
default: "Domyślna wartość"
|
||||
script:
|
||||
categories:
|
||||
flow: "Kontrola przepływu"
|
||||
logical: "Operacje logiczne"
|
||||
operation: "Obliczanie"
|
||||
comparison: "Porównanie"
|
||||
random: "Losowe"
|
||||
value: "Wartość"
|
||||
fn: "Funkcje"
|
||||
text: "Działania na tekście"
|
||||
convert: "Transformacja"
|
||||
list: "Listy"
|
||||
blocks:
|
||||
text: "Tekst"
|
||||
multiLineText: "Tekst (w wielu wierszach)"
|
||||
_textList:
|
||||
info: "Oddziel każdy wpis znakiem nowego wiersza"
|
||||
strLen: "Długość tekstu"
|
||||
_strLen:
|
||||
arg1: "Tekst"
|
||||
_strPick:
|
||||
arg1: "Tekst"
|
||||
arg2: "Położenie znaku"
|
||||
strReplace: "Zamiana tekstu"
|
||||
_strReplace:
|
||||
arg1: "Tekst"
|
||||
arg2: "Tekst do zamiany"
|
||||
arg3: "Zamieniono z"
|
||||
_strReverse:
|
||||
arg1: "Tekst"
|
||||
_join:
|
||||
arg1: "Listy"
|
||||
arg2: "Odstęp"
|
||||
add: "Dodaj"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "Odejmij"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "Pomnóż"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "Podziel"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "Reszta"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
_round:
|
||||
arg1: "Liczba"
|
||||
eq: "A i B są sobie równe"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A i B różnią się"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A I B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A LUB B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A jest mniejsze niż B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A jest większe od B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A jest mniejsze lub równe B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A jest większe lub równe B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "Warunek"
|
||||
_if:
|
||||
arg1: "Jeżeli"
|
||||
arg2: "Jeżeli prawda"
|
||||
not: "NIE"
|
||||
_not:
|
||||
arg1: "NIE"
|
||||
random: "Losowe"
|
||||
_random:
|
||||
arg1: "Prawdopodobieństwo"
|
||||
rannum: "Losowa liczba"
|
||||
_rannum:
|
||||
arg1: "Minimalna wartość"
|
||||
arg2: "Maksymalna wartość"
|
||||
randomPick: "Wybierz losowo z listy"
|
||||
_randomPick:
|
||||
arg1: "Listy"
|
||||
dailyRandom: "Losowo (zostaje na dzień)"
|
||||
_dailyRandom:
|
||||
arg1: "Prawdopodobieństwo"
|
||||
dailyRannum: "Losowa liczba (zostaje na dzień)"
|
||||
_dailyRannum:
|
||||
arg1: "Minimalna wartość"
|
||||
arg2: "Maksymalna wartość"
|
||||
dailyRandomPick: "Wybierz losowo z listy (zostaje na dzień)"
|
||||
_dailyRandomPick:
|
||||
arg1: "Listy"
|
||||
seedRandom: "Losowo (z ziarnem)"
|
||||
_seedRandom:
|
||||
arg1: "Ziarno"
|
||||
arg2: "Prawdopodobieństwo"
|
||||
seedRannum: "Losowa liczba (z ziarnem)"
|
||||
_seedRannum:
|
||||
arg1: "Ziarno"
|
||||
arg2: "Minimalna wartość"
|
||||
arg3: "Maksymalna wartość"
|
||||
seedRandomPick: "Wybierz losowo z listy (z ziarnem)"
|
||||
_seedRandomPick:
|
||||
arg1: "Ziarno"
|
||||
arg2: "Listy"
|
||||
DRPWPM: "Wybierz losowo z ważonej listy (zostaje na dzień)"
|
||||
pick: "Wybierz z listy"
|
||||
_pick:
|
||||
arg1: "Listy"
|
||||
arg2: "Położenie"
|
||||
listLen: "Uzyskaj długość listy"
|
||||
_listLen:
|
||||
arg1: "Listy"
|
||||
number: "Liczba"
|
||||
stringToNumber: "Tekst na liczbę"
|
||||
_stringToNumber:
|
||||
arg1: "Tekst"
|
||||
numberToString: "Liczba na tekst"
|
||||
_numberToString:
|
||||
arg1: "Liczba"
|
||||
splitStrByLine: "Rozdziel tekst znakami nowej linii"
|
||||
_splitStrByLine:
|
||||
arg1: "Tekst"
|
||||
ref: "Zmienne"
|
||||
aiScriptVar: "Zmienna AiScript"
|
||||
fn: "Funkcje"
|
||||
_fn:
|
||||
arg1: "Wyjście"
|
||||
for: "Powtórzenie"
|
||||
_for:
|
||||
arg1: "Liczba powtórzeń"
|
||||
arg2: "Działanie"
|
||||
types:
|
||||
string: "Tekst"
|
||||
number: "Liczba"
|
||||
boolean: "Flaguj"
|
||||
array: "Listy"
|
||||
enviromentVariables: "Zmienna środowiskowa"
|
||||
pageVariables: "Element strony"
|
||||
_relayStatus:
|
||||
requesting: "Oczekujące"
|
||||
accepted: "Zaakceptowano"
|
||||
|
|
|
@ -190,6 +190,173 @@ _exportOrImport:
|
|||
muteList: "Silenciar"
|
||||
blockingList: "Bloquear"
|
||||
userLists: "Listas"
|
||||
_pages:
|
||||
blocks:
|
||||
_button:
|
||||
_action:
|
||||
_pushEvent:
|
||||
event: "Nome do evento"
|
||||
message: "Mostrar mensagem quando ativado"
|
||||
variable: "Variável a mandar"
|
||||
no-variable: "Nenhum"
|
||||
callAiScript: "Invocar AiScript"
|
||||
_callAiScript:
|
||||
functionName: "Nome da função"
|
||||
radioButton: "Escolha"
|
||||
_radioButton:
|
||||
values: "Lista de escolhas separadas por quebras de texto"
|
||||
script:
|
||||
categories:
|
||||
logical: "Operação lógica"
|
||||
operation: "Cálculos"
|
||||
comparison: "Comparação"
|
||||
list: "Listas"
|
||||
blocks:
|
||||
_strReplace:
|
||||
arg2: "Texto que irá ser substituído"
|
||||
arg3: "Substituir com"
|
||||
strReverse: "Virar texto"
|
||||
join: "Sequência de texto"
|
||||
_join:
|
||||
arg1: "Listas"
|
||||
arg2: "Separador"
|
||||
add: "Somar"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "Subtrair"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "Multiplicar"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "Dividir"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "O resto de"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "Arredondar decimal"
|
||||
_round:
|
||||
arg1: "Numérico"
|
||||
eq: "A e B são iguais"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A e B são diferentes"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A e B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A OU B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A é menor do que B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A é maior do que B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A é maior ou igual a B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A é maior ou igual a B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "Galho"
|
||||
_if:
|
||||
arg1: "Se"
|
||||
arg2: "Então"
|
||||
arg3: "Se não"
|
||||
not: "NÃO"
|
||||
_not:
|
||||
arg1: "NÃO"
|
||||
random: "Aleatório"
|
||||
_random:
|
||||
arg1: "Probabilidade"
|
||||
rannum: "Numeral aleatório"
|
||||
_rannum:
|
||||
arg1: "Valor mínimo"
|
||||
arg2: "Valor máximo"
|
||||
randomPick: "Escolher aleatoriamente de uma lista"
|
||||
_randomPick:
|
||||
arg1: "Listas"
|
||||
dailyRandom: "Aleatório (Muda uma vez por dia para cada usuário)"
|
||||
_dailyRandom:
|
||||
arg1: "Probabilidade"
|
||||
dailyRannum: "Numeral aleatório (Muda uma vez por dia para cada usuário)"
|
||||
_dailyRannum:
|
||||
arg1: "Valor mínimo"
|
||||
arg2: "Valor máximo"
|
||||
dailyRandomPick: "Escolher aleatoriamente de uma lista (Muda uma vez por dia para cada usuário)"
|
||||
_dailyRandomPick:
|
||||
arg1: "Listas"
|
||||
seedRandom: "Aleatório (com semente)"
|
||||
_seedRandom:
|
||||
arg1: "Semente"
|
||||
arg2: "Probabilidade"
|
||||
seedRannum: "Número aleatório (com semente)"
|
||||
_seedRannum:
|
||||
arg1: "Semente"
|
||||
arg2: "Valor mínimo"
|
||||
arg3: "Valor máximo"
|
||||
seedRandomPick: "Escolher aleatoriamente de uma lista (com uma semente)"
|
||||
_seedRandomPick:
|
||||
arg1: "Semente"
|
||||
arg2: "Listas"
|
||||
DRPWPM: "Escolher aleatoriamente de uma lista ponderada (Muda uma vez por dia para cada usuário)"
|
||||
_DRPWPM:
|
||||
arg1: "Lista de texto"
|
||||
pick: "Escolhe a partir da lista"
|
||||
_pick:
|
||||
arg1: "Listas"
|
||||
arg2: "Posição"
|
||||
listLen: "Pegar comprimento da lista"
|
||||
_listLen:
|
||||
arg1: "Listas"
|
||||
number: "Numérico"
|
||||
stringToNumber: "Texto para numérico"
|
||||
_stringToNumber:
|
||||
arg1: "Texto"
|
||||
numberToString: "Numérico para texto"
|
||||
_numberToString:
|
||||
arg1: "Numérico"
|
||||
splitStrByLine: "Dividir texto por quebras"
|
||||
_splitStrByLine:
|
||||
arg1: "Texto"
|
||||
ref: "Variável"
|
||||
aiScriptVar: "Variável AiScript"
|
||||
fn: "Função"
|
||||
_fn:
|
||||
slots: "Espaços"
|
||||
slots-info: "Separar cada espaço com uma quebra de texto"
|
||||
arg1: "Resultado"
|
||||
for: "Repetição 'for'"
|
||||
_for:
|
||||
arg1: "Número de repetições"
|
||||
arg2: "Ação"
|
||||
typeError: "Espaço {slot} aceita valores de tipo \"{expect}\", mas o valor dado é do tipo \"{actual}\"!"
|
||||
thereIsEmptySlot: "O espaço {slot} está vazio!"
|
||||
types:
|
||||
string: "Texto"
|
||||
number: "Numérico"
|
||||
array: "Listas"
|
||||
stringArray: "Lista de texto"
|
||||
emptySlot: "Espaço vazio"
|
||||
enviromentVariables: "Variáveis de ambiente"
|
||||
pageVariables: "Variáveis de página"
|
||||
_relayStatus:
|
||||
requesting: "Pendente"
|
||||
accepted: "Aprovado"
|
||||
|
|
|
@ -472,6 +472,8 @@ dayOverDayChanges: "Schimbări până ieri"
|
|||
appearance: "Aspect"
|
||||
clientSettings: "Setări client"
|
||||
accountSettings: "Setări cont"
|
||||
promotion: "Promovat"
|
||||
promote: "Promovează"
|
||||
numberOfDays: "Numărul zilelor"
|
||||
hideThisNote: "Ascunde această notă"
|
||||
showFeaturedNotesInTimeline: "Arată notele recomandate în cronologii"
|
||||
|
@ -547,6 +549,7 @@ poll: "Sondaj"
|
|||
useCw: "Ascunde conținutul"
|
||||
enablePlayer: "Deschide player-ul video"
|
||||
disablePlayer: "Închide player-ul video"
|
||||
expandTweet: "Expandează tweet"
|
||||
themeEditor: "Editor de teme"
|
||||
description: "Descriere"
|
||||
describeFile: "Adaugă titrări"
|
||||
|
@ -680,6 +683,27 @@ _charts:
|
|||
federation: "Federație"
|
||||
_timelines:
|
||||
home: "Acasă"
|
||||
_pages:
|
||||
blocks:
|
||||
image: "Imagini"
|
||||
script:
|
||||
categories:
|
||||
list: "Liste"
|
||||
blocks:
|
||||
_join:
|
||||
arg1: "Liste"
|
||||
_randomPick:
|
||||
arg1: "Liste"
|
||||
_dailyRandomPick:
|
||||
arg1: "Liste"
|
||||
_seedRandomPick:
|
||||
arg2: "Liste"
|
||||
_pick:
|
||||
arg1: "Liste"
|
||||
_listLen:
|
||||
arg1: "Liste"
|
||||
types:
|
||||
array: "Liste"
|
||||
_notification:
|
||||
youWereFollowed: "te-a urmărit"
|
||||
youWereInvitedToGroup: "Ai fost invitat într-un grup"
|
||||
|
|
|
@ -472,6 +472,8 @@ dayOverDayChanges: "За день"
|
|||
appearance: "Внешний вид"
|
||||
clientSettings: "Настройки клиента"
|
||||
accountSettings: "Настройки учетной записи"
|
||||
promotion: "Продвинуто"
|
||||
promote: "Продвинуть"
|
||||
numberOfDays: "Количество дней"
|
||||
hideThisNote: "Спрятать эту запись"
|
||||
showFeaturedNotesInTimeline: "Показывать в ленте заметки из «Горячего»"
|
||||
|
@ -547,6 +549,7 @@ poll: "Опрос"
|
|||
useCw: "Скрывать содержимое под предупреждением"
|
||||
enablePlayer: "Включить проигрыватель"
|
||||
disablePlayer: "Выключить проигрыватель"
|
||||
expandTweet: "Развернуть твит"
|
||||
themeEditor: "Редактор темы оформления"
|
||||
description: "Описание"
|
||||
describeFile: "Добавить подпись"
|
||||
|
@ -1306,7 +1309,10 @@ _pages:
|
|||
my: "Свои страницы"
|
||||
liked: "Понравившиеся страницы"
|
||||
featured: "Популярные"
|
||||
inspector: "Инспектор"
|
||||
contents: "Содержимое"
|
||||
content: "Содержимое"
|
||||
variables: "Переменные"
|
||||
title: "Заголовок"
|
||||
url: "Адрес страницы"
|
||||
summary: "Краткое содержание"
|
||||
|
@ -1317,6 +1323,262 @@ _pages:
|
|||
fontSansSerif: "Гротеск (без засечек)"
|
||||
eyeCatchingImageSet: "Добавить картинку для привлечения внимания"
|
||||
eyeCatchingImageRemove: "Убрать картинку для привлечения внимания"
|
||||
chooseBlock: "Добавить блок"
|
||||
selectType: "Выберите вид"
|
||||
enterVariableName: "Ведите имя переменной"
|
||||
variableNameIsAlreadyUsed: "Это имя уже есть у другой переменной"
|
||||
contentBlocks: "Содержательные"
|
||||
inputBlocks: "Для ввода"
|
||||
specialBlocks: "Особые"
|
||||
blocks:
|
||||
text: "Текст"
|
||||
textarea: "Текст в рамке"
|
||||
section: "Раздел"
|
||||
image: "Изображения"
|
||||
button: "Кнопка"
|
||||
if: "Условный"
|
||||
_if:
|
||||
variable: "Переменная"
|
||||
post: "Создание заметки"
|
||||
_post:
|
||||
text: "Текст"
|
||||
attachCanvasImage: "Прикрепить изображение с холста"
|
||||
canvasId: "Метка холста"
|
||||
textInput: "Поле ввода текста"
|
||||
_textInput:
|
||||
name: "Имя переменной"
|
||||
text: "Подпись"
|
||||
default: "Исходное содержимое"
|
||||
textareaInput: "Многострочное поле ввода текста"
|
||||
_textareaInput:
|
||||
name: "Имя переменной"
|
||||
text: "Подпись"
|
||||
default: "Исходное содержимое"
|
||||
numberInput: "Поле для ввода числа"
|
||||
_numberInput:
|
||||
name: "Имя переменной"
|
||||
text: "Подпись"
|
||||
default: "Исходное значение"
|
||||
canvas: "Холст"
|
||||
_canvas:
|
||||
id: "Метка холста"
|
||||
width: "Ширина"
|
||||
height: "Высота"
|
||||
note: "Встроенная заметка"
|
||||
_note:
|
||||
id: "Идентификатор заметки"
|
||||
idDescription: "Можно также вставить ссылку на заметку."
|
||||
detailed: "Подробный вид"
|
||||
switch: "Выключатель"
|
||||
_switch:
|
||||
name: "Имя переменной"
|
||||
text: "Подпись"
|
||||
default: "Исходное содержимое"
|
||||
counter: "Кнопка со счётчиком"
|
||||
_counter:
|
||||
name: "Имя переменной"
|
||||
text: "Надпись"
|
||||
inc: "Увеличивать на"
|
||||
_button:
|
||||
text: "Надпись"
|
||||
colored: "Выделена цветом"
|
||||
action: "Действие по нажатию"
|
||||
_action:
|
||||
dialog: "Показать всплывающий текст"
|
||||
_dialog:
|
||||
content: "Всплывающий текст"
|
||||
resetRandom: "Сброс генератора случайности"
|
||||
pushEvent: "Вызвать событие"
|
||||
_pushEvent:
|
||||
event: "Имя события"
|
||||
message: "Сообщение при нажатии"
|
||||
variable: "Передать переменную с событием"
|
||||
no-variable: "нет"
|
||||
callAiScript: "Вызвать AiScript"
|
||||
_callAiScript:
|
||||
functionName: "Имя функции"
|
||||
radioButton: "Кнопка-переключатель"
|
||||
_radioButton:
|
||||
name: "Имя переменной"
|
||||
title: "Заголовок"
|
||||
values: "Значения"
|
||||
default: "Исходное значение"
|
||||
script:
|
||||
categories:
|
||||
flow: "Управление исполнением"
|
||||
logical: "Логические"
|
||||
operation: "Арифметические"
|
||||
comparison: "Сравнение"
|
||||
random: "Случайные"
|
||||
value: "Значения"
|
||||
fn: "Функции"
|
||||
text: "Текстовые"
|
||||
convert: "Преобразование"
|
||||
list: "Список"
|
||||
blocks:
|
||||
text: "Строка текста"
|
||||
multiLineText: "Многострочный текст"
|
||||
textList: "Список строк текста"
|
||||
_textList:
|
||||
info: "Пишите каждый пункт с новой строки"
|
||||
strLen: "Длина текста"
|
||||
_strLen:
|
||||
arg1: "Текст"
|
||||
strPick: "Взять знак из текста"
|
||||
_strPick:
|
||||
arg1: "Текст"
|
||||
arg2: "Позиция знака"
|
||||
strReplace: "Замена текста"
|
||||
_strReplace:
|
||||
arg1: "Текст, в котором заменять"
|
||||
arg2: "Заменяемый текст"
|
||||
arg3: "Менять на"
|
||||
strReverse: "В обратном порядке"
|
||||
_strReverse:
|
||||
arg1: "Текст"
|
||||
join: "Объединение"
|
||||
_join:
|
||||
arg1: "Списки"
|
||||
arg2: "Разделитель"
|
||||
add: "Добавить"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "Вычитание"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "Умножение"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "Деление"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "Остаток от деления"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "Округление до целого"
|
||||
_round:
|
||||
arg1: "Число"
|
||||
eq: "A равно B"
|
||||
_eq:
|
||||
arg1: "А"
|
||||
arg2: "B"
|
||||
notEq: "A не равно B"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A и B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A или B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "A < B (меньше)"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "A > B (больше)"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "A ⩽ B (меньше или равно)"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: "A ⩾ B (больше или равно)"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "Условный"
|
||||
_if:
|
||||
arg1: "Условие"
|
||||
arg2: "Если правда"
|
||||
arg3: "Если ложь"
|
||||
not: "Отрицание"
|
||||
_not:
|
||||
arg1: "Условие"
|
||||
random: "Случайность"
|
||||
_random:
|
||||
arg1: "Вероятность"
|
||||
rannum: "Случайное число"
|
||||
_rannum:
|
||||
arg1: "Минимум"
|
||||
arg2: "Максимум"
|
||||
randomPick: "Случайный выбор из списка"
|
||||
_randomPick:
|
||||
arg1: "Списки"
|
||||
dailyRandom: "Случайность (на день для пользователя)"
|
||||
_dailyRandom:
|
||||
arg1: "Вероятность"
|
||||
dailyRannum: "Случайное число (на день для пользователя)"
|
||||
_dailyRannum:
|
||||
arg1: "Минимум"
|
||||
arg2: "Максимум"
|
||||
dailyRandomPick: "Случайный выбор из списка (на день для пользователя)"
|
||||
_dailyRandomPick:
|
||||
arg1: "Списки"
|
||||
seedRandom: "Псевдослучайность (заданная зерном)"
|
||||
_seedRandom:
|
||||
arg1: "Зерно"
|
||||
arg2: "Вероятность"
|
||||
seedRannum: "Псевдослучайное число (заданное зерном)"
|
||||
_seedRannum:
|
||||
arg1: "Зерно"
|
||||
arg2: "Минимум"
|
||||
arg3: "Максимум"
|
||||
seedRandomPick: "Псевдослучайный выбор из списка (заданный зерном)"
|
||||
_seedRandomPick:
|
||||
arg1: "Зерно"
|
||||
arg2: "Списки"
|
||||
DRPWPM: "Случайный выбор из взвешенного списка (на день для пользователя)"
|
||||
_DRPWPM:
|
||||
arg1: "Список строк текста"
|
||||
pick: "Выбор из списка"
|
||||
_pick:
|
||||
arg1: "Списки"
|
||||
arg2: "Индекс"
|
||||
listLen: "Количество элементов в списке"
|
||||
_listLen:
|
||||
arg1: "Списки"
|
||||
number: "Число"
|
||||
stringToNumber: "Число из текста"
|
||||
_stringToNumber:
|
||||
arg1: "Текст"
|
||||
numberToString: "Число в текст"
|
||||
_numberToString:
|
||||
arg1: "Число"
|
||||
splitStrByLine: "Разделение текста на строки"
|
||||
_splitStrByLine:
|
||||
arg1: "Текст"
|
||||
ref: "Переменная"
|
||||
aiScriptVar: "Переменная AiScript"
|
||||
fn: "Свои функции"
|
||||
_fn:
|
||||
slots: "Аргументы"
|
||||
slots-info: "Напишите имя каждого аргумента с новой строки"
|
||||
arg1: "Формула"
|
||||
for: "Цикл"
|
||||
_for:
|
||||
arg1: "Количество повторений"
|
||||
arg2: "Действие"
|
||||
typeError: "Аргумент {slot} должен быть иметь тип «{expect}», а передали «{actual}»!"
|
||||
thereIsEmptySlot: "Аргумент {slot} не заполнен!"
|
||||
types:
|
||||
string: "Текст"
|
||||
number: "Число"
|
||||
boolean: "Логический"
|
||||
array: "Списки"
|
||||
stringArray: "Список строк текста"
|
||||
emptySlot: "Пустой аргумент"
|
||||
enviromentVariables: "Переменная окружения"
|
||||
pageVariables: "Элемент страницы"
|
||||
argVariables: "Аргументы"
|
||||
_relayStatus:
|
||||
requesting: "В ожидании одобрения"
|
||||
accepted: "Одобрено."
|
||||
|
|
|
@ -472,6 +472,8 @@ dayOverDayChanges: "Medzidenné zmeny"
|
|||
appearance: "Vzhľad"
|
||||
clientSettings: "Nastavenia klienta"
|
||||
accountSettings: "Nastavenia účtu"
|
||||
promotion: "Propagácia"
|
||||
promote: "Propagovať"
|
||||
numberOfDays: "Počet dní"
|
||||
hideThisNote: "Skryť túto poznámku"
|
||||
showFeaturedNotesInTimeline: "Zobraziť významné poznámky v časovej osi"
|
||||
|
@ -547,6 +549,7 @@ poll: "Hlasovanie"
|
|||
useCw: "Skryť obsah"
|
||||
enablePlayer: "Otvoriť video prehrávač"
|
||||
disablePlayer: "Zavrieť video prehrávač"
|
||||
expandTweet: "Rozšíriť tweet"
|
||||
themeEditor: "Editor tém"
|
||||
description: "Popis"
|
||||
describeFile: "Pridať nadpis"
|
||||
|
@ -1320,7 +1323,10 @@ _pages:
|
|||
my: "Moje stránky"
|
||||
liked: "Obľúbené stránky"
|
||||
featured: "Význačné"
|
||||
inspector: "Inšpektor"
|
||||
contents: "Obsah"
|
||||
content: "Blok stránky"
|
||||
variables: "Premenné"
|
||||
title: "Nadpis"
|
||||
url: "URL stránky"
|
||||
summary: "Zhrnutie stránky"
|
||||
|
@ -1331,6 +1337,262 @@ _pages:
|
|||
fontSansSerif: "Bezpätkové"
|
||||
eyeCatchingImageSet: "Nastaviť miniatúru"
|
||||
eyeCatchingImageRemove: "Odstrániť miniatúru"
|
||||
chooseBlock: "Pridať blok"
|
||||
selectType: "Vyberte typ"
|
||||
enterVariableName: "Zadajte meno premennej"
|
||||
variableNameIsAlreadyUsed: "Meno premennej s už používa"
|
||||
contentBlocks: "Obsah"
|
||||
inputBlocks: "Vstup"
|
||||
specialBlocks: "Špeciálne"
|
||||
blocks:
|
||||
text: "Text"
|
||||
textarea: "Textové pole"
|
||||
section: "Sekcia"
|
||||
image: "Obrázky"
|
||||
button: "Tlačidlo"
|
||||
if: "Ak"
|
||||
_if:
|
||||
variable: "Premenné"
|
||||
post: "Napísať poznámku"
|
||||
_post:
|
||||
text: "Obsah"
|
||||
attachCanvasImage: "Príspevok s obrázkom na plátne"
|
||||
canvasId: "ID plátna"
|
||||
textInput: "Textový vstup"
|
||||
_textInput:
|
||||
name: "Meno premennej"
|
||||
text: "Nadpis"
|
||||
default: "Predvolená hodnota"
|
||||
textareaInput: "Viacriadkový textový vstup"
|
||||
_textareaInput:
|
||||
name: "Meno premennej"
|
||||
text: "Nadpis"
|
||||
default: "Predvolená hodnota"
|
||||
numberInput: "Číselný vstup"
|
||||
_numberInput:
|
||||
name: "Meno premennej"
|
||||
text: "Nadpis"
|
||||
default: "Predvolená hodnota"
|
||||
canvas: "Plátno"
|
||||
_canvas:
|
||||
id: "ID plátna"
|
||||
width: "Šírka"
|
||||
height: "Výška"
|
||||
note: "Vložená poznámka"
|
||||
_note:
|
||||
id: "ID poznámky"
|
||||
idDescription: "Alebo môžete vložiť URL poznámky sem"
|
||||
detailed: "Podrobný pohľad"
|
||||
switch: "Prepnúť"
|
||||
_switch:
|
||||
name: "Meno premennej"
|
||||
text: "Nadpis"
|
||||
default: "Predvolená hodnota"
|
||||
counter: "Počítadlo"
|
||||
_counter:
|
||||
name: "Meno premennej"
|
||||
text: "Nadpis"
|
||||
inc: "Pripočítať"
|
||||
_button:
|
||||
text: "Nadpis"
|
||||
colored: "Farebné"
|
||||
action: "Operácia po stlačení tlačidla"
|
||||
_action:
|
||||
dialog: "Zobraziť dialóg"
|
||||
_dialog:
|
||||
content: "Obsah"
|
||||
resetRandom: "Resetovať zdroj náhodnosti"
|
||||
pushEvent: "Poslať udalosť"
|
||||
_pushEvent:
|
||||
event: "Názov udalosti"
|
||||
message: "Zobrazená správa po aktivácii"
|
||||
variable: "Odoslaná premenná"
|
||||
no-variable: "Žiadne"
|
||||
callAiScript: "Spustiť AiScript"
|
||||
_callAiScript:
|
||||
functionName: "Názov funkcie"
|
||||
radioButton: "Možnosť"
|
||||
_radioButton:
|
||||
name: "Meno premennej"
|
||||
title: "Nadpis"
|
||||
values: "Zoznam možností oddelené novými riadkami"
|
||||
default: "Predvolená hodnota"
|
||||
script:
|
||||
categories:
|
||||
flow: "Riadenie behu"
|
||||
logical: "Logická operácia"
|
||||
operation: "Výpočet"
|
||||
comparison: "Porovnanie"
|
||||
random: "Náhodné"
|
||||
value: "Hodnoty"
|
||||
fn: "Funkcie"
|
||||
text: "Textové operácie"
|
||||
convert: "Transformácie"
|
||||
list: "Zoznamy"
|
||||
blocks:
|
||||
text: "Text"
|
||||
multiLineText: "Text (viacriadkový)"
|
||||
textList: "Zoznam textov"
|
||||
_textList:
|
||||
info: "Oddeľte každú položku novým riadkom"
|
||||
strLen: "Dĺžka textu"
|
||||
_strLen:
|
||||
arg1: "Text"
|
||||
strPick: "Vybrať znak"
|
||||
_strPick:
|
||||
arg1: "Text"
|
||||
arg2: "Pozícia znaku"
|
||||
strReplace: "Náhradný text"
|
||||
_strReplace:
|
||||
arg1: "Text"
|
||||
arg2: "Nahradený text"
|
||||
arg3: "Nahradiť s"
|
||||
strReverse: "Otočiť text"
|
||||
_strReverse:
|
||||
arg1: "Text"
|
||||
join: "Spojiť texty"
|
||||
_join:
|
||||
arg1: "Zoznamy"
|
||||
arg2: "Oddeľovač"
|
||||
add: "Pridať"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "Odčítať"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "Násobiť"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "Deliť"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "Zvyšok po delení"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "Zaokrúhliť"
|
||||
_round:
|
||||
arg1: "Číslo"
|
||||
eq: "A a B sa rovnajú"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A a B sa nerovnajú"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A a zároveň B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A alebo B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A je menšie ako B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A je väčšie ako B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A je menšie alebo rovné B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A je väčšie alebo rovné B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "Vetva"
|
||||
_if:
|
||||
arg1: "Ak"
|
||||
arg2: "Potom"
|
||||
arg3: "Inak"
|
||||
not: "Opak"
|
||||
_not:
|
||||
arg1: "Opak"
|
||||
random: "Náhodné"
|
||||
_random:
|
||||
arg1: "Pravdepodobnosť"
|
||||
rannum: "Náhodné číslo"
|
||||
_rannum:
|
||||
arg1: "Minimálna hodnota"
|
||||
arg2: "Maximálna hodnota"
|
||||
randomPick: "Náhodný výber zo zoznamu"
|
||||
_randomPick:
|
||||
arg1: "Zoznam"
|
||||
dailyRandom: "Náhodne (zmení sa raz denne pre každého používateľa)"
|
||||
_dailyRandom:
|
||||
arg1: "Pravdepodobnosť"
|
||||
dailyRannum: "Náhodné číslo (Mení sa denne pre každého používateľa)"
|
||||
_dailyRannum:
|
||||
arg1: "Minimálna hodnota"
|
||||
arg2: "Maximálna hodnota"
|
||||
dailyRandomPick: "Náhodný výber zo zoznamu (Mení sa denne pre každého používateľa)"
|
||||
_dailyRandomPick:
|
||||
arg1: "Zoznam"
|
||||
seedRandom: "Náhodne (so seedom)"
|
||||
_seedRandom:
|
||||
arg1: "Seed"
|
||||
arg2: "Pravdepodobnosť"
|
||||
seedRannum: "Náhodné číslo (so seedom)"
|
||||
_seedRannum:
|
||||
arg1: "Seed"
|
||||
arg2: "Minimálna hodnota"
|
||||
arg3: "Maximálna hodnota"
|
||||
seedRandomPick: "Náhodný výber zo zoznamu (so seedom)"
|
||||
_seedRandomPick:
|
||||
arg1: "Seed"
|
||||
arg2: "Zoznam"
|
||||
DRPWPM: "Náhodný výber z váženého zoznamu (Mení sa denne pre každého používateľa)"
|
||||
_DRPWPM:
|
||||
arg1: "Zoznam textov"
|
||||
pick: "Vybrať zo zoznamu"
|
||||
_pick:
|
||||
arg1: "Zoznam"
|
||||
arg2: "Pozícia"
|
||||
listLen: "Získať dĺžku zoznamu"
|
||||
_listLen:
|
||||
arg1: "Zoznam"
|
||||
number: "Číslo"
|
||||
stringToNumber: "Text na číslo"
|
||||
_stringToNumber:
|
||||
arg1: "Text"
|
||||
numberToString: "Číslo na text"
|
||||
_numberToString:
|
||||
arg1: "Číslo"
|
||||
splitStrByLine: "Rozdelí text po riadkoch"
|
||||
_splitStrByLine:
|
||||
arg1: "Text"
|
||||
ref: "Premenné"
|
||||
aiScriptVar: "AiScript premenná"
|
||||
fn: "Funkcie"
|
||||
_fn:
|
||||
slots: "Sloty"
|
||||
slots-info: "Oddeľte každý slot novým riadkom"
|
||||
arg1: "Výstup"
|
||||
for: "For cyklus"
|
||||
_for:
|
||||
arg1: "Počet opakovaní"
|
||||
arg2: "Akcia"
|
||||
typeError: "Slot {slot} akceptuje hodnoty typu \"{expect}\", ale dodaná hodnota je typu \"{actual}\"!"
|
||||
thereIsEmptySlot: "Slot {slot} je prázdny!"
|
||||
types:
|
||||
string: "Text"
|
||||
number: "Číslo"
|
||||
boolean: "Boolean"
|
||||
array: "Zoznamy"
|
||||
stringArray: "Zoznam textov"
|
||||
emptySlot: "Prázdny slot"
|
||||
enviromentVariables: "Premenné prostredia"
|
||||
pageVariables: "Premenné stránky"
|
||||
argVariables: "Vstupné sloty"
|
||||
_relayStatus:
|
||||
requesting: "Čaká sa"
|
||||
accepted: "Akceptované"
|
||||
|
|
|
@ -280,6 +280,25 @@ _exportOrImport:
|
|||
userLists: "Listor"
|
||||
_charts:
|
||||
federation: "Federation"
|
||||
_pages:
|
||||
script:
|
||||
categories:
|
||||
list: "Listor"
|
||||
blocks:
|
||||
_join:
|
||||
arg1: "Listor"
|
||||
_randomPick:
|
||||
arg1: "Listor"
|
||||
_dailyRandomPick:
|
||||
arg1: "Listor"
|
||||
_seedRandomPick:
|
||||
arg2: "Listor"
|
||||
_pick:
|
||||
arg1: "Listor"
|
||||
_listLen:
|
||||
arg1: "Listor"
|
||||
types:
|
||||
array: "Listor"
|
||||
_notification:
|
||||
youWereFollowed: "följde dig"
|
||||
_types:
|
||||
|
|
|
@ -472,6 +472,8 @@ dayOverDayChanges: "Доба"
|
|||
appearance: "Вигляд"
|
||||
clientSettings: "Налаштування клієнта"
|
||||
accountSettings: "Налаштування акаунта"
|
||||
promotion: "Виділене"
|
||||
promote: "Виділити"
|
||||
numberOfDays: "Кількість днів"
|
||||
hideThisNote: "Сховати цю нотатку"
|
||||
showFeaturedNotesInTimeline: "Показувати популярні нотатки у стрічці"
|
||||
|
@ -547,6 +549,7 @@ poll: "Опитування"
|
|||
useCw: "Приховати вміст"
|
||||
enablePlayer: "Відкрити відеоплеєр"
|
||||
disablePlayer: "Закрити відеоплеєр"
|
||||
expandTweet: "Розгорнути твіт"
|
||||
themeEditor: "Редактор тем"
|
||||
description: "Опис"
|
||||
describeFile: "Додати підпис"
|
||||
|
@ -1124,7 +1127,10 @@ _pages:
|
|||
my: "Мої сторінки"
|
||||
liked: "Вподобані сторінки"
|
||||
featured: "Популярні"
|
||||
inspector: "Інспектор"
|
||||
contents: "Вміст"
|
||||
content: "Блок сторінки"
|
||||
variables: "Змінні"
|
||||
title: "Заголовок"
|
||||
url: "URL сторінки"
|
||||
summary: "Короткий зміст"
|
||||
|
@ -1135,6 +1141,261 @@ _pages:
|
|||
fontSansSerif: "Sans serif"
|
||||
eyeCatchingImageSet: "Встановити привабливе зображення"
|
||||
eyeCatchingImageRemove: "Видалити привабливе зображення"
|
||||
chooseBlock: "Додати блок"
|
||||
selectType: "Виберіть тип"
|
||||
enterVariableName: "Введіть назву для змінної"
|
||||
variableNameIsAlreadyUsed: "Ця назва вже використовується іншою змінною"
|
||||
contentBlocks: "Контент"
|
||||
inputBlocks: "Ввід"
|
||||
specialBlocks: "Особливе"
|
||||
blocks:
|
||||
text: "Текст"
|
||||
textarea: "Текстова область"
|
||||
section: "Розділ"
|
||||
image: "Зображення"
|
||||
button: "Кнопка"
|
||||
if: "Якщо"
|
||||
_if:
|
||||
variable: "Змінні"
|
||||
post: "Створення нотатки"
|
||||
_post:
|
||||
text: "Вміст"
|
||||
canvasId: "Ідентифікатор полотна"
|
||||
textInput: "Введення тексту"
|
||||
_textInput:
|
||||
name: "Ім'я змінної"
|
||||
text: "Назва"
|
||||
default: "Значення за замовчуванням"
|
||||
textareaInput: "Багаторядкове введення тексту"
|
||||
_textareaInput:
|
||||
name: "Ім'я змінної"
|
||||
text: "Назва"
|
||||
default: "Значення за замовчуванням"
|
||||
numberInput: "Числове введення"
|
||||
_numberInput:
|
||||
name: "Ім'я змінної"
|
||||
text: "Назва"
|
||||
default: "Значення за замовчуванням"
|
||||
canvas: "Полотно"
|
||||
_canvas:
|
||||
id: "Ідентифікатор полотна"
|
||||
width: "Ширина"
|
||||
height: "Висота"
|
||||
note: "Вбудована нотатка"
|
||||
_note:
|
||||
id: "Ідентифікатор нотатки"
|
||||
idDescription: "Також можна вказати посилання на нотатку"
|
||||
detailed: "Детальний вигляд"
|
||||
switch: "Перемикач"
|
||||
_switch:
|
||||
name: "Ім'я змінної"
|
||||
text: "Назва"
|
||||
default: "Значення за замовчуванням"
|
||||
counter: "Лічильник"
|
||||
_counter:
|
||||
name: "Ім'я змінної"
|
||||
text: "Назва"
|
||||
inc: "Збільшити на"
|
||||
_button:
|
||||
text: "Напис"
|
||||
colored: "Кольоровий"
|
||||
action: "Дія кнопки"
|
||||
_action:
|
||||
dialog: "Показати повідомлення"
|
||||
_dialog:
|
||||
content: "Вміст"
|
||||
resetRandom: "Скидання генератора випадковості"
|
||||
pushEvent: "Надіслати подію"
|
||||
_pushEvent:
|
||||
event: "Назві події"
|
||||
message: "Повідомлення для відображення при активації"
|
||||
variable: "Змінна для надсилання"
|
||||
no-variable: "Відсутньо"
|
||||
callAiScript: "Виклик AiScript"
|
||||
_callAiScript:
|
||||
functionName: "Ім'я функції"
|
||||
radioButton: "Вибір"
|
||||
_radioButton:
|
||||
name: "Ім'я змінної"
|
||||
title: "Напис"
|
||||
values: "Варіанти, розділені розривами рядків"
|
||||
default: "Значення за замовчуванням"
|
||||
script:
|
||||
categories:
|
||||
flow: "Керування потоком"
|
||||
logical: "Логічні операції"
|
||||
operation: "Обчислення"
|
||||
comparison: "Порівняння"
|
||||
random: "Випадковість"
|
||||
value: "Значення"
|
||||
fn: "Функції"
|
||||
text: "Дії з текстом"
|
||||
convert: "Перетворення"
|
||||
list: "Списки"
|
||||
blocks:
|
||||
text: "Текст"
|
||||
multiLineText: "Текст (багаторядковий)"
|
||||
textList: "Текстовий список"
|
||||
_textList:
|
||||
info: "Використовувати новий рядок як роздільник для вводу"
|
||||
strLen: "Довжина тексту"
|
||||
_strLen:
|
||||
arg1: "Текст"
|
||||
strPick: "Вибрати символ"
|
||||
_strPick:
|
||||
arg1: "Текст"
|
||||
arg2: "Розташування символу"
|
||||
strReplace: "Заміна тексту"
|
||||
_strReplace:
|
||||
arg1: "Текст"
|
||||
arg2: "Текст, який потрібно замінити"
|
||||
arg3: "Заміняти на"
|
||||
strReverse: "Перевернути текст"
|
||||
_strReverse:
|
||||
arg1: "Текст"
|
||||
join: "Конкатенація тексту"
|
||||
_join:
|
||||
arg1: "Списки"
|
||||
arg2: "Розділювач"
|
||||
add: "Додати"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "Відняти"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "Помножити"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "Поділити"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "Остача"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "Десяткове округлення"
|
||||
_round:
|
||||
arg1: "Число"
|
||||
eq: "A дорівнює B"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A не дорівнює B"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "А І Б"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A АБО B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A менше, ніж B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A більше, ніж B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A менше або дорівнює B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A більше або дорівнює B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "Умова"
|
||||
_if:
|
||||
arg1: "Якщо"
|
||||
arg2: "Якщо так"
|
||||
arg3: "Якщо ні"
|
||||
not: "НЕ"
|
||||
_not:
|
||||
arg1: "НЕ"
|
||||
random: "Випадково"
|
||||
_random:
|
||||
arg1: "Імовірність"
|
||||
rannum: "Випадкове число"
|
||||
_rannum:
|
||||
arg1: "Мінімальне значення"
|
||||
arg2: "Максимальне значення"
|
||||
randomPick: "Випадковий вибір зі списку"
|
||||
_randomPick:
|
||||
arg1: "Списки"
|
||||
dailyRandom: "Випадково (триває добу)"
|
||||
_dailyRandom:
|
||||
arg1: "Імовірність"
|
||||
dailyRannum: "Випадкове число (триває добу)"
|
||||
_dailyRannum:
|
||||
arg1: "Мінімальне значення"
|
||||
arg2: "Максимальне значення"
|
||||
dailyRandomPick: "Випадково вибрати зі списку (триває добу)"
|
||||
_dailyRandomPick:
|
||||
arg1: "Списки"
|
||||
seedRandom: "Випадковість (з насінням)"
|
||||
_seedRandom:
|
||||
arg1: "Насіння"
|
||||
arg2: "Імовірність"
|
||||
seedRannum: "Випадкове число (з насінням)"
|
||||
_seedRannum:
|
||||
arg1: "Насіння"
|
||||
arg2: "Мінімальне значення"
|
||||
arg3: "Максимальне значення"
|
||||
seedRandomPick: "Випадково вибрати зі списку (з насінням)"
|
||||
_seedRandomPick:
|
||||
arg1: "Насіння"
|
||||
arg2: "Списки"
|
||||
DRPWPM: "Випадково вибрати зі зваженого списку (триває добу)"
|
||||
_DRPWPM:
|
||||
arg1: "Текстовий список"
|
||||
pick: "Вибір зі списку"
|
||||
_pick:
|
||||
arg1: "Списки"
|
||||
arg2: "Позиція"
|
||||
listLen: "Отримати довжину списку"
|
||||
_listLen:
|
||||
arg1: "Списки"
|
||||
number: "Число"
|
||||
stringToNumber: "Текст на число"
|
||||
_stringToNumber:
|
||||
arg1: "Текст"
|
||||
numberToString: "Число на текст"
|
||||
_numberToString:
|
||||
arg1: "Число"
|
||||
splitStrByLine: "Розбиття тексту на рядки"
|
||||
_splitStrByLine:
|
||||
arg1: "Текст"
|
||||
ref: "Змінні"
|
||||
aiScriptVar: "Змінна AiScript"
|
||||
fn: "Функції"
|
||||
_fn:
|
||||
slots: "Паз"
|
||||
slots-info: "Використовувати нову лінію як роздільник пазів"
|
||||
arg1: "Вивід"
|
||||
for: "Повторення"
|
||||
_for:
|
||||
arg1: "Кількість повторень"
|
||||
arg2: "Дія"
|
||||
typeError: "Паз {slot} приймає \"{expect}\" тип, але надана змінна має тип \"{actual}\"!"
|
||||
thereIsEmptySlot: "Паз {slot} пустий!"
|
||||
types:
|
||||
string: "Текст"
|
||||
number: "Число"
|
||||
boolean: "Прапорець"
|
||||
array: "Списки"
|
||||
stringArray: "Текстовий список"
|
||||
emptySlot: "Пустий паз"
|
||||
enviromentVariables: "Змінні середовища"
|
||||
pageVariables: "Елемент сторінки"
|
||||
argVariables: "Стрічка вводу"
|
||||
_relayStatus:
|
||||
requesting: "Очікує затвердження"
|
||||
accepted: "Затверджено"
|
||||
|
|
|
@ -472,6 +472,8 @@ dayOverDayChanges: "Thay đổi hôm qua"
|
|||
appearance: "Giao diện"
|
||||
clientSettings: "Cài đặt Client"
|
||||
accountSettings: "Cài đặt tài khoản"
|
||||
promotion: "Quảng cáo"
|
||||
promote: "Quảng cáo"
|
||||
numberOfDays: "Số ngày"
|
||||
hideThisNote: "Ẩn tút này"
|
||||
showFeaturedNotesInTimeline: "Hiện tút nổi bật trong bảng tin"
|
||||
|
@ -547,6 +549,7 @@ poll: "Bình chọn"
|
|||
useCw: "Ẩn nội dung"
|
||||
enablePlayer: "Mở trình phát video"
|
||||
disablePlayer: "Đóng trình phát video"
|
||||
expandTweet: "Mở rộng tweet"
|
||||
themeEditor: "Công cụ thiết kế theme"
|
||||
description: "Mô tả"
|
||||
describeFile: "Thêm mô tả"
|
||||
|
@ -1321,7 +1324,10 @@ _pages:
|
|||
my: "Trang của tôi"
|
||||
liked: "Trang đã thích"
|
||||
featured: "Nổi tiếng"
|
||||
inspector: "Thanh tra"
|
||||
contents: "Nội dung"
|
||||
content: "Chặn Trang"
|
||||
variables: "Biến thể"
|
||||
title: "Tựa đề"
|
||||
url: "URL Trang"
|
||||
summary: "Mô tả Trang"
|
||||
|
@ -1332,6 +1338,262 @@ _pages:
|
|||
fontSansSerif: "Sans Serif"
|
||||
eyeCatchingImageSet: "Đặt ảnh thu nhỏ"
|
||||
eyeCatchingImageRemove: "Xóa ảnh thu nhỏ"
|
||||
chooseBlock: "Thêm khối"
|
||||
selectType: "Chọn kiểu"
|
||||
enterVariableName: "Nhập tên một biến thể"
|
||||
variableNameIsAlreadyUsed: "Tên biến thể này đã được sử dụng"
|
||||
contentBlocks: "Nội dung"
|
||||
inputBlocks: "Nhập"
|
||||
specialBlocks: "Đặc biệt"
|
||||
blocks:
|
||||
text: "Văn bản"
|
||||
textarea: "Khu vực văn bản"
|
||||
section: "Mục "
|
||||
image: "Hình ảnh"
|
||||
button: "Nút"
|
||||
if: "Nếu"
|
||||
_if:
|
||||
variable: "Biến thể"
|
||||
post: "Mẫu đăng"
|
||||
_post:
|
||||
text: "Nội dung"
|
||||
attachCanvasImage: "Đính kèm hình canva"
|
||||
canvasId: "ID Canva"
|
||||
textInput: "Văn bản đầu vào"
|
||||
_textInput:
|
||||
name: "Tên biến thể"
|
||||
text: "Tựa đề"
|
||||
default: "Giá trị mặc định"
|
||||
textareaInput: "Văn bản nhiều dòng đầu vào"
|
||||
_textareaInput:
|
||||
name: "Tên biến thể"
|
||||
text: "Tựa đề"
|
||||
default: "Giá trị mặc định"
|
||||
numberInput: "Đầu vào số"
|
||||
_numberInput:
|
||||
name: "Tên biến thể"
|
||||
text: "Tựa đề"
|
||||
default: "Giá trị mặc định"
|
||||
canvas: "Canva"
|
||||
_canvas:
|
||||
id: "ID Canva"
|
||||
width: "Chiều rộng"
|
||||
height: "Chiều cao"
|
||||
note: "Tút đã nhúng"
|
||||
_note:
|
||||
id: "ID tút"
|
||||
idDescription: "Ngoài ra, bạn có thể dán URL tút vào đây."
|
||||
detailed: "Xem chi tiết"
|
||||
switch: "Chuyển đổi"
|
||||
_switch:
|
||||
name: "Tên biến thể"
|
||||
text: "Tựa đề"
|
||||
default: "Giá trị mặc định"
|
||||
counter: "Bộ đếm"
|
||||
_counter:
|
||||
name: "Tên biến thể"
|
||||
text: "Tựa đề"
|
||||
inc: "Bước"
|
||||
_button:
|
||||
text: "Tựa đề"
|
||||
colored: "Với màu"
|
||||
action: "Thao tác khi nhấn nút"
|
||||
_action:
|
||||
dialog: "Hiện hộp thoại"
|
||||
_dialog:
|
||||
content: "Nội dung"
|
||||
resetRandom: "Đặt lại seed ngẫu nhiên"
|
||||
pushEvent: "Gửi một sự kiện"
|
||||
_pushEvent:
|
||||
event: "Tên sự kiện"
|
||||
message: "Tin nhắn hiển thị khi kích hoạt"
|
||||
variable: "Biển thể để gửi"
|
||||
no-variable: "Không"
|
||||
callAiScript: "Gọi AiScript"
|
||||
_callAiScript:
|
||||
functionName: "Tên tính năng"
|
||||
radioButton: "Lựa chọn"
|
||||
_radioButton:
|
||||
name: "Tên biến thể"
|
||||
title: "Tựa đề"
|
||||
values: "Phân tách các mục bằng cách xuống dòng"
|
||||
default: "Giá trị mặc định"
|
||||
script:
|
||||
categories:
|
||||
flow: "Điều khiển"
|
||||
logical: "Hoạt động logic"
|
||||
operation: "Tính toán"
|
||||
comparison: "So sánh"
|
||||
random: "Ngẫu nhiên"
|
||||
value: "Giá trị"
|
||||
fn: "Tính năng"
|
||||
text: "Tác vụ văn bản"
|
||||
convert: "Chuyển đổi"
|
||||
list: "Danh sách"
|
||||
blocks:
|
||||
text: "Văn bản"
|
||||
multiLineText: "Văn bản (nhiều dòng)"
|
||||
textList: "Văn bản liệt kê"
|
||||
_textList:
|
||||
info: "Phân tách mục bằng cách xuống dòng"
|
||||
strLen: "Độ dài văn bản"
|
||||
_strLen:
|
||||
arg1: "Văn bản"
|
||||
strPick: "Trích xuất chuỗi"
|
||||
_strPick:
|
||||
arg1: "Văn bản"
|
||||
arg2: "Vị trí chuỗi"
|
||||
strReplace: "Thay thế chuỗi"
|
||||
_strReplace:
|
||||
arg1: "Nội dung"
|
||||
arg2: "Văn bản thay thế"
|
||||
arg3: "Thay thế bằng"
|
||||
strReverse: "Lật văn bản"
|
||||
_strReverse:
|
||||
arg1: "Văn bản"
|
||||
join: "Nối văn bản"
|
||||
_join:
|
||||
arg1: "Danh sách"
|
||||
arg2: "Phân cách"
|
||||
add: "Cộng"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "Trừ"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "Nhân"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "Chia"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "Phần còn lại"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "Làm tròn thập phân"
|
||||
_round:
|
||||
arg1: "Số"
|
||||
eq: "A và B bằng nhau"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A và B khác nhau"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A VÀ B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A HOẶC B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A nhỏ hơn B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A lớn hơn B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A nhỏ hơn hoặc bằng B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A lớn hơn hoặc bằng B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "Nhánh"
|
||||
_if:
|
||||
arg1: "Nếu"
|
||||
arg2: "Sau đó"
|
||||
arg3: "Khác"
|
||||
not: "KHÔNG"
|
||||
_not:
|
||||
arg1: "KHÔNG"
|
||||
random: "Ngẫu nhiên"
|
||||
_random:
|
||||
arg1: "Xác suất"
|
||||
rannum: "Số ngẫu nhiên"
|
||||
_rannum:
|
||||
arg1: "Giá trị tối thiểu"
|
||||
arg2: "Giá trị tối đa"
|
||||
randomPick: "Chọn ngẫu nhiên từ danh sách"
|
||||
_randomPick:
|
||||
arg1: "Danh sách"
|
||||
dailyRandom: "Ngẫu nhiên (Đổi mỗi người một lần mỗi ngày)"
|
||||
_dailyRandom:
|
||||
arg1: "Xác suất"
|
||||
dailyRannum: "Số ngẫu nhiên (Đổi mỗi người một lần mỗi ngày)"
|
||||
_dailyRannum:
|
||||
arg1: "Giá trị tối thiểu"
|
||||
arg2: "Giá trị tối đa"
|
||||
dailyRandomPick: "Chọn ngẫu nhiên từ một danh sách (Đổi mỗi người một lần mỗi ngày)"
|
||||
_dailyRandomPick:
|
||||
arg1: "Danh sách"
|
||||
seedRandom: "Ngẫu nhiên (với seed)"
|
||||
_seedRandom:
|
||||
arg1: "Seed"
|
||||
arg2: "Xác suất"
|
||||
seedRannum: "Số ngẫu nhiên (với seed)"
|
||||
_seedRannum:
|
||||
arg1: "Seed"
|
||||
arg2: "Giá trị tối thiểu"
|
||||
arg3: "Giá trị tối đa"
|
||||
seedRandomPick: "Chọn ngẫu nhiên từ danh sách (với seed)"
|
||||
_seedRandomPick:
|
||||
arg1: "Seed"
|
||||
arg2: "Danh sách"
|
||||
DRPWPM: "Chọn ngẫu nhiên từ danh sách nặng (Đổi mỗi người một lần mỗi ngày)"
|
||||
_DRPWPM:
|
||||
arg1: "Văn bản liệt kê"
|
||||
pick: "Chọn từ danh sách"
|
||||
_pick:
|
||||
arg1: "Danh sách"
|
||||
arg2: "Vị trí"
|
||||
listLen: "Lấy độ dài danh sách"
|
||||
_listLen:
|
||||
arg1: "Danh sách"
|
||||
number: "Số"
|
||||
stringToNumber: "Chữ thành số"
|
||||
_stringToNumber:
|
||||
arg1: "Văn bản"
|
||||
numberToString: "Số thành chữ"
|
||||
_numberToString:
|
||||
arg1: "Số"
|
||||
splitStrByLine: "Phân cách văn bản bằng cách xuống dòng"
|
||||
_splitStrByLine:
|
||||
arg1: "Văn bản"
|
||||
ref: "Biến thể"
|
||||
aiScriptVar: "Biển thể AiScript"
|
||||
fn: "Tính năng"
|
||||
_fn:
|
||||
slots: "Chỗ"
|
||||
slots-info: "Phân cách chỗ bằng cách xuống dòng"
|
||||
arg1: "Đầu ra"
|
||||
for: "để-Lặp lại"
|
||||
_for:
|
||||
arg1: "Số lần lặp lại"
|
||||
arg2: "Hành động"
|
||||
typeError: "Chỗ {slot} chấp nhận các giá trị thuộc loại \"{expect}\", nhưng giá trị được cung cấp thuộc loại \"{actual}\"!"
|
||||
thereIsEmptySlot: "Chỗ {slot} đang trống!"
|
||||
types:
|
||||
string: "Văn bản"
|
||||
number: "Số"
|
||||
boolean: "Cờ"
|
||||
array: "Danh sách"
|
||||
stringArray: "Văn bản liệt kê"
|
||||
emptySlot: "Chỗ trống"
|
||||
enviromentVariables: "Biến môi trường"
|
||||
pageVariables: "Biến trang"
|
||||
argVariables: "Đầu vào chỗ"
|
||||
_relayStatus:
|
||||
requesting: "Đang chờ"
|
||||
accepted: "Đã duyệt"
|
||||
|
|
|
@ -472,6 +472,8 @@ dayOverDayChanges: "与前一日相比"
|
|||
appearance: "外观"
|
||||
clientSettings: "客户端设置"
|
||||
accountSettings: "账户设置"
|
||||
promotion: "推广"
|
||||
promote: "推广"
|
||||
numberOfDays: "天数"
|
||||
hideThisNote: "隐藏这条帖子"
|
||||
showFeaturedNotesInTimeline: "在时间线上显示热门推荐"
|
||||
|
@ -547,6 +549,7 @@ poll: "调查问卷"
|
|||
useCw: "隐藏内容"
|
||||
enablePlayer: "打开播放器"
|
||||
disablePlayer: "关闭播放器"
|
||||
expandTweet: "展开帖子"
|
||||
themeEditor: "主题编辑器"
|
||||
description: "描述"
|
||||
describeFile: "添加标题"
|
||||
|
@ -1320,7 +1323,10 @@ _pages:
|
|||
my: "我的页面"
|
||||
liked: "喜欢的页面"
|
||||
featured: "热门"
|
||||
inspector: "检查器"
|
||||
contents: "内容"
|
||||
content: "页面内容"
|
||||
variables: "变量"
|
||||
title: "标题"
|
||||
url: "页面URL"
|
||||
summary: "页面摘要"
|
||||
|
@ -1331,6 +1337,262 @@ _pages:
|
|||
fontSansSerif: "无衬线字体"
|
||||
eyeCatchingImageSet: "设置封面图片"
|
||||
eyeCatchingImageRemove: "删除封面图片"
|
||||
chooseBlock: "添加块"
|
||||
selectType: "选择类型"
|
||||
enterVariableName: "请输入变量名"
|
||||
variableNameIsAlreadyUsed: "变量名已使用"
|
||||
contentBlocks: "内容"
|
||||
inputBlocks: "输入"
|
||||
specialBlocks: "特殊"
|
||||
blocks:
|
||||
text: "文本"
|
||||
textarea: "文本区域"
|
||||
section: "章节"
|
||||
image: "图片"
|
||||
button: "按钮"
|
||||
if: "如果"
|
||||
_if:
|
||||
variable: "变量"
|
||||
post: "投稿窗口"
|
||||
_post:
|
||||
text: "内容"
|
||||
attachCanvasImage: "附加画布图像"
|
||||
canvasId: "画布ID"
|
||||
textInput: "文本输入"
|
||||
_textInput:
|
||||
name: "变量名"
|
||||
text: "标题"
|
||||
default: "默认值"
|
||||
textareaInput: "多行文本输入"
|
||||
_textareaInput:
|
||||
name: "变量名"
|
||||
text: "标题"
|
||||
default: "默认值"
|
||||
numberInput: "输入数值"
|
||||
_numberInput:
|
||||
name: "变量名"
|
||||
text: "标题"
|
||||
default: "默认值"
|
||||
canvas: "画布"
|
||||
_canvas:
|
||||
id: "画布ID"
|
||||
width: "宽度"
|
||||
height: "高度"
|
||||
note: "嵌入的帖子"
|
||||
_note:
|
||||
id: "帖子ID"
|
||||
idDescription: "您也可以通过粘贴帖子的URL来进行设置。"
|
||||
detailed: "显示详细信息"
|
||||
switch: "开关"
|
||||
_switch:
|
||||
name: "变量名"
|
||||
text: "标题"
|
||||
default: "默认值"
|
||||
counter: "计数器"
|
||||
_counter:
|
||||
name: "变量名"
|
||||
text: "标题"
|
||||
inc: "增加值"
|
||||
_button:
|
||||
text: "标题"
|
||||
colored: "彩色"
|
||||
action: "按下按钮时的行为"
|
||||
_action:
|
||||
dialog: "显示对话框"
|
||||
_dialog:
|
||||
content: "内容"
|
||||
resetRandom: "重置随机值"
|
||||
pushEvent: "发送事件"
|
||||
_pushEvent:
|
||||
event: "事件名称"
|
||||
message: "按下时显示的消息"
|
||||
variable: "发送的变量"
|
||||
no-variable: "空"
|
||||
callAiScript: "调用AiScript"
|
||||
_callAiScript:
|
||||
functionName: "函数名"
|
||||
radioButton: "选择项"
|
||||
_radioButton:
|
||||
name: "变量名"
|
||||
title: "标题"
|
||||
values: "使用换行区分的选择项"
|
||||
default: "默认值"
|
||||
script:
|
||||
categories:
|
||||
flow: "控制"
|
||||
logical: "逻辑运算"
|
||||
operation: "计算"
|
||||
comparison: "比较"
|
||||
random: "随机"
|
||||
value: "值"
|
||||
fn: "函数"
|
||||
text: "文本操作"
|
||||
convert: "转换"
|
||||
list: "列表"
|
||||
blocks:
|
||||
text: "文本"
|
||||
multiLineText: "文本 (多行)"
|
||||
textList: "文本列表"
|
||||
_textList:
|
||||
info: "请使用换行符分隔每行"
|
||||
strLen: "文本长度"
|
||||
_strLen:
|
||||
arg1: "文本"
|
||||
strPick: "提取字符"
|
||||
_strPick:
|
||||
arg1: "文本"
|
||||
arg2: "字符位置"
|
||||
strReplace: "替换文本"
|
||||
_strReplace:
|
||||
arg1: "文本"
|
||||
arg2: "替换之前"
|
||||
arg3: "替换之后"
|
||||
strReverse: "文本反向"
|
||||
_strReverse:
|
||||
arg1: "文本"
|
||||
join: "合并文本"
|
||||
_join:
|
||||
arg1: "列表"
|
||||
arg2: "分隔符"
|
||||
add: "加"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "减"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "乘"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "除"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "取模(MOD)"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "四舍五入"
|
||||
_round:
|
||||
arg1: "数值"
|
||||
eq: "A和B相等"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A和B不等"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A和B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A或B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A小于B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A大于B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A小于等于B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A大于等于B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "分支"
|
||||
_if:
|
||||
arg1: "如果"
|
||||
arg2: "如果"
|
||||
arg3: "否则"
|
||||
not: "否"
|
||||
_not:
|
||||
arg1: "否"
|
||||
random: "随机"
|
||||
_random:
|
||||
arg1: "概率"
|
||||
rannum: "随机数"
|
||||
_rannum:
|
||||
arg1: "最小值"
|
||||
arg2: "最大值"
|
||||
randomPick: "从列表中随机选择"
|
||||
_randomPick:
|
||||
arg1: "列表"
|
||||
dailyRandom: "随机(每个用户每日)"
|
||||
_dailyRandom:
|
||||
arg1: "概率"
|
||||
dailyRannum: "随机数(每个用户每日)"
|
||||
_dailyRannum:
|
||||
arg1: "最小值"
|
||||
arg2: "最大值"
|
||||
dailyRandomPick: "从列表中随机选择(每个用户每日)"
|
||||
_dailyRandomPick:
|
||||
arg1: "列表"
|
||||
seedRandom: "随机 (种子)"
|
||||
_seedRandom:
|
||||
arg1: "种子"
|
||||
arg2: "概率"
|
||||
seedRannum: "随机数(种子)"
|
||||
_seedRannum:
|
||||
arg1: "种子"
|
||||
arg2: "最小值"
|
||||
arg3: "最大值"
|
||||
seedRandomPick: "从列表中随机选择 (种子)"
|
||||
_seedRandomPick:
|
||||
arg1: "种子"
|
||||
arg2: "列表"
|
||||
DRPWPM: "从概率列表中随机选择(每用户每天)"
|
||||
_DRPWPM:
|
||||
arg1: "文本列表"
|
||||
pick: "从列表中选择"
|
||||
_pick:
|
||||
arg1: "列表"
|
||||
arg2: "位置"
|
||||
listLen: "获取列表长度"
|
||||
_listLen:
|
||||
arg1: "列表"
|
||||
number: "数值"
|
||||
stringToNumber: "文本到数字"
|
||||
_stringToNumber:
|
||||
arg1: "文本"
|
||||
numberToString: "数字到文本"
|
||||
_numberToString:
|
||||
arg1: "数值"
|
||||
splitStrByLine: "将文本按行拆分"
|
||||
_splitStrByLine:
|
||||
arg1: "文本"
|
||||
ref: "变量"
|
||||
aiScriptVar: "AiScript变量"
|
||||
fn: "函数"
|
||||
_fn:
|
||||
slots: "槽函数"
|
||||
slots-info: "请使用换行符分隔每个槽函数"
|
||||
arg1: "输出"
|
||||
for: "重复"
|
||||
_for:
|
||||
arg1: "次数"
|
||||
arg2: "处理"
|
||||
typeError: "槽函数{slot}需要传入“{expect}”,但是实际传入为“{actual}”!"
|
||||
thereIsEmptySlot: "槽函数{slot}为空!"
|
||||
types:
|
||||
string: "文字"
|
||||
number: "数值"
|
||||
boolean: "Flag"
|
||||
array: "列表"
|
||||
stringArray: "文本列表"
|
||||
emptySlot: "空白槽函数"
|
||||
enviromentVariables: "环境变量"
|
||||
pageVariables: "页面元素"
|
||||
argVariables: "输入变量"
|
||||
_relayStatus:
|
||||
requesting: "待批准"
|
||||
accepted: "已批准"
|
||||
|
|
|
@ -472,6 +472,8 @@ dayOverDayChanges: "與前一日相比"
|
|||
appearance: "外觀"
|
||||
clientSettings: "用戶端設定"
|
||||
accountSettings: "帳戶設定"
|
||||
promotion: "推廣"
|
||||
promote: "推廣"
|
||||
numberOfDays: "有效天數"
|
||||
hideThisNote: "隱藏此貼文"
|
||||
showFeaturedNotesInTimeline: "在時間軸上顯示熱門推薦"
|
||||
|
@ -547,6 +549,7 @@ poll: "投票"
|
|||
useCw: "隱藏內容"
|
||||
enablePlayer: "打開播放器"
|
||||
disablePlayer: "關閉播放器"
|
||||
expandTweet: "展開推文"
|
||||
themeEditor: "主題編輯器"
|
||||
description: "描述"
|
||||
describeFile: "添加標題 "
|
||||
|
@ -1320,7 +1323,10 @@ _pages:
|
|||
my: "我的頁面"
|
||||
liked: "已喜歡的頁面"
|
||||
featured: "人氣"
|
||||
inspector: "面板檢查"
|
||||
contents: "內容"
|
||||
content: "頁面方塊"
|
||||
variables: "變數"
|
||||
title: "標題"
|
||||
url: "頁面網址"
|
||||
summary: "頁面摘要"
|
||||
|
@ -1331,6 +1337,262 @@ _pages:
|
|||
fontSansSerif: "無襯線體"
|
||||
eyeCatchingImageSet: "設定封面影像"
|
||||
eyeCatchingImageRemove: "刪除封面影像"
|
||||
chooseBlock: "新增方塊"
|
||||
selectType: "選擇類型"
|
||||
enterVariableName: "請輸入變數名稱"
|
||||
variableNameIsAlreadyUsed: "變數名稱已被佔用"
|
||||
contentBlocks: "內容"
|
||||
inputBlocks: "輸入"
|
||||
specialBlocks: "特殊"
|
||||
blocks:
|
||||
text: "字串"
|
||||
textarea: "字串區域"
|
||||
section: "區段"
|
||||
image: "圖片"
|
||||
button: "按鈕"
|
||||
if: "如果"
|
||||
_if:
|
||||
variable: "變數"
|
||||
post: "發佈窗口"
|
||||
_post:
|
||||
text: "内容"
|
||||
attachCanvasImage: "附加相簿圖像 "
|
||||
canvasId: "畫布ID"
|
||||
textInput: "插入字串"
|
||||
_textInput:
|
||||
name: "變數名稱"
|
||||
text: "標題"
|
||||
default: "預設值"
|
||||
textareaInput: "多行文字输入"
|
||||
_textareaInput:
|
||||
name: "變數名稱"
|
||||
text: "標題"
|
||||
default: "預設值"
|
||||
numberInput: "輸入數值"
|
||||
_numberInput:
|
||||
name: "變數名稱"
|
||||
text: "標題"
|
||||
default: "預設值"
|
||||
canvas: "畫布"
|
||||
_canvas:
|
||||
id: "畫布ID"
|
||||
width: "寬度"
|
||||
height: "高度"
|
||||
note: "嵌式貼文"
|
||||
_note:
|
||||
id: "貼文ID"
|
||||
idDescription: "您也可以粘貼筆記 URL 並進行設置。 "
|
||||
detailed: "顯示詳細內容"
|
||||
switch: "開關"
|
||||
_switch:
|
||||
name: "變數名稱"
|
||||
text: "標題"
|
||||
default: "預設值"
|
||||
counter: "計數器"
|
||||
_counter:
|
||||
name: "變數名稱"
|
||||
text: "標題"
|
||||
inc: "増加値"
|
||||
_button:
|
||||
text: "標題"
|
||||
colored: "彩色"
|
||||
action: "按下按鈕後發生的行為"
|
||||
_action:
|
||||
dialog: "顯示對話框 "
|
||||
_dialog:
|
||||
content: "内容"
|
||||
resetRandom: "重設亂數"
|
||||
pushEvent: "發送事件"
|
||||
_pushEvent:
|
||||
event: "事件名稱"
|
||||
message: "按下時顯示的消息 "
|
||||
variable: "要發送的變數"
|
||||
no-variable: "沒有"
|
||||
callAiScript: "調用AiScript"
|
||||
_callAiScript:
|
||||
functionName: "函數名稱"
|
||||
radioButton: "選項"
|
||||
_radioButton:
|
||||
name: "變數名稱"
|
||||
title: "標題"
|
||||
values: "由換行符分隔的選項"
|
||||
default: "預設值"
|
||||
script:
|
||||
categories:
|
||||
flow: "控制"
|
||||
logical: "邏輯運算"
|
||||
operation: "計算"
|
||||
comparison: "對比"
|
||||
random: "隨機"
|
||||
value: "數值 "
|
||||
fn: "函数"
|
||||
text: "文本操作"
|
||||
convert: "轉換"
|
||||
list: "清單"
|
||||
blocks:
|
||||
text: "字串"
|
||||
multiLineText: "字串(多行)"
|
||||
textList: "字串串列"
|
||||
_textList:
|
||||
info: "請分開每個換行符 "
|
||||
strLen: "字串長度"
|
||||
_strLen:
|
||||
arg1: "字串"
|
||||
strPick: "提取字元"
|
||||
_strPick:
|
||||
arg1: "字串"
|
||||
arg2: "字元位置"
|
||||
strReplace: "替換字串"
|
||||
_strReplace:
|
||||
arg1: "字串"
|
||||
arg2: "替換前"
|
||||
arg3: "替換後"
|
||||
strReverse: "倒轉字串"
|
||||
_strReverse:
|
||||
arg1: "字串"
|
||||
join: "合併字串"
|
||||
_join:
|
||||
arg1: "清單"
|
||||
arg2: "分隔字元"
|
||||
add: "加"
|
||||
_add:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
subtract: "减去"
|
||||
_subtract:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
multiply: "乘"
|
||||
_multiply:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
divide: "除"
|
||||
_divide:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
mod: "餘數"
|
||||
_mod:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
round: "四舍五入"
|
||||
_round:
|
||||
arg1: "數值"
|
||||
eq: "A和B相等"
|
||||
_eq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
notEq: "A和B不等"
|
||||
_notEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
and: "A和B"
|
||||
_and:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
or: "A或B"
|
||||
_or:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
lt: "< A小於B"
|
||||
_lt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gt: "> A大於B"
|
||||
_gt:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
ltEq: "<= A小於或等於B"
|
||||
_ltEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
gtEq: ">= A大於或等於B"
|
||||
_gtEq:
|
||||
arg1: "A"
|
||||
arg2: "B"
|
||||
if: "分支"
|
||||
_if:
|
||||
arg1: "如果"
|
||||
arg2: "如果"
|
||||
arg3: "除此以外 "
|
||||
not: "否"
|
||||
_not:
|
||||
arg1: "否"
|
||||
random: "隨機"
|
||||
_random:
|
||||
arg1: "機率"
|
||||
rannum: "亂數"
|
||||
_rannum:
|
||||
arg1: "下限"
|
||||
arg2: "上限"
|
||||
randomPick: "從列表中隨機選擇 "
|
||||
_randomPick:
|
||||
arg1: "清單"
|
||||
dailyRandom: "隨機(使用者每日變化 )"
|
||||
_dailyRandom:
|
||||
arg1: "機率"
|
||||
dailyRannum: "亂數(使用者每日變化)"
|
||||
_dailyRannum:
|
||||
arg1: "下限"
|
||||
arg2: "上限"
|
||||
dailyRandomPick: "從列表中隨機選擇(使用者每日變化 ) "
|
||||
_dailyRandomPick:
|
||||
arg1: "清單"
|
||||
seedRandom: "隨機抽選種子碼"
|
||||
_seedRandom:
|
||||
arg1: "種子"
|
||||
arg2: "機率"
|
||||
seedRannum: "亂數 (種子)"
|
||||
_seedRannum:
|
||||
arg1: "種子"
|
||||
arg2: "最小值"
|
||||
arg3: "最大值"
|
||||
seedRandomPick: "從列表中隨機選擇 (種子)"
|
||||
_seedRandomPick:
|
||||
arg1: "種子"
|
||||
arg2: "清單"
|
||||
DRPWPM: "从機率列表中隨機選擇(每個用户每天)"
|
||||
_DRPWPM:
|
||||
arg1: "字串串列"
|
||||
pick: "從清單中選取"
|
||||
_pick:
|
||||
arg1: "清單"
|
||||
arg2: "位置"
|
||||
listLen: "取得清單長度"
|
||||
_listLen:
|
||||
arg1: "清單"
|
||||
number: "數值"
|
||||
stringToNumber: "將字串轉換至數値"
|
||||
_stringToNumber:
|
||||
arg1: "字串"
|
||||
numberToString: "將數値轉換至字串"
|
||||
_numberToString:
|
||||
arg1: "數值"
|
||||
splitStrByLine: "於換行時分割字串"
|
||||
_splitStrByLine:
|
||||
arg1: "字串"
|
||||
ref: "變數"
|
||||
aiScriptVar: "AiScript的變數"
|
||||
fn: "函数"
|
||||
_fn:
|
||||
slots: "欄位"
|
||||
slots-info: "用換行符分隔每個欄位"
|
||||
arg1: "輸出"
|
||||
for: "重複 "
|
||||
_for:
|
||||
arg1: "重複次數"
|
||||
arg2: "處理"
|
||||
typeError: "槽參數{slot}需要傳入“{expect}”,但是實際傳入為“{actual}”!"
|
||||
thereIsEmptySlot: "參數{slot}是空的!"
|
||||
types:
|
||||
string: "字串"
|
||||
number: "数值"
|
||||
boolean: "標記"
|
||||
array: "清單"
|
||||
stringArray: "字串列表"
|
||||
emptySlot: "空欄位"
|
||||
enviromentVariables: "環境變數"
|
||||
pageVariables: "頁面元素"
|
||||
argVariables: "輸入欄位"
|
||||
_relayStatus:
|
||||
requesting: "等待核准"
|
||||
accepted: "已通過核准"
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
export class pagesToPlaintext1659335999000 {
|
||||
name = 'pagesToPlaintext1659335999000'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "page" ADD "text" text`);
|
||||
|
||||
async function noteUrl(noteId) {
|
||||
const note = await queryRunner.query(`SELECT "uri", "userHost" FROM "note" WHERE "id" = $1`, [noteId]);
|
||||
if (note.uri) return note.uri;
|
||||
// don't really have access to the configuration here so just guess
|
||||
else return `https://${note.userHost}/notes/${noteId}`;
|
||||
}
|
||||
|
||||
async function fileUrl(fileId) {
|
||||
const file = await queryRunner.query(`SELECT "url" from "drive_file" WHERE "id" = $1`, [fileId]);
|
||||
return file.url;
|
||||
}
|
||||
|
||||
async function convertBlock(block) {
|
||||
switch (block.type) {
|
||||
case 'note':
|
||||
if (block.note) return await noteUrl(block.note);
|
||||
else break;
|
||||
case 'section':
|
||||
return (await Promise.all(block.children.map(convertBlock))).join('\n');
|
||||
case 'text':
|
||||
return block.text;
|
||||
case 'textarea':
|
||||
return '```\n' + block.text + '```';
|
||||
case 'image':
|
||||
if (block.fileId) return '![image](' + await fileUrl(block.fileId) + ')';
|
||||
else break;
|
||||
case 'if': // no idea how to convert these
|
||||
case 'post': // new note form, why?
|
||||
case 'canvas': // there is some aiscript api for these but dont think anyone ever used it
|
||||
// interactive elements can also not be converted
|
||||
case 'button':
|
||||
case 'numberInput':
|
||||
case 'textInput':
|
||||
case 'switch':
|
||||
case 'radioButton':
|
||||
case 'counter':
|
||||
break;
|
||||
}
|
||||
|
||||
return `(There was a/an ${block.type} here in a previous version but it is no longer supported.)`;
|
||||
}
|
||||
|
||||
await queryRunner.query(`SELECT id, "content" FROM "page"`)
|
||||
.then(pages => Promise.all(pages.map(page => {
|
||||
return Promise.all(page.content.map(convertBlock))
|
||||
.then(texts => {
|
||||
queryRunner.query(`UPDATE "page" SET "text" = $1 WHERE "id" = $2`, [texts.join('\n'), page.id]);
|
||||
});
|
||||
})));
|
||||
|
||||
await queryRunner.query(`ALTER TABLE "page" DROP COLUMN "content"`);
|
||||
await queryRunner.query(`ALTER TABLE "page" DROP COLUMN "variables"`);
|
||||
await queryRunner.query(`ALTER TABLE "page" DROP COLUMN "script"`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "page" ADD "content" jsonb default '[]'::jsonb`);
|
||||
await queryRunner.query(`ALTER TABLE "page" ADD "variables" jsonb default '[]'::jsonb`);
|
||||
await queryRunner.query(`ALTER TABLE "page" ADD "script" character varying(16384) default ''`);
|
||||
|
||||
// The conversion from the previous page content to text is lossy,
|
||||
// so we can just convert it back to a big text block.
|
||||
await queryRunner.query(`SELECT "id", "text" FROM "page"`)
|
||||
.then(pages => Promise.all(pages.map(page => {
|
||||
const content = [{
|
||||
// just a random UUID to keep the data structure
|
||||
id: '0730b23f-ab5b-4d56-8bd1-f4ead3f72af7',
|
||||
type: 'text',
|
||||
text: page.text,
|
||||
}];
|
||||
return queryRunner.query(`UPDATE "page" SET "content" = $1 WHERE "id" = $2`, [JSON.stringify(content), page.id]);
|
||||
})));
|
||||
|
||||
await queryRunner.query(`ALTER TABLE "page" DROP COLUMN "text"`);
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
export class removePromoEntities1660251834642 {
|
||||
name = 'removePromoEntities1660251834642';
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "promo_read" DROP CONSTRAINT "FK_a46a1a603ecee695d7db26da5f4"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "promo_read" DROP CONSTRAINT "FK_9657d55550c3d37bfafaf7d4b05"`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "promo_note" DROP CONSTRAINT "FK_e263909ca4fe5d57f8d4230dd5c"`, undefined);
|
||||
await queryRunner.query(`DROP INDEX "IDX_2882b8a1a07c7d281a98b6db16"`, undefined);
|
||||
await queryRunner.query(`DROP INDEX "IDX_9657d55550c3d37bfafaf7d4b0"`, undefined);
|
||||
await queryRunner.query(`DROP TABLE "promo_read"`, undefined);
|
||||
await queryRunner.query(`DROP INDEX "IDX_83f0862e9bae44af52ced7099e"`, undefined);
|
||||
await queryRunner.query(`DROP TABLE "promo_note"`, undefined);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`CREATE TABLE "promo_note" ("noteId" character varying(32) NOT NULL, "expiresAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, CONSTRAINT "REL_e263909ca4fe5d57f8d4230dd5" UNIQUE ("noteId"), CONSTRAINT "PK_e263909ca4fe5d57f8d4230dd5c" PRIMARY KEY ("noteId"))`, undefined);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_83f0862e9bae44af52ced7099e" ON "promo_note" ("userId") `, undefined);
|
||||
await queryRunner.query(`CREATE TABLE "promo_read" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, CONSTRAINT "PK_61917c1541002422b703318b7c9" PRIMARY KEY ("id"))`, undefined);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_9657d55550c3d37bfafaf7d4b0" ON "promo_read" ("userId") `, undefined);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_2882b8a1a07c7d281a98b6db16" ON "promo_read" ("userId", "noteId") `, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "promo_note" ADD CONSTRAINT "FK_e263909ca4fe5d57f8d4230dd5c" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "promo_read" ADD CONSTRAINT "FK_9657d55550c3d37bfafaf7d4b05" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
|
||||
await queryRunner.query(`ALTER TABLE "promo_read" ADD CONSTRAINT "FK_a46a1a603ecee695d7db26da5f4" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
|
||||
}
|
||||
}
|
|
@ -69,7 +69,7 @@
|
|||
"mime-types": "2.1.35",
|
||||
"misskey-js": "0.0.14",
|
||||
"mocha": "10.0.0",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"multer": "1.4.4",
|
||||
"nested-property": "4.0.0",
|
||||
"node-fetch": "3.2.6",
|
||||
"nodemailer": "6.7.6",
|
||||
|
|
|
@ -57,6 +57,8 @@ import { Clip } from '@/models/entities/clip.js';
|
|||
import { ClipNote } from '@/models/entities/clip-note.js';
|
||||
import { Antenna } from '@/models/entities/antenna.js';
|
||||
import { AntennaNote } from '@/models/entities/antenna-note.js';
|
||||
import { PromoNote } from '@/models/entities/promo-note.js';
|
||||
import { PromoRead } from '@/models/entities/promo-read.js';
|
||||
import { Relay } from '@/models/entities/relay.js';
|
||||
import { MutedNote } from '@/models/entities/muted-note.js';
|
||||
import { Channel } from '@/models/entities/channel.js';
|
||||
|
@ -157,6 +159,8 @@ export const entities = [
|
|||
ClipNote,
|
||||
Antenna,
|
||||
AntennaNote,
|
||||
PromoNote,
|
||||
PromoRead,
|
||||
Relay,
|
||||
MutedNote,
|
||||
Channel,
|
||||
|
|
|
@ -75,10 +75,21 @@ export class Page {
|
|||
@JoinColumn()
|
||||
public eyeCatchingImage: DriveFile | null;
|
||||
|
||||
@Column('text', {
|
||||
@Column('jsonb', {
|
||||
default: [],
|
||||
})
|
||||
public content: Record<string, any>[];
|
||||
|
||||
@Column('jsonb', {
|
||||
default: [],
|
||||
})
|
||||
public variables: Record<string, any>[];
|
||||
|
||||
@Column('varchar', {
|
||||
length: 16384,
|
||||
default: '',
|
||||
})
|
||||
public text: string;
|
||||
public script: string;
|
||||
|
||||
/**
|
||||
* public ... 公開
|
||||
|
|
28
packages/backend/src/models/entities/promo-note.ts
Normal file
28
packages/backend/src/models/entities/promo-note.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { PrimaryColumn, Entity, Index, JoinColumn, Column, OneToOne } from 'typeorm';
|
||||
import { id } from '../id.js';
|
||||
import { Note } from './note.js';
|
||||
import { User } from './user.js';
|
||||
|
||||
@Entity()
|
||||
export class PromoNote {
|
||||
@PrimaryColumn(id())
|
||||
public noteId: Note['id'];
|
||||
|
||||
@OneToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
public note: Note | null;
|
||||
|
||||
@Column('timestamp with time zone')
|
||||
public expiresAt: Date;
|
||||
|
||||
//#region Denormalized fields
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
comment: '[Denormalized]',
|
||||
})
|
||||
public userId: User['id'];
|
||||
//#endregion
|
||||
}
|
35
packages/backend/src/models/entities/promo-read.ts
Normal file
35
packages/backend/src/models/entities/promo-read.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { id } from '../id.js';
|
||||
import { Note } from './note.js';
|
||||
import { User } from './user.js';
|
||||
|
||||
@Entity()
|
||||
@Index(['userId', 'noteId'], { unique: true })
|
||||
export class PromoRead {
|
||||
@PrimaryColumn(id())
|
||||
public id: string;
|
||||
|
||||
@Column('timestamp with time zone', {
|
||||
comment: 'The created date of the PromoRead.',
|
||||
})
|
||||
public createdAt: Date;
|
||||
|
||||
@Index()
|
||||
@Column(id())
|
||||
public userId: User['id'];
|
||||
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
public user: User | null;
|
||||
|
||||
@Column(id())
|
||||
public noteId: Note['id'];
|
||||
|
||||
@ManyToOne(type => Note, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
public note: Note | null;
|
||||
}
|
|
@ -49,6 +49,8 @@ import { ClipRepository } from './repositories/clip.js';
|
|||
import { ClipNote } from './entities/clip-note.js';
|
||||
import { AntennaRepository } from './repositories/antenna.js';
|
||||
import { AntennaNote } from './entities/antenna-note.js';
|
||||
import { PromoNote } from './entities/promo-note.js';
|
||||
import { PromoRead } from './entities/promo-read.js';
|
||||
import { EmojiRepository } from './repositories/emoji.js';
|
||||
import { RelayRepository } from './repositories/relay.js';
|
||||
import { ChannelRepository } from './repositories/channel.js';
|
||||
|
@ -113,6 +115,8 @@ export const Clips = (ClipRepository);
|
|||
export const ClipNotes = db.getRepository(ClipNote);
|
||||
export const Antennas = (AntennaRepository);
|
||||
export const AntennaNotes = db.getRepository(AntennaNote);
|
||||
export const PromoNotes = db.getRepository(PromoNote);
|
||||
export const PromoReads = db.getRepository(PromoRead);
|
||||
export const Relays = (RelayRepository);
|
||||
export const MutedNotes = db.getRepository(MutedNote);
|
||||
export const Channels = (ChannelRepository);
|
||||
|
|
|
@ -2,6 +2,7 @@ import { db } from '@/db/postgre.js';
|
|||
import { Page } from '@/models/entities/page.js';
|
||||
import { Packed } from '@/misc/schema.js';
|
||||
import { awaitAll } from '@/prelude/await-all.js';
|
||||
import { DriveFile } from '@/models/entities/drive-file.js';
|
||||
import { User } from '@/models/entities/user.js';
|
||||
import { Users, DriveFiles, PageLikes } from '../index.js';
|
||||
|
||||
|
@ -13,21 +14,66 @@ export const PageRepository = db.getRepository(Page).extend({
|
|||
const meId = me ? me.id : null;
|
||||
const page = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src });
|
||||
|
||||
const attachedFiles: Promise<DriveFile | null>[] = [];
|
||||
const collectFile = (xs: any[]) => {
|
||||
for (const x of xs) {
|
||||
if (x.type === 'image') {
|
||||
attachedFiles.push(DriveFiles.findOneBy({
|
||||
id: x.fileId,
|
||||
userId: page.userId,
|
||||
}));
|
||||
}
|
||||
if (x.children) {
|
||||
collectFile(x.children);
|
||||
}
|
||||
}
|
||||
};
|
||||
collectFile(page.content);
|
||||
|
||||
// 後方互換性のため
|
||||
let migrated = false;
|
||||
const migrate = (xs: any[]) => {
|
||||
for (const x of xs) {
|
||||
if (x.type === 'input') {
|
||||
if (x.inputType === 'text') {
|
||||
x.type = 'textInput';
|
||||
}
|
||||
if (x.inputType === 'number') {
|
||||
x.type = 'numberInput';
|
||||
if (x.default) x.default = parseInt(x.default, 10);
|
||||
}
|
||||
migrated = true;
|
||||
}
|
||||
if (x.children) {
|
||||
migrate(x.children);
|
||||
}
|
||||
}
|
||||
};
|
||||
migrate(page.content);
|
||||
if (migrated) {
|
||||
this.update(page.id, {
|
||||
content: page.content,
|
||||
});
|
||||
}
|
||||
|
||||
return await awaitAll({
|
||||
id: page.id,
|
||||
createdAt: page.createdAt.toISOString(),
|
||||
updatedAt: page.updatedAt.toISOString(),
|
||||
userId: page.userId,
|
||||
user: Users.pack(page.user || page.userId, me), // { detail: true } すると無限ループするので注意
|
||||
text: page.text,
|
||||
content: page.content,
|
||||
variables: page.variables,
|
||||
title: page.title,
|
||||
name: page.name,
|
||||
summary: page.summary,
|
||||
hideTitleWhenPinned: page.hideTitleWhenPinned,
|
||||
alignCenter: page.alignCenter,
|
||||
font: page.font,
|
||||
script: page.script,
|
||||
eyeCatchingImageId: page.eyeCatchingImageId,
|
||||
eyeCatchingImage: page.eyeCatchingImageId ? await DriveFiles.pack(page.eyeCatchingImageId) : null,
|
||||
attachedFiles: DriveFiles.packMany((await Promise.all(attachedFiles)).filter((x): x is DriveFile => x != null)),
|
||||
likedCount: page.likedCount,
|
||||
isLiked: meId ? await PageLikes.findOneBy({ pageId: page.id, userId: meId }).then(x => x != null) : undefined,
|
||||
});
|
||||
|
|
|
@ -29,8 +29,12 @@ export const packedPageSchema = {
|
|||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
text: {
|
||||
type: 'string',
|
||||
content: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
variables: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
userId: {
|
||||
|
|
|
@ -25,7 +25,7 @@ const router = new Router();
|
|||
|
||||
//#region Routing
|
||||
|
||||
function inbox(ctx: Router.RouterContext) {
|
||||
function inbox(ctx: Router.RouterContext): void {
|
||||
let signature;
|
||||
|
||||
try {
|
||||
|
@ -43,13 +43,13 @@ function inbox(ctx: Router.RouterContext) {
|
|||
const ACTIVITY_JSON = 'application/activity+json; charset=utf-8';
|
||||
const LD_JSON = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"; charset=utf-8';
|
||||
|
||||
function isActivityPubReq(ctx: Router.RouterContext) {
|
||||
function isActivityPubReq(ctx: Router.RouterContext): boolean {
|
||||
ctx.response.vary('Accept');
|
||||
const accepted = ctx.accepts('html', ACTIVITY_JSON, LD_JSON);
|
||||
return typeof accepted === 'string' && !accepted.match(/html/);
|
||||
}
|
||||
|
||||
export function setResponseType(ctx: Router.RouterContext) {
|
||||
export function setResponseType(ctx: Router.RouterContext): void {
|
||||
const accept = ctx.accepts(ACTIVITY_JSON, LD_JSON);
|
||||
if (accept === LD_JSON) {
|
||||
ctx.response.type = LD_JSON;
|
||||
|
@ -77,13 +77,9 @@ router.get('/notes/:note', async (ctx, next) => {
|
|||
return;
|
||||
}
|
||||
|
||||
// リモートだったらリダイレクト
|
||||
if (note.userHost != null) {
|
||||
if (note.uri == null || isSelfHost(note.userHost)) {
|
||||
ctx.status = 500;
|
||||
return;
|
||||
}
|
||||
ctx.redirect(note.uri);
|
||||
if (!isSelfHost(note.userHost)) {
|
||||
if (note.uri != null) ctx.redirect(note.uri);
|
||||
else ctx.status = 500;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -132,24 +128,19 @@ router.get('/users/:user/publickey', async ctx => {
|
|||
host: IsNull(),
|
||||
});
|
||||
|
||||
if (user == null) {
|
||||
if (user == null || !Users.isLocalUser(user)) {
|
||||
ctx.status = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
const keypair = await getUserKeypair(user.id);
|
||||
|
||||
if (Users.isLocalUser(user)) {
|
||||
ctx.body = renderActivity(renderKey(user, keypair));
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
setResponseType(ctx);
|
||||
} else {
|
||||
ctx.status = 400;
|
||||
}
|
||||
ctx.body = renderActivity(renderKey(user, keypair));
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
setResponseType(ctx);
|
||||
});
|
||||
|
||||
// user
|
||||
async function userInfo(ctx: Router.RouterContext, user: User | null) {
|
||||
async function userInfo(ctx: Router.RouterContext, user: User | null): void {
|
||||
if (user == null) {
|
||||
ctx.status = 404;
|
||||
return;
|
||||
|
|
34
packages/backend/src/server/api/common/inject-promo.ts
Normal file
34
packages/backend/src/server/api/common/inject-promo.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import rndstr from 'rndstr';
|
||||
import { Note } from '@/models/entities/note.js';
|
||||
import { User } from '@/models/entities/user.js';
|
||||
import { PromoReads, PromoNotes, Notes, Users } from '@/models/index.js';
|
||||
|
||||
export async function injectPromo(timeline: Note[], user?: User | null) {
|
||||
if (timeline.length < 5) return;
|
||||
|
||||
// TODO: readやexpireフィルタはクエリ側でやる
|
||||
|
||||
const reads = user ? await PromoReads.findBy({
|
||||
userId: user.id,
|
||||
}) : [];
|
||||
|
||||
let promos = await PromoNotes.find();
|
||||
|
||||
promos = promos.filter(n => n.expiresAt.getTime() > Date.now());
|
||||
promos = promos.filter(n => !reads.map(r => r.noteId).includes(n.noteId));
|
||||
|
||||
if (promos.length === 0) return;
|
||||
|
||||
// Pick random promo
|
||||
const promo = promos[Math.floor(Math.random() * promos.length)];
|
||||
|
||||
const note = await Notes.findOneByOrFail({ id: promo.noteId });
|
||||
|
||||
// Join
|
||||
note.user = await Users.findOneByOrFail({ id: note.userId });
|
||||
|
||||
(note as any)._prId_ = rndstr('a-z0-9', 8);
|
||||
|
||||
// Inject promo
|
||||
timeline.splice(3, 0, note);
|
||||
}
|
|
@ -33,6 +33,7 @@ import * as ep___admin_getTableStats from './endpoints/admin/get-table-stats.js'
|
|||
import * as ep___admin_invite from './endpoints/admin/invite.js';
|
||||
import * as ep___admin_moderators_add from './endpoints/admin/moderators/add.js';
|
||||
import * as ep___admin_moderators_remove from './endpoints/admin/moderators/remove.js';
|
||||
import * as ep___admin_promo_create from './endpoints/admin/promo/create.js';
|
||||
import * as ep___admin_queue_clear from './endpoints/admin/queue/clear.js';
|
||||
import * as ep___admin_queue_deliverDelayed from './endpoints/admin/queue/deliver-delayed.js';
|
||||
import * as ep___admin_queue_inboxDelayed from './endpoints/admin/queue/inbox-delayed.js';
|
||||
|
@ -260,6 +261,7 @@ import * as ep___pages_unlike from './endpoints/pages/unlike.js';
|
|||
import * as ep___pages_update from './endpoints/pages/update.js';
|
||||
import * as ep___ping from './endpoints/ping.js';
|
||||
import * as ep___pinnedUsers from './endpoints/pinned-users.js';
|
||||
import * as ep___promo_read from './endpoints/promo/read.js';
|
||||
import * as ep___requestResetPassword from './endpoints/request-reset-password.js';
|
||||
import * as ep___resetDb from './endpoints/reset-db.js';
|
||||
import * as ep___resetPassword from './endpoints/reset-password.js';
|
||||
|
@ -340,6 +342,7 @@ const eps = [
|
|||
['admin/invite', ep___admin_invite],
|
||||
['admin/moderators/add', ep___admin_moderators_add],
|
||||
['admin/moderators/remove', ep___admin_moderators_remove],
|
||||
['admin/promo/create', ep___admin_promo_create],
|
||||
['admin/queue/clear', ep___admin_queue_clear],
|
||||
['admin/queue/deliver-delayed', ep___admin_queue_deliverDelayed],
|
||||
['admin/queue/inbox-delayed', ep___admin_queue_inboxDelayed],
|
||||
|
@ -567,6 +570,7 @@ const eps = [
|
|||
['pages/update', ep___pages_update],
|
||||
['ping', ep___ping],
|
||||
['pinned-users', ep___pinnedUsers],
|
||||
['promo/read', ep___promo_read],
|
||||
['request-reset-password', ep___requestResetPassword],
|
||||
['reset-db', ep___resetDb],
|
||||
['reset-password', ep___resetPassword],
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
import { PromoNotes } from '@/models/index.js';
|
||||
import define from '../../../define.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
import { getNote } from '../../../common/getters.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
errors: {
|
||||
noSuchNote: {
|
||||
message: 'No such note.',
|
||||
code: 'NO_SUCH_NOTE',
|
||||
id: 'ee449fbe-af2a-453b-9cae-cf2fe7c895fc',
|
||||
},
|
||||
|
||||
alreadyPromoted: {
|
||||
message: 'The note has already promoted.',
|
||||
code: 'ALREADY_PROMOTED',
|
||||
id: 'ae427aa2-7a41-484f-a18c-2c1104051604',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
noteId: { type: 'string', format: 'misskey:id' },
|
||||
expiresAt: { type: 'integer' },
|
||||
},
|
||||
required: ['noteId', 'expiresAt'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const note = await getNote(ps.noteId, user).catch(err => {
|
||||
if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
|
||||
throw err;
|
||||
});
|
||||
|
||||
const exist = await PromoNotes.findOneBy({ noteId: note.id });
|
||||
|
||||
if (exist != null) {
|
||||
throw new ApiError(meta.errors.alreadyPromoted);
|
||||
}
|
||||
|
||||
await PromoNotes.insert({
|
||||
noteId: note.id,
|
||||
expiresAt: new Date(ps.expiresAt),
|
||||
userId: note.userId,
|
||||
});
|
||||
});
|
|
@ -43,13 +43,19 @@ export const paramDef = {
|
|||
title: { type: 'string' },
|
||||
name: { type: 'string', minLength: 1 },
|
||||
summary: { type: 'string', nullable: true },
|
||||
text: { type: 'string', minLength: 1 },
|
||||
content: { type: 'array', items: {
|
||||
type: 'object', additionalProperties: true,
|
||||
} },
|
||||
variables: { type: 'array', items: {
|
||||
type: 'object', additionalProperties: true,
|
||||
} },
|
||||
script: { type: 'string' },
|
||||
eyeCatchingImageId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||
font: { type: 'string', enum: ['serif', 'sans-serif'], default: 'sans-serif' },
|
||||
alignCenter: { type: 'boolean', default: false },
|
||||
hideTitleWhenPinned: { type: 'boolean', default: false },
|
||||
},
|
||||
required: ['title', 'name', 'text'],
|
||||
required: ['title', 'name', 'content', 'variables', 'script'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
|
@ -82,7 +88,9 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
title: ps.title,
|
||||
name: ps.name,
|
||||
summary: ps.summary,
|
||||
text: ps.text,
|
||||
content: ps.content,
|
||||
variables: ps.variables,
|
||||
script: ps.script,
|
||||
eyeCatchingImageId: eyeCatchingImage ? eyeCatchingImage.id : null,
|
||||
userId: user.id,
|
||||
visibility: 'public',
|
||||
|
|
|
@ -49,13 +49,19 @@ export const paramDef = {
|
|||
title: { type: 'string' },
|
||||
name: { type: 'string', minLength: 1 },
|
||||
summary: { type: 'string', nullable: true },
|
||||
text: { type: 'string', minLength: 1 },
|
||||
content: { type: 'array', items: {
|
||||
type: 'object', additionalProperties: true,
|
||||
} },
|
||||
variables: { type: 'array', items: {
|
||||
type: 'object', additionalProperties: true,
|
||||
} },
|
||||
script: { type: 'string' },
|
||||
eyeCatchingImageId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||
font: { type: 'string', enum: ['serif', 'sans-serif'] },
|
||||
alignCenter: { type: 'boolean' },
|
||||
hideTitleWhenPinned: { type: 'boolean' },
|
||||
},
|
||||
required: ['pageId', 'title', 'name', 'text'],
|
||||
required: ['pageId', 'title', 'name', 'content', 'variables', 'script'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
|
@ -95,7 +101,9 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
title: ps.title,
|
||||
name: ps.name === undefined ? page.name : ps.name,
|
||||
summary: ps.name === undefined ? page.summary : ps.summary,
|
||||
text: ps.text,
|
||||
content: ps.content,
|
||||
variables: ps.variables,
|
||||
script: ps.script,
|
||||
alignCenter: ps.alignCenter === undefined ? page.alignCenter : ps.alignCenter,
|
||||
hideTitleWhenPinned: ps.hideTitleWhenPinned === undefined ? page.hideTitleWhenPinned : ps.hideTitleWhenPinned,
|
||||
font: ps.font === undefined ? page.font : ps.font,
|
||||
|
|
51
packages/backend/src/server/api/endpoints/promo/read.ts
Normal file
51
packages/backend/src/server/api/endpoints/promo/read.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { PromoReads } from '@/models/index.js';
|
||||
import { genId } from '@/misc/gen-id.js';
|
||||
import define from '../../define.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
import { getNote } from '../../common/getters.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['notes'],
|
||||
|
||||
requireCredential: true,
|
||||
|
||||
errors: {
|
||||
noSuchNote: {
|
||||
message: 'No such note.',
|
||||
code: 'NO_SUCH_NOTE',
|
||||
id: 'd785b897-fcd3-4fe9-8fc3-b85c26e6c932',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
noteId: { type: 'string', format: 'misskey:id' },
|
||||
},
|
||||
required: ['noteId'],
|
||||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const note = await getNote(ps.noteId, user).catch(err => {
|
||||
if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
|
||||
throw err;
|
||||
});
|
||||
|
||||
const exist = await PromoReads.findOneBy({
|
||||
noteId: note.id,
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
if (exist != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
await PromoReads.insert({
|
||||
id: genId(),
|
||||
createdAt: new Date(),
|
||||
noteId: note.id,
|
||||
userId: user.id,
|
||||
});
|
||||
});
|
|
@ -1486,12 +1486,13 @@ bull@4.8.4:
|
|||
semver "^7.3.2"
|
||||
uuid "^8.3.0"
|
||||
|
||||
busboy@^1.0.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
|
||||
integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
|
||||
busboy@^0.2.11:
|
||||
version "0.2.14"
|
||||
resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453"
|
||||
integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=
|
||||
dependencies:
|
||||
streamsearch "^1.1.0"
|
||||
dicer "0.2.5"
|
||||
readable-stream "1.1.x"
|
||||
|
||||
bytes@3.1.0, bytes@^3.1.0:
|
||||
version "3.1.0"
|
||||
|
@ -2236,6 +2237,14 @@ detect-libc@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.0.tgz#c528bc09bc6d1aa30149228240917c225448f204"
|
||||
integrity sha512-S55LzUl8HUav8l9E2PBTlC5PAJrHK7tkM+XXFGD+fbsbkTzhCpG6K05LxJcUOEWzMa4v6ptcMZ9s3fOdJDu0Zw==
|
||||
|
||||
dicer@0.2.5:
|
||||
version "0.2.5"
|
||||
resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f"
|
||||
integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=
|
||||
dependencies:
|
||||
readable-stream "1.1.x"
|
||||
streamsearch "0.1.2"
|
||||
|
||||
diff@5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
|
||||
|
@ -3543,7 +3552,7 @@ inflight@^1.0.4:
|
|||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3:
|
||||
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
@ -3852,6 +3861,11 @@ is-whitespace@^0.3.0:
|
|||
resolved "https://registry.yarnpkg.com/is-whitespace/-/is-whitespace-0.3.0.tgz#1639ecb1be036aec69a54cbb401cfbed7114ab7f"
|
||||
integrity sha1-Fjnssb4DauxppUy7QBz77XEUq38=
|
||||
|
||||
isarray@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
|
||||
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
|
||||
|
||||
isarray@^1.0.0, isarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
|
@ -4751,16 +4765,17 @@ msgpackr@^1.5.2:
|
|||
optionalDependencies:
|
||||
msgpackr-extract "^1.0.14"
|
||||
|
||||
multer@1.4.5-lts.1:
|
||||
version "1.4.5-lts.1"
|
||||
resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.5-lts.1.tgz#803e24ad1984f58edffbc79f56e305aec5cfd1ac"
|
||||
integrity sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==
|
||||
multer@1.4.4:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.4.tgz#e2bc6cac0df57a8832b858d7418ccaa8ebaf7d8c"
|
||||
integrity sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==
|
||||
dependencies:
|
||||
append-field "^1.0.0"
|
||||
busboy "^1.0.0"
|
||||
busboy "^0.2.11"
|
||||
concat-stream "^1.5.2"
|
||||
mkdirp "^0.5.4"
|
||||
object-assign "^4.1.1"
|
||||
on-finished "^2.3.0"
|
||||
type-is "^1.6.4"
|
||||
xtend "^4.0.0"
|
||||
|
||||
|
@ -5756,6 +5771,16 @@ re2@1.17.7:
|
|||
nan "^2.16.0"
|
||||
node-gyp "^9.0.0"
|
||||
|
||||
readable-stream@1.1.x:
|
||||
version "1.1.14"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
|
||||
integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk=
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.1"
|
||||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@~2.3.6:
|
||||
version "2.3.7"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
|
||||
|
@ -6278,10 +6303,10 @@ stream-parser@~0.3.1:
|
|||
dependencies:
|
||||
debug "2"
|
||||
|
||||
streamsearch@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
|
||||
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
|
||||
streamsearch@0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
|
||||
integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
|
||||
|
||||
strict-event-emitter-types@2.0.0:
|
||||
version "2.0.0"
|
||||
|
@ -6346,6 +6371,11 @@ string_decoder@^1.1.1:
|
|||
dependencies:
|
||||
safe-buffer "~5.2.0"
|
||||
|
||||
string_decoder@~0.10.x:
|
||||
version "0.10.31"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
|
||||
integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
|
||||
|
||||
string_decoder@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
>
|
||||
<MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" class="reply-to"/>
|
||||
<div v-if="pinned" class="info"><i class="fas fa-thumbtack"></i> {{ i18n.ts.pinnedNote }}</div>
|
||||
<div v-if="appearNote._prId_" class="info"><i class="fas fa-bullhorn"></i> {{ i18n.ts.promotion }}<button class="_textButton hide" @click="readPromo()">{{ i18n.ts.hideThisNote }} <i class="fas fa-times"></i></button></div>
|
||||
<div v-if="appearNote._featuredId_" class="info"><i class="fas fa-bolt"></i> {{ i18n.ts.featured }}</div>
|
||||
<div v-if="isRenote" class="renote">
|
||||
<MkAvatar class="avatar" :user="note.user"/>
|
||||
|
@ -280,6 +281,13 @@ function focusBefore() {
|
|||
function focusAfter() {
|
||||
focusNext(el.value);
|
||||
}
|
||||
|
||||
function readPromo() {
|
||||
os.api('promo/read', {
|
||||
noteId: appearNote.id,
|
||||
});
|
||||
isDeleted.value = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<template #default="{ items: notes }">
|
||||
<div class="giivymft" :class="{ noGap }">
|
||||
<XList ref="notes" v-slot="{ item: note }" :items="notes" :direction="pagination.reversed ? 'up' : 'down'" :reversed="pagination.reversed" :no-gap="noGap" class="notes">
|
||||
<XNote :key="note._featuredId_ || note.id" class="qtqtichx" :note="note"/>
|
||||
<XNote :key="note._featuredId_ || note._prId_ || note.id" class="qtqtichx" :note="note"/>
|
||||
</XList>
|
||||
</div>
|
||||
</template>
|
||||
|
|
44
packages/client/src/components/page/page.block.vue
Normal file
44
packages/client/src/components/page/page.block.vue
Normal file
|
@ -0,0 +1,44 @@
|
|||
<template>
|
||||
<component :is="'x-' + block.type" :key="block.id" :block="block" :hpml="hpml" :h="h"/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import XText from './page.text.vue';
|
||||
import XSection from './page.section.vue';
|
||||
import XImage from './page.image.vue';
|
||||
import XButton from './page.button.vue';
|
||||
import XNumberInput from './page.number-input.vue';
|
||||
import XTextInput from './page.text-input.vue';
|
||||
import XTextareaInput from './page.textarea-input.vue';
|
||||
import XSwitch from './page.switch.vue';
|
||||
import XIf from './page.if.vue';
|
||||
import XTextarea from './page.textarea.vue';
|
||||
import XPost from './page.post.vue';
|
||||
import XCounter from './page.counter.vue';
|
||||
import XRadioButton from './page.radio-button.vue';
|
||||
import XCanvas from './page.canvas.vue';
|
||||
import XNote from './page.note.vue';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { Block } from '@/scripts/hpml/block';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XText, XSection, XImage, XButton, XNumberInput, XTextInput, XTextareaInput, XTextarea, XPost, XSwitch, XIf, XCounter, XRadioButton, XCanvas, XNote,
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<Block>,
|
||||
required: true,
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true,
|
||||
},
|
||||
h: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
66
packages/client/src/components/page/page.button.vue
Normal file
66
packages/client/src/components/page/page.button.vue
Normal file
|
@ -0,0 +1,66 @@
|
|||
<template>
|
||||
<div>
|
||||
<MkButton class="kudkigyw" :primary="block.primary" @click="click()">{{ hpml.interpolate(block.text) }}</MkButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, unref } from 'vue';
|
||||
import MkButton from '../ui/button.vue';
|
||||
import * as os from '@/os';
|
||||
import { ButtonBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkButton,
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<ButtonBlock>,
|
||||
required: true,
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
click() {
|
||||
if (this.block.action === 'dialog') {
|
||||
this.hpml.eval();
|
||||
os.alert({
|
||||
text: this.hpml.interpolate(this.block.content),
|
||||
});
|
||||
} else if (this.block.action === 'resetRandom') {
|
||||
this.hpml.updateRandomSeed(Math.random());
|
||||
this.hpml.eval();
|
||||
} else if (this.block.action === 'pushEvent') {
|
||||
os.api('page-push', {
|
||||
pageId: this.hpml.page.id,
|
||||
event: this.block.event,
|
||||
...(this.block.var ? {
|
||||
var: unref(this.hpml.vars)[this.block.var],
|
||||
} : {}),
|
||||
});
|
||||
|
||||
os.alert({
|
||||
type: 'success',
|
||||
text: this.hpml.interpolate(this.block.message),
|
||||
});
|
||||
} else if (this.block.action === 'callAiScript') {
|
||||
this.hpml.callAiScript(this.block.fn);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.kudkigyw {
|
||||
display: inline-block;
|
||||
min-width: 200px;
|
||||
max-width: 450px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
</style>
|
49
packages/client/src/components/page/page.canvas.vue
Normal file
49
packages/client/src/components/page/page.canvas.vue
Normal file
|
@ -0,0 +1,49 @@
|
|||
<template>
|
||||
<div class="ysrxegms">
|
||||
<canvas ref="canvas" :width="block.width" :height="block.height"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, PropType, Ref, ref } from 'vue';
|
||||
import * as os from '@/os';
|
||||
import { CanvasBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<CanvasBlock>,
|
||||
required: true,
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const canvas: Ref<any> = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
props.hpml.registerCanvas(props.block.name, canvas.value);
|
||||
});
|
||||
|
||||
return {
|
||||
canvas,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ysrxegms {
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
overflow: auto;
|
||||
max-width: 100%;
|
||||
|
||||
> canvas {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
</style>
|
52
packages/client/src/components/page/page.counter.vue
Normal file
52
packages/client/src/components/page/page.counter.vue
Normal file
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<div>
|
||||
<MkButton class="llumlmnx" @click="click()">{{ hpml.interpolate(block.text) }}</MkButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import MkButton from '../ui/button.vue';
|
||||
import * as os from '@/os';
|
||||
import { CounterVarBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkButton,
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<CounterVarBlock>,
|
||||
required: true,
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const value = computed(() => {
|
||||
return props.hpml.vars.value[props.block.name];
|
||||
});
|
||||
|
||||
function click() {
|
||||
props.hpml.updatePageVar(props.block.name, value.value + (props.block.inc || 1));
|
||||
props.hpml.eval();
|
||||
}
|
||||
|
||||
return {
|
||||
click,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.llumlmnx {
|
||||
display: inline-block;
|
||||
min-width: 300px;
|
||||
max-width: 450px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
</style>
|
31
packages/client/src/components/page/page.if.vue
Normal file
31
packages/client/src/components/page/page.if.vue
Normal file
|
@ -0,0 +1,31 @@
|
|||
<template>
|
||||
<div v-show="hpml.vars.value[block.var]">
|
||||
<XBlock v-for="child in block.children" :key="child.id" :block="child" :hpml="hpml" :h="h"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, defineAsyncComponent, PropType } from 'vue';
|
||||
import { IfBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XBlock: defineAsyncComponent(() => import('./page.block.vue')),
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<IfBlock>,
|
||||
required: true,
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true,
|
||||
},
|
||||
h: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
28
packages/client/src/components/page/page.image.vue
Normal file
28
packages/client/src/components/page/page.image.vue
Normal file
|
@ -0,0 +1,28 @@
|
|||
<template>
|
||||
<div class="lzyxtsnt">
|
||||
<ImgWithBlurhash v-if="image" :hash="image.blurhash" :src="image.url" :alt="image.comment" :title="image.comment" :cover="false"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import ImgWithBlurhash from '@/components/img-with-blurhash.vue';
|
||||
import * as os from '@/os';
|
||||
import { ImageBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
|
||||
const props = defineProps<{
|
||||
block: PropType<ImageBlock>,
|
||||
hpml: PropType<Hpml>,
|
||||
}>();
|
||||
|
||||
const image = props.hpml.page.attachedFiles.find(x => x.id === props.block.fileId);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lzyxtsnt {
|
||||
> img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
47
packages/client/src/components/page/page.note.vue
Normal file
47
packages/client/src/components/page/page.note.vue
Normal file
|
@ -0,0 +1,47 @@
|
|||
<template>
|
||||
<div class="voxdxuby">
|
||||
<XNote v-if="note && !block.detailed" :key="note.id + ':normal'" v-model:note="note"/>
|
||||
<XNoteDetailed v-if="note && block.detailed" :key="note.id + ':detail'" v-model:note="note"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, PropType, Ref, ref } from 'vue';
|
||||
import XNote from '@/components/note.vue';
|
||||
import XNoteDetailed from '@/components/note-detailed.vue';
|
||||
import * as os from '@/os';
|
||||
import { NoteBlock } from '@/scripts/hpml/block';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XNote,
|
||||
XNoteDetailed,
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<NoteBlock>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const note: Ref<Record<string, any> | null> = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
os.api('notes/show', { noteId: props.block.note })
|
||||
.then(result => {
|
||||
note.value = result;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
note,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.voxdxuby {
|
||||
margin: 1em 0;
|
||||
}
|
||||
</style>
|
55
packages/client/src/components/page/page.number-input.vue
Normal file
55
packages/client/src/components/page/page.number-input.vue
Normal file
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<div>
|
||||
<MkInput class="kudkigyw" :model-value="value" type="number" @update:modelValue="updateValue($event)">
|
||||
<template #label>{{ hpml.interpolate(block.text) }}</template>
|
||||
</MkInput>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import MkInput from '../form/input.vue';
|
||||
import * as os from '@/os';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { NumberInputVarBlock } from '@/scripts/hpml/block';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkInput,
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<NumberInputVarBlock>,
|
||||
required: true,
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const value = computed(() => {
|
||||
return props.hpml.vars.value[props.block.name];
|
||||
});
|
||||
|
||||
function updateValue(newValue) {
|
||||
props.hpml.updatePageVar(props.block.name, newValue);
|
||||
props.hpml.eval();
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
updateValue,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.kudkigyw {
|
||||
display: inline-block;
|
||||
min-width: 300px;
|
||||
max-width: 450px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
</style>
|
111
packages/client/src/components/page/page.post.vue
Normal file
111
packages/client/src/components/page/page.post.vue
Normal file
|
@ -0,0 +1,111 @@
|
|||
<template>
|
||||
<div class="ngbfujlo">
|
||||
<MkTextarea :model-value="text" readonly style="margin: 0;"></MkTextarea>
|
||||
<MkButton class="button" primary :disabled="posting || posted" @click="post()">
|
||||
<i v-if="posted" class="fas fa-check"></i>
|
||||
<i v-else class="fas fa-paper-plane"></i>
|
||||
</MkButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import MkTextarea from '../form/textarea.vue';
|
||||
import MkButton from '../ui/button.vue';
|
||||
import { apiUrl } from '@/config';
|
||||
import * as os from '@/os';
|
||||
import { PostBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkTextarea,
|
||||
MkButton,
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<PostBlock>,
|
||||
required: true,
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
text: this.hpml.interpolate(this.block.text),
|
||||
posted: false,
|
||||
posting: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
'hpml.vars': {
|
||||
handler() {
|
||||
this.text = this.hpml.interpolate(this.block.text);
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
upload() {
|
||||
const promise = new Promise((ok) => {
|
||||
const canvas = this.hpml.canvases[this.block.canvasId];
|
||||
canvas.toBlob(blob => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', blob);
|
||||
if (this.$store.state.uploadFolder) {
|
||||
formData.append('folderId', this.$store.state.uploadFolder);
|
||||
}
|
||||
|
||||
fetch(apiUrl + '/drive/files/create', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
authorization: `Bearer ${this.$i.token}`,
|
||||
},
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(f => {
|
||||
ok(f);
|
||||
});
|
||||
});
|
||||
});
|
||||
os.promiseDialog(promise);
|
||||
return promise;
|
||||
},
|
||||
async post() {
|
||||
this.posting = true;
|
||||
const file = this.block.attachCanvasImage ? await this.upload() : null;
|
||||
os.apiWithDialog('notes/create', {
|
||||
text: this.text === '' ? null : this.text,
|
||||
fileIds: file ? [file.id] : undefined,
|
||||
}).then(() => {
|
||||
this.posted = true;
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ngbfujlo {
|
||||
position: relative;
|
||||
padding: 32px;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 8px var(--shadow);
|
||||
z-index: 1;
|
||||
|
||||
> .button {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
padding: 16px;
|
||||
|
||||
> .button {
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
45
packages/client/src/components/page/page.radio-button.vue
Normal file
45
packages/client/src/components/page/page.radio-button.vue
Normal file
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>{{ hpml.interpolate(block.title) }}</div>
|
||||
<MkRadio v-for="item in block.values" :key="item" :model-value="value" :value="item" @update:modelValue="updateValue($event)">{{ item }}</MkRadio>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import MkRadio from '../form/radio.vue';
|
||||
import * as os from '@/os';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { RadioButtonVarBlock } from '@/scripts/hpml/block';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkRadio,
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<RadioButtonVarBlock>,
|
||||
required: true,
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const value = computed(() => {
|
||||
return props.hpml.vars.value[props.block.name];
|
||||
});
|
||||
|
||||
function updateValue(newValue: string) {
|
||||
props.hpml.updatePageVar(props.block.name, newValue);
|
||||
props.hpml.eval();
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
updateValue,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
60
packages/client/src/components/page/page.section.vue
Normal file
60
packages/client/src/components/page/page.section.vue
Normal file
|
@ -0,0 +1,60 @@
|
|||
<template>
|
||||
<section class="sdgxphyu">
|
||||
<component :is="'h' + h">{{ block.title }}</component>
|
||||
|
||||
<div class="children">
|
||||
<XBlock v-for="child in block.children" :key="child.id" :block="child" :hpml="hpml" :h="h + 1"/>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, defineAsyncComponent, PropType } from 'vue';
|
||||
import * as os from '@/os';
|
||||
import { SectionBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XBlock: defineAsyncComponent(() => import('./page.block.vue')),
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<SectionBlock>,
|
||||
required: true,
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true,
|
||||
},
|
||||
h: {
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sdgxphyu {
|
||||
margin: 1.5em 0;
|
||||
|
||||
> h2 {
|
||||
font-size: 1.35em;
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
> h3 {
|
||||
font-size: 1em;
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
> h4 {
|
||||
font-size: 1em;
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
> .children {
|
||||
//padding 16px
|
||||
}
|
||||
}
|
||||
</style>
|
55
packages/client/src/components/page/page.switch.vue
Normal file
55
packages/client/src/components/page/page.switch.vue
Normal file
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<div class="hkcxmtwj">
|
||||
<MkSwitch :model-value="value" @update:modelValue="updateValue($event)">{{ hpml.interpolate(block.text) }}</MkSwitch>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import MkSwitch from '../form/switch.vue';
|
||||
import * as os from '@/os';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { SwitchVarBlock } from '@/scripts/hpml/block';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkSwitch,
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<SwitchVarBlock>,
|
||||
required: true,
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const value = computed(() => {
|
||||
return props.hpml.vars.value[props.block.name];
|
||||
});
|
||||
|
||||
function updateValue(newValue: boolean) {
|
||||
props.hpml.updatePageVar(props.block.name, newValue);
|
||||
props.hpml.eval();
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
updateValue,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.hkcxmtwj {
|
||||
display: inline-block;
|
||||
margin: 16px auto;
|
||||
|
||||
& + .hkcxmtwj {
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
55
packages/client/src/components/page/page.text-input.vue
Normal file
55
packages/client/src/components/page/page.text-input.vue
Normal file
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<div>
|
||||
<MkInput class="kudkigyw" :model-value="value" type="text" @update:modelValue="updateValue($event)">
|
||||
<template #label>{{ hpml.interpolate(block.text) }}</template>
|
||||
</MkInput>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import MkInput from '../form/input.vue';
|
||||
import * as os from '@/os';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { TextInputVarBlock } from '@/scripts/hpml/block';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkInput,
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<TextInputVarBlock>,
|
||||
required: true,
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const value = computed(() => {
|
||||
return props.hpml.vars.value[props.block.name];
|
||||
});
|
||||
|
||||
function updateValue(newValue) {
|
||||
props.hpml.updatePageVar(props.block.name, newValue);
|
||||
props.hpml.eval();
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
updateValue,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.kudkigyw {
|
||||
display: inline-block;
|
||||
min-width: 300px;
|
||||
max-width: 450px;
|
||||
margin: 8px 0;
|
||||
}
|
||||
</style>
|
54
packages/client/src/components/page/page.text.vue
Normal file
54
packages/client/src/components/page/page.text.vue
Normal file
|
@ -0,0 +1,54 @@
|
|||
<template>
|
||||
<div class="mrdgzndn">
|
||||
<Mfm :key="text" :text="text" :is-note="false"/>
|
||||
<MkUrlPreview v-for="url in urls" :key="url" :url="url" class="url"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, watch, computed } from 'vue';
|
||||
import * as mfm from 'mfm-js';
|
||||
import { TextBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm';
|
||||
|
||||
const props = defineProps<{
|
||||
block: TextBlock;
|
||||
hpml: Hpml;
|
||||
}>();
|
||||
|
||||
const MkUrlPreview = defineAsyncComponent(() => import('@/components/url-preview.vue'));
|
||||
|
||||
let text: string = $ref('');
|
||||
|
||||
const urls = computed((): string[] => {
|
||||
if (text) {
|
||||
return extractUrlFromMfm(mfm.parse(text));
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
watch(props.hpml.vars, () => {
|
||||
text = props.hpml.interpolate(props.block.text) as string;
|
||||
}, {
|
||||
deep: true,
|
||||
immediate: true,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mrdgzndn {
|
||||
&:not(:first-child) {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
> .url {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
}
|
||||
</style>
|
47
packages/client/src/components/page/page.textarea-input.vue
Normal file
47
packages/client/src/components/page/page.textarea-input.vue
Normal file
|
@ -0,0 +1,47 @@
|
|||
<template>
|
||||
<div>
|
||||
<MkTextarea :model-value="value" @update:modelValue="updateValue($event)">
|
||||
<template #label>{{ hpml.interpolate(block.text) }}</template>
|
||||
</MkTextarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import MkTextarea from '../form/textarea.vue';
|
||||
import * as os from '@/os';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { HpmlTextInput } from '@/scripts/hpml';
|
||||
import { TextInputVarBlock } from '@/scripts/hpml/block';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkTextarea,
|
||||
},
|
||||
props: {
|
||||
block: {
|
||||
type: Object as PropType<TextInputVarBlock>,
|
||||
required: true,
|
||||
},
|
||||
hpml: {
|
||||
type: Object as PropType<Hpml>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const value = computed(() => {
|
||||
return props.hpml.vars.value[props.block.name];
|
||||
});
|
||||
|
||||
function updateValue(newValue) {
|
||||
props.hpml.updatePageVar(props.block.name, newValue);
|
||||
props.hpml.eval();
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
updateValue,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
24
packages/client/src/components/page/page.textarea.vue
Normal file
24
packages/client/src/components/page/page.textarea.vue
Normal file
|
@ -0,0 +1,24 @@
|
|||
<template>
|
||||
<MkTextarea :model-value="text" readonly></MkTextarea>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch } from 'vue';
|
||||
import MkTextarea from '../form/textarea.vue';
|
||||
import { TextBlock } from '@/scripts/hpml/block';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
|
||||
const props = defineProps<{
|
||||
block: TextBlock;
|
||||
hpml: Hpml;
|
||||
}>();
|
||||
|
||||
let text = $ref('');
|
||||
|
||||
watch(props.hpml.vars, () => {
|
||||
text = props.hpml.interpolate(props.block.text) as string;
|
||||
}, {
|
||||
deep: true,
|
||||
immediate: true,
|
||||
});
|
||||
</script>
|
85
packages/client/src/components/page/page.vue
Normal file
85
packages/client/src/components/page/page.vue
Normal file
|
@ -0,0 +1,85 @@
|
|||
<template>
|
||||
<div v-if="hpml" class="iroscrza" :class="{ center: page.alignCenter, serif: page.font === 'serif' }">
|
||||
<XBlock v-for="child in page.content" :key="child.id" :block="child" :hpml="hpml" :h="2"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, nextTick, onUnmounted, PropType } from 'vue';
|
||||
import { parse } from '@syuilo/aiscript';
|
||||
import XBlock from './page.block.vue';
|
||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||
import { url } from '@/config';
|
||||
import { $i } from '@/account';
|
||||
import { defaultStore } from '@/store';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XBlock,
|
||||
},
|
||||
props: {
|
||||
page: {
|
||||
type: Object as PropType<Record<string, any>>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, ctx) {
|
||||
const hpml = new Hpml(props.page, {
|
||||
randomSeed: Math.random(),
|
||||
visitor: $i,
|
||||
url,
|
||||
enableAiScript: !defaultStore.state.disablePagesScript,
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
if (props.page.script && hpml.aiscript) {
|
||||
let ast;
|
||||
try {
|
||||
ast = parse(props.page.script);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
/*os.alert({
|
||||
type: 'error',
|
||||
text: 'Syntax error :('
|
||||
});*/
|
||||
return;
|
||||
}
|
||||
hpml.aiscript.exec(ast).then(() => {
|
||||
hpml.eval();
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
/*os.alert({
|
||||
type: 'error',
|
||||
text: err
|
||||
});*/
|
||||
});
|
||||
} else {
|
||||
hpml.eval();
|
||||
}
|
||||
});
|
||||
onUnmounted(() => {
|
||||
if (hpml.aiscript) hpml.aiscript.abort();
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
hpml,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.iroscrza {
|
||||
&.serif {
|
||||
> div {
|
||||
font-family: serif;
|
||||
}
|
||||
}
|
||||
|
||||
&.center {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -3,6 +3,9 @@
|
|||
<button class="disablePlayer" :title="i18n.ts.disablePlayer" @click="playerEnabled = false"><i class="fas fa-times"></i></button>
|
||||
<iframe :src="player.url + (player.url.match(/\?/) ? '&autoplay=1&auto_play=1' : '?autoplay=1&auto_play=1')" :width="player.width || '100%'" :heigth="player.height || 250" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen/>
|
||||
</div>
|
||||
<div v-else-if="tweetId && tweetExpanded" ref="twitter" class="twitter">
|
||||
<iframe ref="tweet" scrolling="no" frameborder="no" :style="{ position: 'relative', width: '100%', height: `${tweetHeight}px` }" :src="`https://platform.twitter.com/embed/index.html?embedId=${embedId}&hideCard=false&hideThread=false&lang=en&theme=${$store.state.darkMode ? 'dark' : 'light'}&id=${tweetId}`"></iframe>
|
||||
</div>
|
||||
<div v-else v-size="{ max: [400, 350] }" class="mk-url-preview">
|
||||
<transition :name="$store.state.animation ? 'zoom' : ''" mode="out-in">
|
||||
<component :is="self ? 'MkA' : 'a'" v-if="!fetching" :class="{ compact }" :[attr]="self ? url.substr(local.length) : url" rel="nofollow noopener" :target="target" :title="url">
|
||||
|
@ -21,10 +24,16 @@
|
|||
</article>
|
||||
</component>
|
||||
</transition>
|
||||
<div v-if="tweetId" class="expandTweet">
|
||||
<a @click="tweetExpanded = true">
|
||||
<i class="fab fa-twitter"></i> {{ i18n.ts.expandTweet }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onUnmounted } from 'vue';
|
||||
import { url as local, lang } from '@/config';
|
||||
import { i18n } from '@/i18n';
|
||||
|
||||
|
@ -52,14 +61,23 @@ let player = $ref({
|
|||
height: null,
|
||||
});
|
||||
let playerEnabled = $ref(false);
|
||||
let tweetId = $ref<string | null>(null);
|
||||
let tweetExpanded = $ref(props.detail);
|
||||
const embedId = `embed${Math.random().toString().replace(/\D/,'')}`;
|
||||
let tweetHeight = $ref(150);
|
||||
|
||||
const requestUrl = new URL(props.url);
|
||||
|
||||
if (requestUrl.hostname === 'twitter.com') {
|
||||
const m = requestUrl.pathname.match(/^\/.+\/status(?:es)?\/(\d+)/);
|
||||
if (m) tweetId = m[1];
|
||||
}
|
||||
|
||||
if (requestUrl.hostname === 'music.youtube.com' && requestUrl.pathname.match('^/(?:watch|channel)')) {
|
||||
requestUrl.hostname = 'www.youtube.com';
|
||||
}
|
||||
|
||||
const requestLang = lang || 'en-US';
|
||||
const requestLang = (lang || 'ja-JP').replace('ja-KS', 'ja-JP');
|
||||
|
||||
requestUrl.hash = '';
|
||||
|
||||
|
@ -75,6 +93,21 @@ fetch(`/url?url=${encodeURIComponent(requestUrl.href)}&lang=${requestLang}`).the
|
|||
player = info.player;
|
||||
});
|
||||
});
|
||||
|
||||
function adjustTweetHeight(message: any) {
|
||||
if (message.origin !== 'https://platform.twitter.com') return;
|
||||
const embed = message.data?.['twttr.embed'];
|
||||
if (embed?.method !== 'twttr.private.resize') return;
|
||||
if (embed?.id !== embedId) return;
|
||||
const height = embed?.params[0]?.height;
|
||||
if (height) tweetHeight = height;
|
||||
}
|
||||
|
||||
(window as any).addEventListener('message', adjustTweetHeight);
|
||||
|
||||
onUnmounted(() => {
|
||||
(window as any).removeEventListener('message', adjustTweetHeight);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -33,7 +33,7 @@ function calc(src: Element) {
|
|||
}
|
||||
|
||||
export default {
|
||||
mounted(src, binding) {
|
||||
mounted(src) {
|
||||
const resize = new ResizeObserver(() => {
|
||||
calc(src);
|
||||
});
|
||||
|
|
|
@ -1,265 +0,0 @@
|
|||
<template>
|
||||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader v-model:tab="tab" :tabs="headerTabs"/></template>
|
||||
<MkSpacer :content-max="700">
|
||||
<div class="jqqmcavi">
|
||||
<MkButton v-if="pageId" class="button" inline link :to="`/@${ author.username }/pages/${ currentName }`"><i class="fas fa-external-link-square-alt"></i> {{ $ts._pages.viewPage }}</MkButton>
|
||||
<MkButton v-if="!readonly" inline primary class="button" @click="save"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
|
||||
<MkButton v-if="pageId" inline class="button" @click="duplicate"><i class="fas fa-copy"></i> {{ $ts.duplicate }}</MkButton>
|
||||
<MkButton v-if="pageId && !readonly" inline class="button" danger @click="del"><i class="fas fa-trash-alt"></i> {{ $ts.delete }}</MkButton>
|
||||
</div>
|
||||
|
||||
<div v-if="tab === 'settings'">
|
||||
<div class="_formRoot">
|
||||
<MkInput v-model="title" :readonly="readonly" class="_formBlock">
|
||||
<template #label>{{ $ts._pages.title }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput v-model="summary" :readonly="readonly" class="_formBlock">
|
||||
<template #label>{{ $ts._pages.summary }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput v-model="name" :readonly="readonly" class="_formBlock">
|
||||
<template #prefix>{{ url }}/@{{ author.username }}/pages/</template>
|
||||
<template #label>{{ $ts._pages.url }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkSwitch v-model="alignCenter" :disabled="readonly" class="_formBlock">{{ $ts._pages.alignCenter }}</MkSwitch>
|
||||
|
||||
<MkSelect v-model="font" :readonly="readonly" class="_formBlock">
|
||||
<template #label>{{ $ts._pages.font }}</template>
|
||||
<option value="serif">{{ $ts._pages.fontSerif }}</option>
|
||||
<option value="sans-serif">{{ $ts._pages.fontSansSerif }}</option>
|
||||
</MkSelect>
|
||||
|
||||
<MkSwitch v-model="hideTitleWhenPinned" :disabled="readonly" class="_formBlock">{{ $ts._pages.hideTitleWhenPinned }}</MkSwitch>
|
||||
|
||||
<div class="eyeCatch">
|
||||
<MkButton v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage"><i class="fas fa-plus"></i> {{ $ts._pages.eyeCatchingImageSet }}</MkButton>
|
||||
<div v-else-if="eyeCatchingImage">
|
||||
<img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name" style="max-width: 100%;"/>
|
||||
<MkButton v-if="!readonly" @click="removeEyeCatchingImage()"><i class="fas fa-trash-alt"></i> {{ $ts._pages.eyeCatchingImageRemove }}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="tab === 'contents'">
|
||||
<MkTextarea v-model="text" :readonly="readonly"/>
|
||||
</div>
|
||||
</MkSpacer>
|
||||
</MkStickyContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import MkButton from '@/components/ui/button.vue';
|
||||
import MkSelect from '@/components/form/select.vue';
|
||||
import MkSwitch from '@/components/form/switch.vue';
|
||||
import MkInput from '@/components/form/input.vue';
|
||||
import MkTextarea from '@/components/form/textarea.vue';
|
||||
import { url } from '@/config';
|
||||
import * as os from '@/os';
|
||||
import { selectFile } from '@/scripts/select-file';
|
||||
import { mainRouter } from '@/router';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
import { $i } from '@/account';
|
||||
|
||||
const props = defineProps<{
|
||||
initPageId?: string;
|
||||
initPageName?: string;
|
||||
initUser?: string;
|
||||
}>();
|
||||
|
||||
let tab = $ref('settings');
|
||||
let author = $ref($i);
|
||||
let readonly = $ref(false);
|
||||
let page = $ref(null);
|
||||
let pageId = $ref(null);
|
||||
let currentName = $ref(null);
|
||||
let title = $ref('');
|
||||
let summary = $ref(null);
|
||||
let text = $ref('Hello, world!');
|
||||
let name = $ref(Date.now().toString());
|
||||
let eyeCatchingImage = $ref(null);
|
||||
let eyeCatchingImageId = $ref(null);
|
||||
let font = $ref('sans-serif');
|
||||
let alignCenter = $ref(false);
|
||||
let hideTitleWhenPinned = $ref(false);
|
||||
|
||||
watch($$(eyeCatchingImageId), async () => {
|
||||
if (eyeCatchingImageId == null) {
|
||||
eyeCatchingImage = null;
|
||||
} else {
|
||||
eyeCatchingImage = await os.api('drive/files/show', {
|
||||
fileId: eyeCatchingImageId,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function getSaveOptions() {
|
||||
return {
|
||||
title: title.trim(),
|
||||
name: name.trim(),
|
||||
summary,
|
||||
font,
|
||||
hideTitleWhenPinned,
|
||||
alignCenter,
|
||||
text,
|
||||
eyeCatchingImageId,
|
||||
};
|
||||
}
|
||||
|
||||
function save() {
|
||||
const options = getSaveOptions();
|
||||
|
||||
const onError = err => {
|
||||
if (err.id === '3d81ceae-475f-4600-b2a8-2bc116157532') {
|
||||
if (err.info.param === 'name') {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
title: i18n.ts._pages.invalidNameTitle,
|
||||
text: i18n.ts._pages.invalidNameText,
|
||||
});
|
||||
}
|
||||
} else if (err.code === 'NAME_ALREADY_EXISTS') {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
text: i18n.ts._pages.nameAlreadyExists,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (pageId) {
|
||||
options.pageId = pageId;
|
||||
os.api('pages/update', options)
|
||||
.then(page => {
|
||||
currentName = name.trim();
|
||||
os.alert({
|
||||
type: 'success',
|
||||
text: i18n.ts._pages.updated,
|
||||
});
|
||||
}).catch(onError);
|
||||
} else {
|
||||
os.api('pages/create', options)
|
||||
.then(created => {
|
||||
pageId = created.id;
|
||||
currentName = name.trim();
|
||||
os.alert({
|
||||
type: 'success',
|
||||
text: i18n.ts._pages.created,
|
||||
});
|
||||
mainRouter.push(`/pages/edit/${pageId}`);
|
||||
}).catch(onError);
|
||||
}
|
||||
}
|
||||
|
||||
function del() {
|
||||
os.confirm({
|
||||
type: 'warning',
|
||||
text: i18n.t('removeAreYouSure', { x: title.trim() }),
|
||||
}).then(({ canceled }) => {
|
||||
if (canceled) return;
|
||||
os.api('pages/delete', {
|
||||
pageId,
|
||||
}).then(() => {
|
||||
os.alert({
|
||||
type: 'success',
|
||||
text: i18n.ts._pages.deleted,
|
||||
});
|
||||
mainRouter.push('/pages');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function duplicate() {
|
||||
title = title + ' - copy';
|
||||
name = name + '-copy';
|
||||
os.api('pages/create', getSaveOptions()).then(created => {
|
||||
pageId = created.id;
|
||||
currentName = name.trim();
|
||||
os.alert({
|
||||
type: 'success',
|
||||
text: i18n.ts._pages.created,
|
||||
});
|
||||
mainRouter.push(`/pages/edit/${pageId}`);
|
||||
});
|
||||
}
|
||||
|
||||
function setEyeCatchingImage(evt) {
|
||||
selectFile(evt.currentTarget ?? evt.target, null).then(file => {
|
||||
eyeCatchingImageId = file.id;
|
||||
});
|
||||
}
|
||||
|
||||
function removeEyeCatchingImage() {
|
||||
eyeCatchingImageId = null;
|
||||
}
|
||||
|
||||
async function init() {
|
||||
if (props.initPageId) {
|
||||
page = await os.api('pages/show', {
|
||||
pageId: props.initPageId,
|
||||
});
|
||||
} else if (props.initPageName && props.initUser) {
|
||||
page = await os.api('pages/show', {
|
||||
name: props.initPageName,
|
||||
username: props.initUser,
|
||||
});
|
||||
readonly = true;
|
||||
}
|
||||
|
||||
if (page) {
|
||||
author = page.user;
|
||||
pageId = page.id;
|
||||
title = page.title;
|
||||
name = page.name;
|
||||
currentName = page.name;
|
||||
summary = page.summary;
|
||||
font = page.font;
|
||||
hideTitleWhenPinned = page.hideTitleWhenPinned;
|
||||
alignCenter = page.alignCenter;
|
||||
text = page.text;
|
||||
eyeCatchingImageId = page.eyeCatchingImageId;
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
key: 'settings',
|
||||
title: i18n.ts._pages.pageSetting,
|
||||
icon: 'fas fa-cog',
|
||||
}, {
|
||||
key: 'contents',
|
||||
title: i18n.ts._pages.contents,
|
||||
icon: 'fas fa-sticky-note',
|
||||
}]);
|
||||
|
||||
definePageMetadata(computed(() => {
|
||||
let title = i18n.ts._pages.newPage;
|
||||
if (props.initPageId) {
|
||||
title = i18n.ts._pages.editPage;
|
||||
}
|
||||
else if (props.initPageName && props.initUser) {
|
||||
title = i18n.ts._pages.readPage;
|
||||
}
|
||||
return {
|
||||
title,
|
||||
icon: 'fas fa-pencil-alt',
|
||||
};
|
||||
}));
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.jqqmcavi {
|
||||
margin-bottom: 1em;
|
||||
|
||||
> .button {
|
||||
& + .button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,69 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.button }}</template>
|
||||
|
||||
<section class="xfhsjczc">
|
||||
<MkInput v-model="value.text"><template #label>{{ $ts._pages.blocks._button.text }}</template></MkInput>
|
||||
<MkSwitch v-model="value.primary"><span>{{ $ts._pages.blocks._button.colored }}</span></MkSwitch>
|
||||
<MkSelect v-model="value.action">
|
||||
<template #label>{{ $ts._pages.blocks._button.action }}</template>
|
||||
<option value="dialog">{{ $ts._pages.blocks._button._action.dialog }}</option>
|
||||
<option value="resetRandom">{{ $ts._pages.blocks._button._action.resetRandom }}</option>
|
||||
<option value="pushEvent">{{ $ts._pages.blocks._button._action.pushEvent }}</option>
|
||||
<option value="callAiScript">{{ $ts._pages.blocks._button._action.callAiScript }}</option>
|
||||
</MkSelect>
|
||||
<template v-if="value.action === 'dialog'">
|
||||
<MkInput v-model="value.content"><template #label>{{ $ts._pages.blocks._button._action._dialog.content }}</template></MkInput>
|
||||
</template>
|
||||
<template v-else-if="value.action === 'pushEvent'">
|
||||
<MkInput v-model="value.event"><template #label>{{ $ts._pages.blocks._button._action._pushEvent.event }}</template></MkInput>
|
||||
<MkInput v-model="value.message"><template #label>{{ $ts._pages.blocks._button._action._pushEvent.message }}</template></MkInput>
|
||||
<MkSelect v-model="value.var">
|
||||
<template #label>{{ $ts._pages.blocks._button._action._pushEvent.variable }}</template>
|
||||
<option :value="null">{{ $t('_pages.blocks._button._action._pushEvent.no-variable') }}</option>
|
||||
<option v-for="v in hpml.getVarsByType()" :value="v.name">{{ v.name }}</option>
|
||||
<optgroup :label="$ts._pages.script.pageVariables">
|
||||
<option v-for="v in hpml.getPageVarsByType()" :value="v">{{ v }}</option>
|
||||
</optgroup>
|
||||
<optgroup :label="$ts._pages.script.enviromentVariables">
|
||||
<option v-for="v in hpml.getEnvVarsByType()" :value="v">{{ v }}</option>
|
||||
</optgroup>
|
||||
</MkSelect>
|
||||
</template>
|
||||
<template v-else-if="value.action === 'callAiScript'">
|
||||
<MkInput v-model="value.fn"><template #label>{{ $ts._pages.blocks._button._action._callAiScript.functionName }}</template></MkInput>
|
||||
</template>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkSelect from '@/components/form/select.vue';
|
||||
import MkInput from '@/components/form/input.vue';
|
||||
import MkSwitch from '@/components/form/switch.vue';
|
||||
|
||||
withDefaults(defineProps<{
|
||||
value: any,
|
||||
hpml: any
|
||||
}>(), {
|
||||
value: {
|
||||
text: '',
|
||||
action: 'dialog',
|
||||
content: null,
|
||||
event: null,
|
||||
message: null,
|
||||
primary: false,
|
||||
var: null,
|
||||
fn: null,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.xfhsjczc {
|
||||
padding: 0 16px 0 16px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,37 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-paint-brush"></i> {{ $ts._pages.blocks.canvas }}</template>
|
||||
|
||||
<section style="padding: 0 16px 0 16px;">
|
||||
<MkInput v-model="value.name">
|
||||
<template #prefix><i class="fas fa-magic"></i></template>
|
||||
<template #label>{{ $ts._pages.blocks._canvas.id }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="value.width" type="number">
|
||||
<template #label>{{ $ts._pages.blocks._canvas.width }}</template>
|
||||
<template #suffix>px</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="value.height" type="number">
|
||||
<template #label>{{ $ts._pages.blocks._canvas.height }}</template>
|
||||
<template #suffix>px</template>
|
||||
</MkInput>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkInput from '@/components/form/input.vue';
|
||||
|
||||
withDefaults(defineProps<{
|
||||
value: any
|
||||
}>(), {
|
||||
value: {
|
||||
name: '',
|
||||
width: 300,
|
||||
height: 200,
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.counter }}</template>
|
||||
|
||||
<section style="padding: 0 16px 0 16px;">
|
||||
<MkInput v-model="value.name">
|
||||
<template #prefix><i class="fas fa-magic"></i></template>
|
||||
<template #label>{{ $ts._pages.blocks._counter.name }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="value.text">
|
||||
<template #label>{{ $ts._pages.blocks._counter.text }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="value.inc" type="number">
|
||||
<template #label>{{ $ts._pages.blocks._counter.inc }}</template>
|
||||
</MkInput>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkInput from '@/components/form/input.vue';
|
||||
|
||||
withDefaults(defineProps<{
|
||||
value: any
|
||||
}>(), {
|
||||
value: {
|
||||
name: '',
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,67 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-question"></i> {{ $ts._pages.blocks.if }}</template>
|
||||
<template #func>
|
||||
<button class="_button" @click="add()">
|
||||
<i class="fas fa-plus"></i>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<section class="romcojzs">
|
||||
<MkSelect v-model="value.var">
|
||||
<template #label>{{ $ts._pages.blocks._if.variable }}</template>
|
||||
<option v-for="v in hpml.getVarsByType('boolean')" :value="v.name">{{ v.name }}</option>
|
||||
<optgroup :label="$ts._pages.script.pageVariables">
|
||||
<option v-for="v in hpml.getPageVarsByType('boolean')" :value="v">{{ v }}</option>
|
||||
</optgroup>
|
||||
<optgroup :label="$ts._pages.script.enviromentVariables">
|
||||
<option v-for="v in hpml.getEnvVarsByType('boolean')" :value="v">{{ v }}</option>
|
||||
</optgroup>
|
||||
</MkSelect>
|
||||
|
||||
<XBlocks v-model="value.children" class="children" :hpml="hpml"/>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import { defineAsyncComponent, inject } from 'vue';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkSelect from '@/components/form/select.vue';
|
||||
import * as os from '@/os';
|
||||
import { i18n } from '@/i18n';
|
||||
|
||||
const XBlocks = defineAsyncComponent(() => import('../page-editor.blocks.vue'));
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
value: any,
|
||||
hpml: any
|
||||
}>(), {
|
||||
value: {
|
||||
children: [],
|
||||
var: null,
|
||||
},
|
||||
});
|
||||
|
||||
const getPageBlockList = inject<(any) => any>('getPageBlockList');
|
||||
|
||||
async function add() {
|
||||
const { canceled, result: type } = await os.select({
|
||||
title: i18n.ts._pages.chooseBlock,
|
||||
groupedItems: getPageBlockList(),
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
const id = uuid();
|
||||
props.value.children.push({ id, type });
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.romcojzs {
|
||||
padding: 0 16px 16px 16px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,60 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-image"></i> {{ $ts._pages.blocks.image }}</template>
|
||||
<template #func>
|
||||
<button @click="choose()">
|
||||
<i class="fas fa-folder-open"></i>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<section class="oyyftmcf">
|
||||
<MkDriveFileThumbnail v-if="file" class="preview" :file="file" fit="contain" @click="choose()"/>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import { onMounted } from 'vue';
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkDriveFileThumbnail from '@/components/drive-file-thumbnail.vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
value: any
|
||||
}>(), {
|
||||
value: {
|
||||
fileId: null,
|
||||
},
|
||||
});
|
||||
|
||||
let file: any = $ref(null);
|
||||
|
||||
async function choose() {
|
||||
os.selectDriveFile(false).then((fileResponse: any) => {
|
||||
file = fileResponse;
|
||||
props.value.fileId = fileResponse.id;
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (props.value.fileId == null) {
|
||||
await choose();
|
||||
} else {
|
||||
os.api('drive/files/show', {
|
||||
fileId: props.value.fileId,
|
||||
}).then(fileResponse => {
|
||||
file = fileResponse;
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.oyyftmcf {
|
||||
> .preview {
|
||||
height: 150px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,52 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-sticky-note"></i> {{ $ts._pages.blocks.note }}</template>
|
||||
|
||||
<section style="padding: 0 16px 0 16px;">
|
||||
<MkInput v-model="id">
|
||||
<template #label>{{ $ts._pages.blocks._note.id }}</template>
|
||||
<template #caption>{{ $ts._pages.blocks._note.idDescription }}</template>
|
||||
</MkInput>
|
||||
<MkSwitch v-model="value.detailed"><span>{{ $ts._pages.blocks._note.detailed }}</span></MkSwitch>
|
||||
|
||||
<XNote v-if="note && !value.detailed" :key="note.id + ':normal'" v-model:note="note" style="margin-bottom: 16px;"/>
|
||||
<XNoteDetailed v-if="note && value.detailed" :key="note.id + ':detail'" v-model:note="note" style="margin-bottom: 16px;"/>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import { watch } from 'vue';
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkInput from '@/components/form/input.vue';
|
||||
import MkSwitch from '@/components/form/switch.vue';
|
||||
import XNote from '@/components/note.vue';
|
||||
import XNoteDetailed from '@/components/note-detailed.vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
value: any
|
||||
}>(), {
|
||||
value: {
|
||||
note: null,
|
||||
detailed: false,
|
||||
},
|
||||
});
|
||||
|
||||
let id: any = $ref(props.value.note);
|
||||
let note: any = $ref(null);
|
||||
|
||||
watch(id, async () => {
|
||||
if (id && (id.startsWith('http://') || id.startsWith('https://'))) {
|
||||
props.value.note = (id.endsWith('/') ? id.slice(0, -1) : id).split('/').pop();
|
||||
} else {
|
||||
props.value.note = id;
|
||||
}
|
||||
|
||||
note = await os.api('notes/show', { noteId: props.value.note });
|
||||
}, {
|
||||
immediate: true,
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.numberInput }}</template>
|
||||
|
||||
<section style="padding: 0 16px 0 16px;">
|
||||
<MkInput v-model="value.name">
|
||||
<template #prefix><i class="fas fa-magic"></i></template>
|
||||
<template #label>{{ $ts._pages.blocks._numberInput.name }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="value.text">
|
||||
<template #label>{{ $ts._pages.blocks._numberInput.text }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="value.default" type="number">
|
||||
<template #label>{{ $ts._pages.blocks._numberInput.default }}</template>
|
||||
</MkInput>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkInput from '@/components/form/input.vue';
|
||||
|
||||
withDefaults(defineProps<{
|
||||
value: any
|
||||
}>(), {
|
||||
value: {
|
||||
name: '',
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,30 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-paper-plane"></i> {{ $ts._pages.blocks.post }}</template>
|
||||
|
||||
<section style="padding: 16px;">
|
||||
<MkTextarea v-model="value.text"><template #label>{{ $ts._pages.blocks._post.text }}</template></MkTextarea>
|
||||
<MkSwitch v-model="value.attachCanvasImage"><span>{{ $ts._pages.blocks._post.attachCanvasImage }}</span></MkSwitch>
|
||||
<MkInput v-if="value.attachCanvasImage" v-model="value.canvasId"><template #label>{{ $ts._pages.blocks._post.canvasId }}</template></MkInput>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkTextarea from '@/components/form/textarea.vue';
|
||||
import MkInput from '@/components/form/input.vue';
|
||||
import MkSwitch from '@/components/form/switch.vue';
|
||||
|
||||
withDefaults(defineProps<{
|
||||
value: any
|
||||
}>(), {
|
||||
value: {
|
||||
text: '',
|
||||
attachCanvasImage: false,
|
||||
canvasId: '',
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,39 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.radioButton }}</template>
|
||||
|
||||
<section style="padding: 0 16px 16px 16px;">
|
||||
<MkInput v-model="value.name"><template #prefix><i class="fas fa-magic"></i></template><template #label>{{ $ts._pages.blocks._radioButton.name }}</template></MkInput>
|
||||
<MkInput v-model="value.title"><template #label>{{ $ts._pages.blocks._radioButton.title }}</template></MkInput>
|
||||
<MkTextarea v-model="values"><template #label>{{ $ts._pages.blocks._radioButton.values }}</template></MkTextarea>
|
||||
<MkInput v-model="value.default"><template #label>{{ $ts._pages.blocks._radioButton.default }}</template></MkInput>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import { watch } from 'vue';
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkTextarea from '@/components/form/textarea.vue';
|
||||
import MkInput from '@/components/form/input.vue';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
value: any
|
||||
}>(), {
|
||||
value: {
|
||||
name: '',
|
||||
title: '',
|
||||
values: [],
|
||||
},
|
||||
});
|
||||
|
||||
let values: string = $ref(props.value.values.join('\n'));
|
||||
|
||||
watch(values, () => {
|
||||
props.value.values = values.split('\n');
|
||||
}, {
|
||||
deep: true,
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-sticky-note"></i> {{ value.title }}</template>
|
||||
<template #func>
|
||||
<button class="_button" @click="rename()">
|
||||
<i class="fas fa-pencil-alt"></i>
|
||||
</button>
|
||||
<button class="_button" @click="add()">
|
||||
<i class="fas fa-plus"></i>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<section class="ilrvjyvi">
|
||||
<XBlocks v-model="value.children" class="children" :hpml="hpml"/>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import { defineAsyncComponent, inject, onMounted } from 'vue';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import * as os from '@/os';
|
||||
import { i18n } from '@/i18n';
|
||||
|
||||
const XBlocks = defineAsyncComponent(() => import('../page-editor.blocks.vue'));
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
value: any,
|
||||
hpml: any
|
||||
}>(), {
|
||||
value: {
|
||||
title: null,
|
||||
children: [],
|
||||
},
|
||||
});
|
||||
|
||||
const getPageBlockList = inject<(any) => any>('getPageBlockList');
|
||||
|
||||
async function rename() {
|
||||
const { canceled, result: title } = await os.inputText({
|
||||
title: 'Enter title',
|
||||
default: props.value.title,
|
||||
});
|
||||
if (canceled) return;
|
||||
props.value.title = title;
|
||||
}
|
||||
|
||||
async function add() {
|
||||
const { canceled, result: type } = await os.select({
|
||||
title: i18n.ts._pages.chooseBlock,
|
||||
groupedItems: getPageBlockList(),
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
const id = uuid();
|
||||
props.value.children.push({ id, type });
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (props.value.title == null) {
|
||||
rename();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ilrvjyvi {
|
||||
> .children {
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.switch }}</template>
|
||||
|
||||
<section class="kjuadyyj">
|
||||
<MkInput v-model="value.name"><template #prefix><i class="fas fa-magic"></i></template><template #label>{{ $ts._pages.blocks._switch.name }}</template></MkInput>
|
||||
<MkInput v-model="value.text"><template #label>{{ $ts._pages.blocks._switch.text }}</template></MkInput>
|
||||
<MkSwitch v-model="value.default"><span>{{ $ts._pages.blocks._switch.default }}</span></MkSwitch>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkSwitch from '@/components/form/switch.vue';
|
||||
import MkInput from '@/components/form/input.vue';
|
||||
|
||||
withDefaults(defineProps<{
|
||||
value: any
|
||||
}>(), {
|
||||
value: {
|
||||
name: '',
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.kjuadyyj {
|
||||
padding: 0 16px 16px 16px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,26 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.textInput }}</template>
|
||||
|
||||
<section style="padding: 0 16px 0 16px;">
|
||||
<MkInput v-model="value.name"><template #prefix><i class="fas fa-magic"></i></template><template #label>{{ $ts._pages.blocks._textInput.name }}</template></MkInput>
|
||||
<MkInput v-model="value.text"><template #label>{{ $ts._pages.blocks._textInput.text }}</template></MkInput>
|
||||
<MkInput v-model="value.default" type="text"><template #label>{{ $ts._pages.blocks._textInput.default }}</template></MkInput>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkInput from '@/components/form/input.vue';
|
||||
|
||||
withDefaults(defineProps<{
|
||||
value: any
|
||||
}>(), {
|
||||
value: {
|
||||
name: '',
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,44 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-align-left"></i> {{ $ts._pages.blocks.text }}</template>
|
||||
|
||||
<section class="vckmsadr">
|
||||
<textarea v-model="value.text"></textarea>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
|
||||
withDefaults(defineProps<{
|
||||
value: any
|
||||
}>(), {
|
||||
value: {
|
||||
text: '',
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.vckmsadr {
|
||||
> textarea {
|
||||
display: block;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
min-height: 150px;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding: 16px;
|
||||
background: transparent;
|
||||
color: var(--fg);
|
||||
font-size: 14px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,27 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.textareaInput }}</template>
|
||||
|
||||
<section style="padding: 0 16px 16px 16px;">
|
||||
<MkInput v-model="value.name"><template #prefix><i class="fas fa-magic"></i></template><template #label>{{ $ts._pages.blocks._textareaInput.name }}</template></MkInput>
|
||||
<MkInput v-model="value.text"><template #label>{{ $ts._pages.blocks._textareaInput.text }}</template></MkInput>
|
||||
<MkTextarea v-model="value.default"><template #label>{{ $ts._pages.blocks._textareaInput.default }}</template></MkTextarea>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
import MkTextarea from '@/components/form/textarea.vue';
|
||||
import MkInput from '@/components/form/input.vue';
|
||||
|
||||
withDefaults(defineProps<{
|
||||
value: any
|
||||
}>(), {
|
||||
value: {
|
||||
name: '',
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,44 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :draggable="true" @remove="() => $emit('remove')">
|
||||
<template #header><i class="fas fa-align-left"></i> {{ $ts._pages.blocks.textarea }}</template>
|
||||
|
||||
<section class="ihymsbbe">
|
||||
<textarea v-model="value.text"></textarea>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import XContainer from '../page-editor.container.vue';
|
||||
|
||||
withDefaults(defineProps<{
|
||||
value: any
|
||||
}>(), {
|
||||
value: {
|
||||
text: '',
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ihymsbbe {
|
||||
> textarea {
|
||||
display: block;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
min-height: 150px;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding: 16px;
|
||||
background: transparent;
|
||||
color: var(--fg);
|
||||
font-size: 14px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
</style>
|
78
packages/client/src/pages/page-editor/page-editor.blocks.vue
Normal file
78
packages/client/src/pages/page-editor/page-editor.blocks.vue
Normal file
|
@ -0,0 +1,78 @@
|
|||
<template>
|
||||
<XDraggable v-model="blocks" tag="div" item-key="id" handle=".drag-handle" :group="{ name: 'blocks' }" animation="150" swap-threshold="0.5">
|
||||
<template #item="{element}">
|
||||
<component :is="'x-' + element.type" :value="element" :hpml="hpml" @update:value="updateItem" @remove="() => removeItem(element)"/>
|
||||
</template>
|
||||
</XDraggable>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, defineAsyncComponent } from 'vue';
|
||||
import XSection from './els/page-editor.el.section.vue';
|
||||
import XText from './els/page-editor.el.text.vue';
|
||||
import XTextarea from './els/page-editor.el.textarea.vue';
|
||||
import XImage from './els/page-editor.el.image.vue';
|
||||
import XButton from './els/page-editor.el.button.vue';
|
||||
import XTextInput from './els/page-editor.el.text-input.vue';
|
||||
import XTextareaInput from './els/page-editor.el.textarea-input.vue';
|
||||
import XNumberInput from './els/page-editor.el.number-input.vue';
|
||||
import XSwitch from './els/page-editor.el.switch.vue';
|
||||
import XIf from './els/page-editor.el.if.vue';
|
||||
import XPost from './els/page-editor.el.post.vue';
|
||||
import XCounter from './els/page-editor.el.counter.vue';
|
||||
import XRadioButton from './els/page-editor.el.radio-button.vue';
|
||||
import XCanvas from './els/page-editor.el.canvas.vue';
|
||||
import XNote from './els/page-editor.el.note.vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XDraggable: defineAsyncComponent(() => import('vuedraggable').then(x => x.default)),
|
||||
XSection, XText, XImage, XButton, XTextarea, XTextInput, XTextareaInput, XNumberInput, XSwitch, XIf, XPost, XCounter, XRadioButton, XCanvas, XNote,
|
||||
},
|
||||
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
hpml: {
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
emits: ['update:modelValue'],
|
||||
|
||||
computed: {
|
||||
blocks: {
|
||||
get() {
|
||||
return this.modelValue;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('update:modelValue', value);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateItem(v) {
|
||||
const i = this.blocks.findIndex(x => x.id === v.id);
|
||||
const newValue = [
|
||||
...this.blocks.slice(0, i),
|
||||
v,
|
||||
...this.blocks.slice(i + 1),
|
||||
];
|
||||
this.$emit('update:modelValue', newValue);
|
||||
},
|
||||
|
||||
removeItem(el) {
|
||||
const i = this.blocks.findIndex(x => x.id === el.id);
|
||||
const newValue = [
|
||||
...this.blocks.slice(0, i),
|
||||
...this.blocks.slice(i + 1),
|
||||
];
|
||||
this.$emit('update:modelValue', newValue);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
143
packages/client/src/pages/page-editor/page-editor.container.vue
Normal file
143
packages/client/src/pages/page-editor/page-editor.container.vue
Normal file
|
@ -0,0 +1,143 @@
|
|||
<template>
|
||||
<div class="cpjygsrt" :class="{ error: error != null, warn: warn != null }">
|
||||
<header>
|
||||
<div class="title"><slot name="header"></slot></div>
|
||||
<div class="buttons">
|
||||
<slot name="func"></slot>
|
||||
<button v-if="removable" class="_button" @click="emit('remove')">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
<button v-if="draggable" class="drag-handle _button">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
<button class="_button" @click="toggleContent(!showBody)">
|
||||
<template v-if="showBody"><i class="fas fa-angle-up"></i></template>
|
||||
<template v-else><i class="fas fa-angle-down"></i></template>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<p v-show="showBody" v-if="error != null" class="error">{{ i18n.t('_pages.script.typeError', { slot: error.arg + 1, expect: i18n.t(`script.types.${error.expect}`), actual: i18n.t(`script.types.${error.actual}`) }) }}</p>
|
||||
<p v-show="showBody" v-if="warn != null" class="warn">{{ i18n.t('_pages.script.thereIsEmptySlot', { slot: warn.slot + 1 }) }}</p>
|
||||
<div v-show="showBody" class="body">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { i18n } from '@/i18n';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'toggle', v: boolean): void;
|
||||
(ev: 'remove'): void;
|
||||
}>();
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
expanded?: boolean;
|
||||
removable?: boolean;
|
||||
draggable?: boolean;
|
||||
error?: { arg: number; expect: string; actual: string; };
|
||||
warn?: { slot: number; };
|
||||
}>(), {
|
||||
expanded: true,
|
||||
removable: true,
|
||||
draggable: false,
|
||||
});
|
||||
|
||||
let showBody = $ref(props.expanded);
|
||||
|
||||
function toggleContent(show: boolean) {
|
||||
showBody = show;
|
||||
emit('toggle', show);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cpjygsrt {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: var(--panel);
|
||||
border: solid 2px var(--X12);
|
||||
border-radius: 6px;
|
||||
|
||||
&:hover {
|
||||
border: solid 2px var(--X13);
|
||||
}
|
||||
|
||||
&.warn {
|
||||
border: solid 2px #dec44c;
|
||||
}
|
||||
|
||||
&.error {
|
||||
border: solid 2px #f00;
|
||||
}
|
||||
|
||||
& + .cpjygsrt {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
> header {
|
||||
> .title {
|
||||
z-index: 1;
|
||||
margin: 0;
|
||||
padding: 0 16px;
|
||||
line-height: 42px;
|
||||
font-size: 0.9em;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 1px rgba(#000, 0.07);
|
||||
|
||||
> i {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
> .buttons {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
> button {
|
||||
padding: 0;
|
||||
width: 42px;
|
||||
font-size: 0.9em;
|
||||
line-height: 42px;
|
||||
}
|
||||
|
||||
.drag-handle {
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .warn {
|
||||
color: #b19e49;
|
||||
margin: 0;
|
||||
padding: 16px 16px 0 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
> .error {
|
||||
color: #f00;
|
||||
margin: 0;
|
||||
padding: 16px 16px 0 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
> .body {
|
||||
::v-deep(.juejbjww), ::v-deep(.eiipwacr) {
|
||||
&:not(.inline):first-child {
|
||||
margin-top: 28px;
|
||||
}
|
||||
|
||||
&:not(.inline):last-child {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,279 @@
|
|||
<template>
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<XContainer :removable="removable" :error="error" :warn="warn" :draggable="draggable" @remove="() => $emit('remove')">
|
||||
<template #header><i v-if="icon" :class="icon"></i> <template v-if="title">{{ title }} <span v-if="typeText" class="turmquns">({{ typeText }})</span></template><template v-else-if="typeText">{{ typeText }}</template></template>
|
||||
<template #func>
|
||||
<button class="_button" @click="changeType()">
|
||||
<i class="fas fa-pencil-alt"></i>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<section v-if="modelValue.type === null" class="pbglfege" @click="changeType()">
|
||||
{{ $ts._pages.script.emptySlot }}
|
||||
</section>
|
||||
<section v-else-if="modelValue.type === 'text'" class="tbwccoaw">
|
||||
<input v-model="modelValue.value"/>
|
||||
</section>
|
||||
<section v-else-if="modelValue.type === 'multiLineText'" class="tbwccoaw">
|
||||
<textarea v-model="modelValue.value"></textarea>
|
||||
</section>
|
||||
<section v-else-if="modelValue.type === 'textList'" class="tbwccoaw">
|
||||
<textarea v-model="modelValue.value" :placeholder="$ts._pages.script.blocks._textList.info"></textarea>
|
||||
</section>
|
||||
<section v-else-if="modelValue.type === 'number'" class="tbwccoaw">
|
||||
<input v-model="modelValue.value" type="number"/>
|
||||
</section>
|
||||
<section v-else-if="modelValue.type === 'ref'" class="hpdwcrvs">
|
||||
<select v-model="modelValue.value">
|
||||
<option v-for="v in hpml.getVarsByType(getExpectedType ? getExpectedType() : null).filter(x => x.name !== name)" :value="v.name">{{ v.name }}</option>
|
||||
<optgroup :label="$ts._pages.script.argVariables">
|
||||
<option v-for="v in fnSlots" :value="v.name">{{ v.name }}</option>
|
||||
</optgroup>
|
||||
<optgroup :label="$ts._pages.script.pageVariables">
|
||||
<option v-for="v in hpml.getPageVarsByType(getExpectedType ? getExpectedType() : null)" :value="v">{{ v }}</option>
|
||||
</optgroup>
|
||||
<optgroup :label="$ts._pages.script.enviromentVariables">
|
||||
<option v-for="v in hpml.getEnvVarsByType(getExpectedType ? getExpectedType() : null)" :value="v">{{ v }}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</section>
|
||||
<section v-else-if="modelValue.type === 'aiScriptVar'" class="tbwccoaw">
|
||||
<input v-model="modelValue.value"/>
|
||||
</section>
|
||||
<section v-else-if="modelValue.type === 'fn'" class="" style="padding:0 16px 16px 16px;">
|
||||
<MkTextarea v-model="slots">
|
||||
<template #label>{{ $ts._pages.script.blocks._fn.slots }}</template>
|
||||
<template #caption>{{ $t('_pages.script.blocks._fn.slots-info') }}</template>
|
||||
</MkTextarea>
|
||||
<XV v-if="modelValue.value.expression" v-model="modelValue.value.expression" :title="$t(`_pages.script.blocks._fn.arg1`)" :get-expected-type="() => null" :hpml="hpml" :fn-slots="modelValue.value.slots" :name="name"/>
|
||||
</section>
|
||||
<section v-else-if="modelValue.type.startsWith('fn:')" class="" style="padding:16px;">
|
||||
<XV v-for="(x, i) in modelValue.args" :key="i" v-model="modelValue.args[i]" :title="hpml.getVarByName(modelValue.type.split(':')[1]).value.slots[i].name" :get-expected-type="() => null" :hpml="hpml" :name="name"/>
|
||||
</section>
|
||||
<section v-else class="" style="padding:16px;">
|
||||
<XV v-for="(x, i) in modelValue.args" :key="i" v-model="modelValue.args[i]" :title="$t(`_pages.script.blocks._${modelValue.type}.arg${i + 1}`)" :get-expected-type="() => _getExpectedType(i)" :hpml="hpml" :name="name" :fn-slots="fnSlots"/>
|
||||
</section>
|
||||
</XContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
/* eslint-disable vue/no-mutating-props */
|
||||
import { defineAsyncComponent, defineComponent } from 'vue';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import XContainer from './page-editor.container.vue';
|
||||
import MkTextarea from '@/components/form/textarea.vue';
|
||||
import { blockDefs } from '@/scripts/hpml/index';
|
||||
import * as os from '@/os';
|
||||
import { isLiteralValue } from '@/scripts/hpml/expr';
|
||||
import { funcDefs } from '@/scripts/hpml/lib';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XContainer, MkTextarea,
|
||||
XV: defineAsyncComponent(() => import('./page-editor.script-block.vue')),
|
||||
},
|
||||
|
||||
inject: ['getScriptBlockList'],
|
||||
|
||||
props: {
|
||||
getExpectedType: {
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
modelValue: {
|
||||
required: true,
|
||||
},
|
||||
title: {
|
||||
required: false,
|
||||
},
|
||||
removable: {
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
hpml: {
|
||||
required: true,
|
||||
},
|
||||
name: {
|
||||
required: true,
|
||||
},
|
||||
fnSlots: {
|
||||
required: false,
|
||||
},
|
||||
draggable: {
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
error: null,
|
||||
warn: null,
|
||||
slots: '',
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
icon(): any {
|
||||
if (this.modelValue.type === null) return null;
|
||||
if (this.modelValue.type.startsWith('fn:')) return 'fas fa-plug';
|
||||
return blockDefs.find(x => x.type === this.modelValue.type).icon;
|
||||
},
|
||||
typeText(): any {
|
||||
if (this.modelValue.type === null) return null;
|
||||
if (this.modelValue.type.startsWith('fn:')) return this.modelValue.type.split(':')[1];
|
||||
return this.$t(`_pages.script.blocks.${this.modelValue.type}`);
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
slots: {
|
||||
handler() {
|
||||
this.modelValue.value.slots = this.slots.split('\n').map(x => ({
|
||||
name: x,
|
||||
type: null,
|
||||
}));
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.modelValue.value == null) this.modelValue.value = null;
|
||||
|
||||
if (this.modelValue.value && this.modelValue.value.slots) this.slots = this.modelValue.value.slots.map(x => x.name).join('\n');
|
||||
|
||||
this.$watch(() => this.modelValue.type, (t) => {
|
||||
this.warn = null;
|
||||
|
||||
if (this.modelValue.type === 'fn') {
|
||||
const id = uuid();
|
||||
this.modelValue.value = {
|
||||
slots: [],
|
||||
expression: { id, type: null },
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.modelValue.type && this.modelValue.type.startsWith('fn:')) {
|
||||
const fnName = this.modelValue.type.split(':')[1];
|
||||
const fn = this.hpml.getVarByName(fnName);
|
||||
|
||||
const empties = [];
|
||||
for (let i = 0; i < fn.value.slots.length; i++) {
|
||||
const id = uuid();
|
||||
empties.push({ id, type: null });
|
||||
}
|
||||
this.modelValue.args = empties;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isLiteralValue(this.modelValue)) return;
|
||||
|
||||
const empties = [];
|
||||
for (let i = 0; i < funcDefs[this.modelValue.type].in.length; i++) {
|
||||
const id = uuid();
|
||||
empties.push({ id, type: null });
|
||||
}
|
||||
this.modelValue.args = empties;
|
||||
|
||||
for (let i = 0; i < funcDefs[this.modelValue.type].in.length; i++) {
|
||||
const inType = funcDefs[this.modelValue.type].in[i];
|
||||
if (typeof inType !== 'number') {
|
||||
if (inType === 'number') this.modelValue.args[i].type = 'number';
|
||||
if (inType === 'string') this.modelValue.args[i].type = 'text';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.$watch(() => this.modelValue.args, (args) => {
|
||||
if (args == null) {
|
||||
this.warn = null;
|
||||
return;
|
||||
}
|
||||
const emptySlotIndex = args.findIndex(x => x.type === null);
|
||||
if (emptySlotIndex !== -1 && emptySlotIndex < args.length) {
|
||||
this.warn = {
|
||||
slot: emptySlotIndex,
|
||||
};
|
||||
} else {
|
||||
this.warn = null;
|
||||
}
|
||||
}, {
|
||||
deep: true,
|
||||
});
|
||||
|
||||
this.$watch(() => this.hpml.variables, () => {
|
||||
if (this.type != null && this.modelValue) {
|
||||
this.error = this.hpml.typeCheck(this.modelValue);
|
||||
}
|
||||
}, {
|
||||
deep: true,
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
async changeType() {
|
||||
const { canceled, result: type } = await os.select({
|
||||
title: this.$ts._pages.selectType,
|
||||
groupedItems: this.getScriptBlockList(this.getExpectedType ? this.getExpectedType() : null),
|
||||
});
|
||||
if (canceled) return;
|
||||
this.modelValue.type = type;
|
||||
},
|
||||
|
||||
_getExpectedType(slot: number) {
|
||||
return this.hpml.getExpectedType(this.modelValue, slot);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.turmquns {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.pbglfege {
|
||||
opacity: 0.5;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
.tbwccoaw {
|
||||
> input,
|
||||
> textarea {
|
||||
display: block;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
min-width: 100%;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding: 16px;
|
||||
font-size: 16px;
|
||||
background: transparent;
|
||||
color: var(--fg);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
> textarea {
|
||||
min-height: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
.hpdwcrvs {
|
||||
padding: 16px;
|
||||
|
||||
> select {
|
||||
display: block;
|
||||
padding: 4px;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
531
packages/client/src/pages/page-editor/page-editor.vue
Normal file
531
packages/client/src/pages/page-editor/page-editor.vue
Normal file
|
@ -0,0 +1,531 @@
|
|||
<template>
|
||||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
|
||||
<MkSpacer :content-max="700">
|
||||
<div class="jqqmcavi">
|
||||
<MkButton v-if="pageId" class="button" inline link :to="`/@${ author.username }/pages/${ currentName }`"><i class="fas fa-external-link-square-alt"></i> {{ $ts._pages.viewPage }}</MkButton>
|
||||
<MkButton v-if="!readonly" inline primary class="button" @click="save"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
|
||||
<MkButton v-if="pageId" inline class="button" @click="duplicate"><i class="fas fa-copy"></i> {{ $ts.duplicate }}</MkButton>
|
||||
<MkButton v-if="pageId && !readonly" inline class="button" danger @click="del"><i class="fas fa-trash-alt"></i> {{ $ts.delete }}</MkButton>
|
||||
</div>
|
||||
|
||||
<div v-if="tab === 'settings'">
|
||||
<div class="_formRoot">
|
||||
<MkInput v-model="title" class="_formBlock">
|
||||
<template #label>{{ $ts._pages.title }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput v-model="summary" class="_formBlock">
|
||||
<template #label>{{ $ts._pages.summary }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkInput v-model="name" class="_formBlock">
|
||||
<template #prefix>{{ url }}/@{{ author.username }}/pages/</template>
|
||||
<template #label>{{ $ts._pages.url }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkSwitch v-model="alignCenter" class="_formBlock">{{ $ts._pages.alignCenter }}</MkSwitch>
|
||||
|
||||
<MkSelect v-model="font" class="_formBlock">
|
||||
<template #label>{{ $ts._pages.font }}</template>
|
||||
<option value="serif">{{ $ts._pages.fontSerif }}</option>
|
||||
<option value="sans-serif">{{ $ts._pages.fontSansSerif }}</option>
|
||||
</MkSelect>
|
||||
|
||||
<MkSwitch v-model="hideTitleWhenPinned" class="_formBlock">{{ $ts._pages.hideTitleWhenPinned }}</MkSwitch>
|
||||
|
||||
<div class="eyeCatch">
|
||||
<MkButton v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage"><i class="fas fa-plus"></i> {{ $ts._pages.eyeCatchingImageSet }}</MkButton>
|
||||
<div v-else-if="eyeCatchingImage">
|
||||
<img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name" style="max-width: 100%;"/>
|
||||
<MkButton v-if="!readonly" @click="removeEyeCatchingImage()"><i class="fas fa-trash-alt"></i> {{ $ts._pages.eyeCatchingImageRemove }}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="tab === 'contents'">
|
||||
<div>
|
||||
<XBlocks v-model="content" class="content" :hpml="hpml"/>
|
||||
|
||||
<MkButton v-if="!readonly" @click="add()"><i class="fas fa-plus"></i></MkButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="tab === 'variables'">
|
||||
<div class="qmuvgica">
|
||||
<XDraggable v-show="variables.length > 0" v-model="variables" tag="div" class="variables" item-key="name" handle=".drag-handle" :group="{ name: 'variables' }" animation="150" swap-threshold="0.5">
|
||||
<template #item="{element}">
|
||||
<XVariable
|
||||
:model-value="element"
|
||||
:removable="true"
|
||||
:hpml="hpml"
|
||||
:name="element.name"
|
||||
:title="element.name"
|
||||
:draggable="true"
|
||||
@remove="() => removeVariable(element)"
|
||||
/>
|
||||
</template>
|
||||
</XDraggable>
|
||||
|
||||
<MkButton v-if="!readonly" class="add" @click="addVariable()"><i class="fas fa-plus"></i></MkButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="tab === 'script'">
|
||||
<div>
|
||||
<MkTextarea v-model="script" class="_code"/>
|
||||
</div>
|
||||
</div>
|
||||
</MkSpacer>
|
||||
</MkStickyContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, computed, provide, watch } from 'vue';
|
||||
import 'prismjs';
|
||||
import { highlight, languages } from 'prismjs/components/prism-core';
|
||||
import 'prismjs/components/prism-clike';
|
||||
import 'prismjs/components/prism-javascript';
|
||||
import 'prismjs/themes/prism-okaidia.css';
|
||||
import 'vue-prism-editor/dist/prismeditor.min.css';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import XVariable from './page-editor.script-block.vue';
|
||||
import XBlocks from './page-editor.blocks.vue';
|
||||
import MkTextarea from '@/components/form/textarea.vue';
|
||||
import MkButton from '@/components/ui/button.vue';
|
||||
import MkSelect from '@/components/form/select.vue';
|
||||
import MkSwitch from '@/components/form/switch.vue';
|
||||
import MkInput from '@/components/form/input.vue';
|
||||
import { blockDefs } from '@/scripts/hpml/index';
|
||||
import { HpmlTypeChecker } from '@/scripts/hpml/type-checker';
|
||||
import { url } from '@/config';
|
||||
import { collectPageVars } from '@/scripts/collect-page-vars';
|
||||
import * as os from '@/os';
|
||||
import { selectFile } from '@/scripts/select-file';
|
||||
import { mainRouter } from '@/router';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
import { $i } from '@/account';
|
||||
const XDraggable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
|
||||
|
||||
const props = defineProps<{
|
||||
initPageId?: string;
|
||||
initPageName?: string;
|
||||
initUser?: string;
|
||||
}>();
|
||||
|
||||
let tab = $ref('settings');
|
||||
let author = $ref($i);
|
||||
let readonly = $ref(false);
|
||||
let page = $ref(null);
|
||||
let pageId = $ref(null);
|
||||
let currentName = $ref(null);
|
||||
let title = $ref('');
|
||||
let summary = $ref(null);
|
||||
let name = $ref(Date.now().toString());
|
||||
let eyeCatchingImage = $ref(null);
|
||||
let eyeCatchingImageId = $ref(null);
|
||||
let font = $ref('sans-serif');
|
||||
let content = $ref([]);
|
||||
let alignCenter = $ref(false);
|
||||
let hideTitleWhenPinned = $ref(false);
|
||||
let variables = $ref([]);
|
||||
let hpml = $ref(null);
|
||||
let script = $ref('');
|
||||
|
||||
provide('readonly', readonly);
|
||||
provide('getScriptBlockList', getScriptBlockList);
|
||||
provide('getPageBlockList', getPageBlockList);
|
||||
|
||||
watch($$(eyeCatchingImageId), async () => {
|
||||
if (eyeCatchingImageId == null) {
|
||||
eyeCatchingImage = null;
|
||||
} else {
|
||||
eyeCatchingImage = await os.api('drive/files/show', {
|
||||
fileId: eyeCatchingImageId,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function getSaveOptions() {
|
||||
return {
|
||||
title: title.trim(),
|
||||
name: name.trim(),
|
||||
summary,
|
||||
font,
|
||||
script,
|
||||
hideTitleWhenPinned,
|
||||
alignCenter,
|
||||
content,
|
||||
variables,
|
||||
eyeCatchingImageId,
|
||||
};
|
||||
}
|
||||
|
||||
function save() {
|
||||
const options = getSaveOptions();
|
||||
|
||||
const onError = err => {
|
||||
if (err.id === '3d81ceae-475f-4600-b2a8-2bc116157532') {
|
||||
if (err.info.param === 'name') {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
title: i18n.ts._pages.invalidNameTitle,
|
||||
text: i18n.ts._pages.invalidNameText,
|
||||
});
|
||||
}
|
||||
} else if (err.code === 'NAME_ALREADY_EXISTS') {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
text: i18n.ts._pages.nameAlreadyExists,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (pageId) {
|
||||
options.pageId = pageId;
|
||||
os.api('pages/update', options)
|
||||
.then(page => {
|
||||
currentName = name.trim();
|
||||
os.alert({
|
||||
type: 'success',
|
||||
text: i18n.ts._pages.updated,
|
||||
});
|
||||
}).catch(onError);
|
||||
} else {
|
||||
os.api('pages/create', options)
|
||||
.then(created => {
|
||||
pageId = created.id;
|
||||
currentName = name.trim();
|
||||
os.alert({
|
||||
type: 'success',
|
||||
text: i18n.ts._pages.created,
|
||||
});
|
||||
mainRouter.push(`/pages/edit/${pageId}`);
|
||||
}).catch(onError);
|
||||
}
|
||||
}
|
||||
|
||||
function del() {
|
||||
os.confirm({
|
||||
type: 'warning',
|
||||
text: i18n.t('removeAreYouSure', { x: title.trim() }),
|
||||
}).then(({ canceled }) => {
|
||||
if (canceled) return;
|
||||
os.api('pages/delete', {
|
||||
pageId,
|
||||
}).then(() => {
|
||||
os.alert({
|
||||
type: 'success',
|
||||
text: i18n.ts._pages.deleted,
|
||||
});
|
||||
mainRouter.push('/pages');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function duplicate() {
|
||||
title = title + ' - copy';
|
||||
name = name + '-copy';
|
||||
os.api('pages/create', getSaveOptions()).then(created => {
|
||||
pageId = created.id;
|
||||
currentName = name.trim();
|
||||
os.alert({
|
||||
type: 'success',
|
||||
text: i18n.ts._pages.created,
|
||||
});
|
||||
mainRouter.push(`/pages/edit/${pageId}`);
|
||||
});
|
||||
}
|
||||
|
||||
async function add() {
|
||||
const { canceled, result: type } = await os.select({
|
||||
type: null,
|
||||
title: i18n.ts._pages.chooseBlock,
|
||||
groupedItems: getPageBlockList(),
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
const id = uuid();
|
||||
content.push({ id, type });
|
||||
}
|
||||
|
||||
async function addVariable() {
|
||||
let { canceled, result: name } = await os.inputText({
|
||||
title: i18n.ts._pages.enterVariableName,
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
name = name.trim();
|
||||
|
||||
if (hpml.isUsedName(name)) {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
text: i18n.ts._pages.variableNameIsAlreadyUsed,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const id = uuid();
|
||||
variables.push({ id, name, type: null });
|
||||
}
|
||||
|
||||
function removeVariable(v) {
|
||||
variables = variables.filter(x => x.name !== v.name);
|
||||
}
|
||||
|
||||
function getPageBlockList() {
|
||||
return [{
|
||||
label: i18n.ts._pages.contentBlocks,
|
||||
items: [
|
||||
{ value: 'section', text: i18n.ts._pages.blocks.section },
|
||||
{ value: 'text', text: i18n.ts._pages.blocks.text },
|
||||
{ value: 'image', text: i18n.ts._pages.blocks.image },
|
||||
{ value: 'textarea', text: i18n.ts._pages.blocks.textarea },
|
||||
{ value: 'note', text: i18n.ts._pages.blocks.note },
|
||||
{ value: 'canvas', text: i18n.ts._pages.blocks.canvas },
|
||||
],
|
||||
}, {
|
||||
label: i18n.ts._pages.inputBlocks,
|
||||
items: [
|
||||
{ value: 'button', text: i18n.ts._pages.blocks.button },
|
||||
{ value: 'radioButton', text: i18n.ts._pages.blocks.radioButton },
|
||||
{ value: 'textInput', text: i18n.ts._pages.blocks.textInput },
|
||||
{ value: 'textareaInput', text: i18n.ts._pages.blocks.textareaInput },
|
||||
{ value: 'numberInput', text: i18n.ts._pages.blocks.numberInput },
|
||||
{ value: 'switch', text: i18n.ts._pages.blocks.switch },
|
||||
{ value: 'counter', text: i18n.ts._pages.blocks.counter },
|
||||
],
|
||||
}, {
|
||||
label: i18n.ts._pages.specialBlocks,
|
||||
items: [
|
||||
{ value: 'if', text: i18n.ts._pages.blocks.if },
|
||||
{ value: 'post', text: i18n.ts._pages.blocks.post },
|
||||
],
|
||||
}];
|
||||
}
|
||||
|
||||
function getScriptBlockList(type: string = null) {
|
||||
const list = [];
|
||||
|
||||
const blocks = blockDefs.filter(block => type == null || block.out == null || block.out === type || typeof block.out === 'number');
|
||||
|
||||
for (const block of blocks) {
|
||||
const category = list.find(x => x.category === block.category);
|
||||
if (category) {
|
||||
category.items.push({
|
||||
value: block.type,
|
||||
text: i18n.t(`_pages.script.blocks.${block.type}`),
|
||||
});
|
||||
} else {
|
||||
list.push({
|
||||
category: block.category,
|
||||
label: i18n.t(`_pages.script.categories.${block.category}`),
|
||||
items: [{
|
||||
value: block.type,
|
||||
text: i18n.t(`_pages.script.blocks.${block.type}`),
|
||||
}],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const userFns = variables.filter(x => x.type === 'fn');
|
||||
if (userFns.length > 0) {
|
||||
list.unshift({
|
||||
label: i18n.t('_pages.script.categories.fn'),
|
||||
items: userFns.map(v => ({
|
||||
value: 'fn:' + v.name,
|
||||
text: v.name,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
function setEyeCatchingImage(evt) {
|
||||
selectFile(evt.currentTarget ?? evt.target, null).then(file => {
|
||||
eyeCatchingImageId = file.id;
|
||||
});
|
||||
}
|
||||
|
||||
function removeEyeCatchingImage() {
|
||||
eyeCatchingImageId = null;
|
||||
}
|
||||
|
||||
function highlighter(code) {
|
||||
return highlight(code, languages.js, 'javascript');
|
||||
}
|
||||
|
||||
async function init() {
|
||||
hpml = new HpmlTypeChecker();
|
||||
|
||||
watch($$(variables), () => {
|
||||
hpml.variables = variables;
|
||||
}, { deep: true });
|
||||
|
||||
watch($$(content), () => {
|
||||
hpml.pageVars = collectPageVars(content);
|
||||
}, { deep: true });
|
||||
|
||||
if (props.initPageId) {
|
||||
page = await os.api('pages/show', {
|
||||
pageId: props.initPageId,
|
||||
});
|
||||
} else if (props.initPageName && props.initUser) {
|
||||
page = await os.api('pages/show', {
|
||||
name: props.initPageName,
|
||||
username: props.initUser,
|
||||
});
|
||||
readonly = true;
|
||||
}
|
||||
|
||||
if (page) {
|
||||
author = page.user;
|
||||
pageId = page.id;
|
||||
title = page.title;
|
||||
name = page.name;
|
||||
currentName = page.name;
|
||||
summary = page.summary;
|
||||
font = page.font;
|
||||
script = page.script;
|
||||
hideTitleWhenPinned = page.hideTitleWhenPinned;
|
||||
alignCenter = page.alignCenter;
|
||||
content = page.content;
|
||||
variables = page.variables;
|
||||
eyeCatchingImageId = page.eyeCatchingImageId;
|
||||
} else {
|
||||
const id = uuid();
|
||||
content = [{
|
||||
id,
|
||||
type: 'text',
|
||||
text: 'Hello World!',
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => [{
|
||||
key: 'settings',
|
||||
title: i18n.ts._pages.pageSetting,
|
||||
icon: 'fas fa-cog',
|
||||
}, {
|
||||
key: 'contents',
|
||||
title: i18n.ts._pages.contents,
|
||||
icon: 'fas fa-sticky-note',
|
||||
}, {
|
||||
key: 'variables',
|
||||
title: i18n.ts._pages.variables,
|
||||
icon: 'fas fa-magic',
|
||||
}, {
|
||||
key: 'script',
|
||||
title: i18n.ts.script,
|
||||
icon: 'fas fa-code',
|
||||
}]);
|
||||
|
||||
definePageMetadata(computed(() => {
|
||||
let title = i18n.ts._pages.newPage;
|
||||
if (props.initPageId) {
|
||||
title = i18n.ts._pages.editPage;
|
||||
}
|
||||
else if (props.initPageName && props.initUser) {
|
||||
title = i18n.ts._pages.readPage;
|
||||
}
|
||||
return {
|
||||
title,
|
||||
icon: 'fas fa-pencil-alt',
|
||||
};
|
||||
}));
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.jqqmcavi {
|
||||
> .button {
|
||||
& + .button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gwbmwxkm {
|
||||
position: relative;
|
||||
|
||||
> header {
|
||||
> .title {
|
||||
z-index: 1;
|
||||
margin: 0;
|
||||
padding: 0 16px;
|
||||
line-height: 42px;
|
||||
font-size: 0.9em;
|
||||
font-weight: bold;
|
||||
box-shadow: 0 1px rgba(#000, 0.07);
|
||||
|
||||
> i {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
> .buttons {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
> button {
|
||||
padding: 0;
|
||||
width: 42px;
|
||||
font-size: 0.9em;
|
||||
line-height: 42px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> section {
|
||||
padding: 0 32px 32px 32px;
|
||||
|
||||
@media (max-width: 500px) {
|
||||
padding: 0 16px 16px 16px;
|
||||
}
|
||||
|
||||
> .view {
|
||||
display: inline-block;
|
||||
margin: 16px 0 0 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
> .content {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
> .eyeCatch {
|
||||
margin-bottom: 16px;
|
||||
|
||||
> div {
|
||||
> img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.qmuvgica {
|
||||
padding: 16px;
|
||||
|
||||
> .variables {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
> .add {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,15 +1,20 @@
|
|||
<template>
|
||||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader/></template>
|
||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||
<MkSpacer :content-max="700">
|
||||
<transition :name="$store.state.animation ? 'fade' : ''" mode="out-in">
|
||||
<div v-if="page" :key="page.id" v-size="{ max: [450] }" class="xcukqgmh">
|
||||
<div class="_block main">
|
||||
<!--
|
||||
<div class="header">
|
||||
<h1>{{ page.title }}</h1>
|
||||
</div>
|
||||
-->
|
||||
<div class="banner">
|
||||
<img v-if="page.eyeCatchingImageId" :src="page.eyeCatchingImage.url"/>
|
||||
</div>
|
||||
<div class="content" :class="{ center: page.alignCenter, serif: page.font === 'serif' }">
|
||||
<Mfm :text="page.text" :is-note="false"/>
|
||||
<div class="content">
|
||||
<XPage :page="page"/>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<div class="like">
|
||||
|
@ -58,6 +63,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import XPage from '@/components/page/page.vue';
|
||||
import MkButton from '@/components/ui/button.vue';
|
||||
import * as os from '@/os';
|
||||
import { url } from '@/config';
|
||||
|
@ -190,16 +196,6 @@ definePageMetadata(computed(() => page ? {
|
|||
> .content {
|
||||
margin-top: 1em;
|
||||
padding: 1em;
|
||||
|
||||
&.serif {
|
||||
> div {
|
||||
font-family: serif;
|
||||
}
|
||||
}
|
||||
|
||||
&.center {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
> .actions {
|
||||
|
|
|
@ -12,7 +12,7 @@ const page = (loader: AsyncComponentLoader<any>) => defineAsyncComponent({
|
|||
|
||||
export const routes = [{
|
||||
path: '/@:initUser/pages/:initPageName/view-source',
|
||||
component: page(() => import('./pages/page-editor.vue')),
|
||||
component: page(() => import('./pages/page-editor/page-editor.vue')),
|
||||
}, {
|
||||
path: '/@:username/pages/:pageName',
|
||||
component: page(() => import('./pages/page.vue')),
|
||||
|
@ -121,11 +121,11 @@ export const routes = [{
|
|||
component: page(() => import('./pages/tag.vue')),
|
||||
}, {
|
||||
path: '/pages/new',
|
||||
component: page(() => import('./pages/page-editor.vue')),
|
||||
component: page(() => import('./pages/page-editor/page-editor.vue')),
|
||||
loginRequired: true,
|
||||
}, {
|
||||
path: '/pages/edit/:initPageId',
|
||||
component: page(() => import('./pages/page-editor.vue')),
|
||||
component: page(() => import('./pages/page-editor/page-editor.vue')),
|
||||
loginRequired: true,
|
||||
}, {
|
||||
path: '/pages',
|
||||
|
|
48
packages/client/src/scripts/collect-page-vars.ts
Normal file
48
packages/client/src/scripts/collect-page-vars.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
export function collectPageVars(content) {
|
||||
const pageVars = [];
|
||||
const collect = (xs: any[]) => {
|
||||
for (const x of xs) {
|
||||
if (x.type === 'textInput') {
|
||||
pageVars.push({
|
||||
name: x.name,
|
||||
type: 'string',
|
||||
value: x.default || '',
|
||||
});
|
||||
} else if (x.type === 'textareaInput') {
|
||||
pageVars.push({
|
||||
name: x.name,
|
||||
type: 'string',
|
||||
value: x.default || '',
|
||||
});
|
||||
} else if (x.type === 'numberInput') {
|
||||
pageVars.push({
|
||||
name: x.name,
|
||||
type: 'number',
|
||||
value: x.default || 0,
|
||||
});
|
||||
} else if (x.type === 'switch') {
|
||||
pageVars.push({
|
||||
name: x.name,
|
||||
type: 'boolean',
|
||||
value: x.default || false,
|
||||
});
|
||||
} else if (x.type === 'counter') {
|
||||
pageVars.push({
|
||||
name: x.name,
|
||||
type: 'number',
|
||||
value: 0,
|
||||
});
|
||||
} else if (x.type === 'radioButton') {
|
||||
pageVars.push({
|
||||
name: x.name,
|
||||
type: 'string',
|
||||
value: x.default || '',
|
||||
});
|
||||
} else if (x.children) {
|
||||
collect(x.children);
|
||||
}
|
||||
}
|
||||
};
|
||||
collect(content);
|
||||
return pageVars;
|
||||
}
|
|
@ -157,6 +157,19 @@ export function getNoteMenu(props: {
|
|||
props.isDeleted.value = true;
|
||||
}
|
||||
|
||||
async function promote(): Promise<void> {
|
||||
const { canceled, result: days } = await os.inputNumber({
|
||||
title: i18n.ts.numberOfDays,
|
||||
});
|
||||
|
||||
if (canceled) return;
|
||||
|
||||
os.apiWithDialog('admin/promo/create', {
|
||||
noteId: appearNote.id,
|
||||
expiresAt: Date.now() + (86400000 * days),
|
||||
});
|
||||
}
|
||||
|
||||
function share(): void {
|
||||
navigator.share({
|
||||
title: i18n.t('noteOf', { user: appearNote.user.name }),
|
||||
|
@ -258,6 +271,16 @@ export function getNoteMenu(props: {
|
|||
text: i18n.ts.pin,
|
||||
action: () => togglePin(true),
|
||||
} : undefined,
|
||||
/*
|
||||
...($i.isModerator || $i.isAdmin ? [
|
||||
null,
|
||||
{
|
||||
icon: 'fas fa-bullhorn',
|
||||
text: i18n.ts.promote,
|
||||
action: promote
|
||||
}]
|
||||
: []
|
||||
),*/
|
||||
...(appearNote.userId !== $i.id ? [
|
||||
null,
|
||||
{
|
||||
|
|
109
packages/client/src/scripts/hpml/block.ts
Normal file
109
packages/client/src/scripts/hpml/block.ts
Normal file
|
@ -0,0 +1,109 @@
|
|||
// blocks
|
||||
|
||||
export type BlockBase = {
|
||||
id: string;
|
||||
type: string;
|
||||
};
|
||||
|
||||
export type TextBlock = BlockBase & {
|
||||
type: 'text';
|
||||
text: string;
|
||||
};
|
||||
|
||||
export type SectionBlock = BlockBase & {
|
||||
type: 'section';
|
||||
title: string;
|
||||
children: (Block | VarBlock)[];
|
||||
};
|
||||
|
||||
export type ImageBlock = BlockBase & {
|
||||
type: 'image';
|
||||
fileId: string | null;
|
||||
};
|
||||
|
||||
export type ButtonBlock = BlockBase & {
|
||||
type: 'button';
|
||||
text: any;
|
||||
primary: boolean;
|
||||
action: string;
|
||||
content: string;
|
||||
event: string;
|
||||
message: string;
|
||||
var: string;
|
||||
fn: string;
|
||||
};
|
||||
|
||||
export type IfBlock = BlockBase & {
|
||||
type: 'if';
|
||||
var: string;
|
||||
children: Block[];
|
||||
};
|
||||
|
||||
export type TextareaBlock = BlockBase & {
|
||||
type: 'textarea';
|
||||
text: string;
|
||||
};
|
||||
|
||||
export type PostBlock = BlockBase & {
|
||||
type: 'post';
|
||||
text: string;
|
||||
attachCanvasImage: boolean;
|
||||
canvasId: string;
|
||||
};
|
||||
|
||||
export type CanvasBlock = BlockBase & {
|
||||
type: 'canvas';
|
||||
name: string; // canvas id
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
|
||||
export type NoteBlock = BlockBase & {
|
||||
type: 'note';
|
||||
detailed: boolean;
|
||||
note: string | null;
|
||||
};
|
||||
|
||||
export type Block =
|
||||
TextBlock | SectionBlock | ImageBlock | ButtonBlock | IfBlock | TextareaBlock | PostBlock | CanvasBlock | NoteBlock | VarBlock;
|
||||
|
||||
// variable blocks
|
||||
|
||||
export type VarBlockBase = BlockBase & {
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type NumberInputVarBlock = VarBlockBase & {
|
||||
type: 'numberInput';
|
||||
text: string;
|
||||
};
|
||||
|
||||
export type TextInputVarBlock = VarBlockBase & {
|
||||
type: 'textInput';
|
||||
text: string;
|
||||
};
|
||||
|
||||
export type SwitchVarBlock = VarBlockBase & {
|
||||
type: 'switch';
|
||||
text: string;
|
||||
};
|
||||
|
||||
export type RadioButtonVarBlock = VarBlockBase & {
|
||||
type: 'radioButton';
|
||||
title: string;
|
||||
values: string[];
|
||||
};
|
||||
|
||||
export type CounterVarBlock = VarBlockBase & {
|
||||
type: 'counter';
|
||||
text: string;
|
||||
inc: number;
|
||||
};
|
||||
|
||||
export type VarBlock =
|
||||
NumberInputVarBlock | TextInputVarBlock | SwitchVarBlock | RadioButtonVarBlock | CounterVarBlock;
|
||||
|
||||
const varBlock = ['numberInput', 'textInput', 'switch', 'radioButton', 'counter'];
|
||||
export function isVarBlock(block: Block): block is VarBlock {
|
||||
return varBlock.includes(block.type);
|
||||
}
|
232
packages/client/src/scripts/hpml/evaluator.ts
Normal file
232
packages/client/src/scripts/hpml/evaluator.ts
Normal file
|
@ -0,0 +1,232 @@
|
|||
import autobind from 'autobind-decorator';
|
||||
import { AiScript, utils, values } from '@syuilo/aiscript';
|
||||
import { markRaw, ref, Ref, unref } from 'vue';
|
||||
import { createAiScriptEnv } from '../aiscript/api';
|
||||
import { collectPageVars } from '../collect-page-vars';
|
||||
import { initHpmlLib, initAiLib } from './lib';
|
||||
import { Expr, isLiteralValue, Variable } from './expr';
|
||||
import { PageVar, envVarsDef, Fn, HpmlScope, HpmlError } from '.';
|
||||
import { version } from '@/config';
|
||||
import * as os from '@/os';
|
||||
|
||||
/**
|
||||
* Hpml evaluator
|
||||
*/
|
||||
export class Hpml {
|
||||
private variables: Variable[];
|
||||
private pageVars: PageVar[];
|
||||
private envVars: Record<keyof typeof envVarsDef, any>;
|
||||
public aiscript?: AiScript;
|
||||
public pageVarUpdatedCallback?: values.VFn;
|
||||
public canvases: Record<string, HTMLCanvasElement> = {};
|
||||
public vars: Ref<Record<string, any>> = ref({});
|
||||
public page: Record<string, any>;
|
||||
|
||||
private opts: {
|
||||
randomSeed: string; visitor?: any; url?: string;
|
||||
enableAiScript: boolean;
|
||||
};
|
||||
|
||||
constructor(page: Hpml['page'], opts: Hpml['opts']) {
|
||||
this.page = page;
|
||||
this.variables = this.page.variables;
|
||||
this.pageVars = collectPageVars(this.page.content);
|
||||
this.opts = opts;
|
||||
|
||||
if (this.opts.enableAiScript) {
|
||||
this.aiscript = markRaw(new AiScript({ ...createAiScriptEnv({
|
||||
storageKey: 'pages:' + this.page.id,
|
||||
}), ...initAiLib(this) }, {
|
||||
in: (q) => {
|
||||
return new Promise(ok => {
|
||||
os.inputText({
|
||||
title: q,
|
||||
}).then(({ canceled, result: a }) => {
|
||||
ok(a);
|
||||
});
|
||||
});
|
||||
},
|
||||
out: (value) => {
|
||||
console.log(value);
|
||||
},
|
||||
log: (type, params) => {
|
||||
},
|
||||
}));
|
||||
|
||||
this.aiscript.scope.opts.onUpdated = (name, value) => {
|
||||
this.eval();
|
||||
};
|
||||
}
|
||||
|
||||
const date = new Date();
|
||||
|
||||
this.envVars = {
|
||||
AI: 'kawaii',
|
||||
VERSION: version,
|
||||
URL: this.page ? `${opts.url}/@${this.page.user.username}/pages/${this.page.name}` : '',
|
||||
LOGIN: opts.visitor != null,
|
||||
NAME: opts.visitor ? opts.visitor.name || opts.visitor.username : '',
|
||||
USERNAME: opts.visitor ? opts.visitor.username : '',
|
||||
USERID: opts.visitor ? opts.visitor.id : '',
|
||||
NOTES_COUNT: opts.visitor ? opts.visitor.notesCount : 0,
|
||||
FOLLOWERS_COUNT: opts.visitor ? opts.visitor.followersCount : 0,
|
||||
FOLLOWING_COUNT: opts.visitor ? opts.visitor.followingCount : 0,
|
||||
IS_CAT: opts.visitor ? opts.visitor.isCat : false,
|
||||
SEED: opts.randomSeed ? opts.randomSeed : '',
|
||||
YMD: `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`,
|
||||
AISCRIPT_DISABLED: !this.opts.enableAiScript,
|
||||
NULL: null,
|
||||
};
|
||||
|
||||
this.eval();
|
||||
}
|
||||
|
||||
@autobind
|
||||
public eval() {
|
||||
try {
|
||||
this.vars.value = this.evaluateVars();
|
||||
} catch (err) {
|
||||
//this.onError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@autobind
|
||||
public interpolate(str: string) {
|
||||
if (str == null) return null;
|
||||
return str.replace(/{(.+?)}/g, match => {
|
||||
const v = unref(this.vars)[match.slice(1, -1).trim()];
|
||||
return v == null ? 'NULL' : v.toString();
|
||||
});
|
||||
}
|
||||
|
||||
@autobind
|
||||
public callAiScript(fn: string) {
|
||||
try {
|
||||
if (this.aiscript) this.aiscript.execFn(this.aiscript.scope.get(fn), []);
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
@autobind
|
||||
public registerCanvas(id: string, canvas: any) {
|
||||
this.canvases[id] = canvas;
|
||||
}
|
||||
|
||||
@autobind
|
||||
public updatePageVar(name: string, value: any) {
|
||||
const pageVar = this.pageVars.find(v => v.name === name);
|
||||
if (pageVar !== undefined) {
|
||||
pageVar.value = value;
|
||||
if (this.pageVarUpdatedCallback) {
|
||||
if (this.aiscript) this.aiscript.execFn(this.pageVarUpdatedCallback, [values.STR(name), utils.jsToVal(value)]);
|
||||
}
|
||||
} else {
|
||||
throw new HpmlError(`No such page var '${name}'`);
|
||||
}
|
||||
}
|
||||
|
||||
@autobind
|
||||
public updateRandomSeed(seed: string) {
|
||||
this.opts.randomSeed = seed;
|
||||
this.envVars.SEED = seed;
|
||||
}
|
||||
|
||||
@autobind
|
||||
private _interpolateScope(str: string, scope: HpmlScope) {
|
||||
return str.replace(/{(.+?)}/g, match => {
|
||||
const v = scope.getState(match.slice(1, -1).trim());
|
||||
return v == null ? 'NULL' : v.toString();
|
||||
});
|
||||
}
|
||||
|
||||
@autobind
|
||||
public evaluateVars(): Record<string, any> {
|
||||
const values: Record<string, any> = {};
|
||||
|
||||
for (const [k, v] of Object.entries(this.envVars)) {
|
||||
values[k] = v;
|
||||
}
|
||||
|
||||
for (const v of this.pageVars) {
|
||||
values[v.name] = v.value;
|
||||
}
|
||||
|
||||
for (const v of this.variables) {
|
||||
values[v.name] = this.evaluate(v, new HpmlScope([values]));
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
@autobind
|
||||
private evaluate(expr: Expr, scope: HpmlScope): any {
|
||||
if (isLiteralValue(expr)) {
|
||||
if (expr.type === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (expr.type === 'number') {
|
||||
return parseInt((expr.value as any), 10);
|
||||
}
|
||||
|
||||
if (expr.type === 'text' || expr.type === 'multiLineText') {
|
||||
return this._interpolateScope(expr.value || '', scope);
|
||||
}
|
||||
|
||||
if (expr.type === 'textList') {
|
||||
return this._interpolateScope(expr.value || '', scope).trim().split('\n');
|
||||
}
|
||||
|
||||
if (expr.type === 'ref') {
|
||||
return scope.getState(expr.value);
|
||||
}
|
||||
|
||||
if (expr.type === 'aiScriptVar') {
|
||||
if (this.aiscript) {
|
||||
try {
|
||||
return utils.valToJs(this.aiscript.scope.get(expr.value));
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Define user function
|
||||
if (expr.type === 'fn') {
|
||||
return {
|
||||
slots: expr.value.slots.map(x => x.name),
|
||||
exec: (slotArg: Record<string, any>) => {
|
||||
return this.evaluate(expr.value.expression, scope.createChildScope(slotArg, expr.id));
|
||||
},
|
||||
} as Fn;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Call user function
|
||||
if (expr.type.startsWith('fn:')) {
|
||||
const fnName = expr.type.split(':')[1];
|
||||
const fn = scope.getState(fnName);
|
||||
const args = {} as Record<string, any>;
|
||||
for (let i = 0; i < fn.slots.length; i++) {
|
||||
const name = fn.slots[i];
|
||||
args[name] = this.evaluate(expr.args[i], scope);
|
||||
}
|
||||
return fn.exec(args);
|
||||
}
|
||||
|
||||
if (expr.args === undefined) return null;
|
||||
|
||||
const funcs = initHpmlLib(expr, scope, this.opts.randomSeed, this.opts.visitor);
|
||||
|
||||
// Call function
|
||||
const fnName = expr.type;
|
||||
const fn = (funcs as any)[fnName];
|
||||
if (fn == null) {
|
||||
throw new HpmlError(`No such function '${fnName}'`);
|
||||
} else {
|
||||
return fn(...expr.args.map(x => this.evaluate(x, scope)));
|
||||
}
|
||||
}
|
||||
}
|
79
packages/client/src/scripts/hpml/expr.ts
Normal file
79
packages/client/src/scripts/hpml/expr.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
import { literalDefs, Type } from '.';
|
||||
|
||||
export type ExprBase = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
// value
|
||||
|
||||
export type EmptyValue = ExprBase & {
|
||||
type: null;
|
||||
value: null;
|
||||
};
|
||||
|
||||
export type TextValue = ExprBase & {
|
||||
type: 'text';
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type MultiLineTextValue = ExprBase & {
|
||||
type: 'multiLineText';
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type TextListValue = ExprBase & {
|
||||
type: 'textList';
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type NumberValue = ExprBase & {
|
||||
type: 'number';
|
||||
value: number;
|
||||
};
|
||||
|
||||
export type RefValue = ExprBase & {
|
||||
type: 'ref';
|
||||
value: string; // value is variable name
|
||||
};
|
||||
|
||||
export type AiScriptRefValue = ExprBase & {
|
||||
type: 'aiScriptVar';
|
||||
value: string; // value is variable name
|
||||
};
|
||||
|
||||
export type UserFnValue = ExprBase & {
|
||||
type: 'fn';
|
||||
value: UserFnInnerValue;
|
||||
};
|
||||
type UserFnInnerValue = {
|
||||
slots: {
|
||||
name: string;
|
||||
type: Type;
|
||||
}[];
|
||||
expression: Expr;
|
||||
};
|
||||
|
||||
export type Value =
|
||||
EmptyValue | TextValue | MultiLineTextValue | TextListValue | NumberValue | RefValue | AiScriptRefValue | UserFnValue;
|
||||
|
||||
export function isLiteralValue(expr: Expr): expr is Value {
|
||||
if (expr.type == null) return true;
|
||||
if (literalDefs[expr.type]) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// call function
|
||||
|
||||
export type CallFn = ExprBase & { // "fn:hoge" or string
|
||||
type: string;
|
||||
args: Expr[];
|
||||
value: null;
|
||||
};
|
||||
|
||||
// variable
|
||||
export type Variable = (Value | CallFn) & {
|
||||
name: string;
|
||||
};
|
||||
|
||||
// expression
|
||||
export type Expr = Variable | Value | CallFn;
|
103
packages/client/src/scripts/hpml/index.ts
Normal file
103
packages/client/src/scripts/hpml/index.ts
Normal file
|
@ -0,0 +1,103 @@
|
|||
/**
|
||||
* Hpml
|
||||
*/
|
||||
|
||||
import autobind from 'autobind-decorator';
|
||||
import { Hpml } from './evaluator';
|
||||
import { funcDefs } from './lib';
|
||||
|
||||
export type Fn = {
|
||||
slots: string[];
|
||||
exec: (args: Record<string, any>) => ReturnType<Hpml['evaluate']>;
|
||||
};
|
||||
|
||||
export type Type = 'string' | 'number' | 'boolean' | 'stringArray' | null;
|
||||
|
||||
export const literalDefs: Record<string, { out: any; category: string; icon: any; }> = {
|
||||
text: { out: 'string', category: 'value', icon: 'fas fa-quote-right' },
|
||||
multiLineText: { out: 'string', category: 'value', icon: 'fas fa-align-left' },
|
||||
textList: { out: 'stringArray', category: 'value', icon: 'fas fa-list' },
|
||||
number: { out: 'number', category: 'value', icon: 'fas fa-sort-numeric-up' },
|
||||
ref: { out: null, category: 'value', icon: 'fas fa-magic' },
|
||||
aiScriptVar: { out: null, category: 'value', icon: 'fas fa-magic' },
|
||||
fn: { out: 'function', category: 'value', icon: 'fas fa-square-root-alt' },
|
||||
};
|
||||
|
||||
export const blockDefs = [
|
||||
...Object.entries(literalDefs).map(([k, v]) => ({
|
||||
type: k, out: v.out, category: v.category, icon: v.icon,
|
||||
})),
|
||||
...Object.entries(funcDefs).map(([k, v]) => ({
|
||||
type: k, out: v.out, category: v.category, icon: v.icon,
|
||||
})),
|
||||
];
|
||||
|
||||
export type PageVar = { name: string; value: any; type: Type; };
|
||||
|
||||
export const envVarsDef: Record<string, Type> = {
|
||||
AI: 'string',
|
||||
URL: 'string',
|
||||
VERSION: 'string',
|
||||
LOGIN: 'boolean',
|
||||
NAME: 'string',
|
||||
USERNAME: 'string',
|
||||
USERID: 'string',
|
||||
NOTES_COUNT: 'number',
|
||||
FOLLOWERS_COUNT: 'number',
|
||||
FOLLOWING_COUNT: 'number',
|
||||
IS_CAT: 'boolean',
|
||||
SEED: null,
|
||||
YMD: 'string',
|
||||
AISCRIPT_DISABLED: 'boolean',
|
||||
NULL: null,
|
||||
};
|
||||
|
||||
export class HpmlScope {
|
||||
private layerdStates: Record<string, any>[];
|
||||
public name: string;
|
||||
|
||||
constructor(layerdStates: HpmlScope['layerdStates'], name?: HpmlScope['name']) {
|
||||
this.layerdStates = layerdStates;
|
||||
this.name = name || 'anonymous';
|
||||
}
|
||||
|
||||
@autobind
|
||||
public createChildScope(states: Record<string, any>, name?: HpmlScope['name']): HpmlScope {
|
||||
const layer = [states, ...this.layerdStates];
|
||||
return new HpmlScope(layer, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定した名前の変数の値を取得します
|
||||
* @param name 変数名
|
||||
*/
|
||||
@autobind
|
||||
public getState(name: string): any {
|
||||
for (const later of this.layerdStates) {
|
||||
const state = later[name];
|
||||
if (state !== undefined) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
throw new HpmlError(
|
||||
`No such variable '${name}' in scope '${this.name}'`, {
|
||||
scope: this.layerdStates,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class HpmlError extends Error {
|
||||
public info?: any;
|
||||
|
||||
constructor(message: string, info?: any) {
|
||||
super(message);
|
||||
|
||||
this.info = info;
|
||||
|
||||
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, HpmlError);
|
||||
}
|
||||
}
|
||||
}
|
247
packages/client/src/scripts/hpml/lib.ts
Normal file
247
packages/client/src/scripts/hpml/lib.ts
Normal file
|
@ -0,0 +1,247 @@
|
|||
import tinycolor from 'tinycolor2';
|
||||
import { values, utils } from '@syuilo/aiscript';
|
||||
import seedrandom from 'seedrandom';
|
||||
import { Hpml } from './evaluator';
|
||||
import { Expr } from './expr';
|
||||
import { Fn, HpmlScope } from '.';
|
||||
|
||||
/* TODO: https://www.chartjs.org/docs/latest/configuration/canvas-background.html#color
|
||||
// https://stackoverflow.com/questions/38493564/chart-area-background-color-chartjs
|
||||
Chart.pluginService.register({
|
||||
beforeDraw: (chart, easing) => {
|
||||
if (chart.config.options.chartArea && chart.config.options.chartArea.backgroundColor) {
|
||||
const ctx = chart.chart.ctx;
|
||||
ctx.save();
|
||||
ctx.fillStyle = chart.config.options.chartArea.backgroundColor;
|
||||
ctx.fillRect(0, 0, chart.chart.width, chart.chart.height);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
export function initAiLib(hpml: Hpml) {
|
||||
return {
|
||||
'MkPages:updated': values.FN_NATIVE(([callback]) => {
|
||||
hpml.pageVarUpdatedCallback = (callback as values.VFn);
|
||||
}),
|
||||
'MkPages:get_canvas': values.FN_NATIVE(([id]) => {
|
||||
utils.assertString(id);
|
||||
const canvas = hpml.canvases[id.value];
|
||||
const ctx = canvas.getContext('2d');
|
||||
return values.OBJ(new Map([
|
||||
['clear_rect', values.FN_NATIVE(([x, y, width, height]) => { ctx.clearRect(x.value, y.value, width.value, height.value); })],
|
||||
['fill_rect', values.FN_NATIVE(([x, y, width, height]) => { ctx.fillRect(x.value, y.value, width.value, height.value); })],
|
||||
['stroke_rect', values.FN_NATIVE(([x, y, width, height]) => { ctx.strokeRect(x.value, y.value, width.value, height.value); })],
|
||||
['fill_text', values.FN_NATIVE(([text, x, y, width]) => { ctx.fillText(text.value, x.value, y.value, width ? width.value : undefined); })],
|
||||
['stroke_text', values.FN_NATIVE(([text, x, y, width]) => { ctx.strokeText(text.value, x.value, y.value, width ? width.value : undefined); })],
|
||||
['set_line_width', values.FN_NATIVE(([width]) => { ctx.lineWidth = width.value; })],
|
||||
['set_font', values.FN_NATIVE(([font]) => { ctx.font = font.value; })],
|
||||
['set_fill_style', values.FN_NATIVE(([style]) => { ctx.fillStyle = style.value; })],
|
||||
['set_stroke_style', values.FN_NATIVE(([style]) => { ctx.strokeStyle = style.value; })],
|
||||
['begin_path', values.FN_NATIVE(() => { ctx.beginPath(); })],
|
||||
['close_path', values.FN_NATIVE(() => { ctx.closePath(); })],
|
||||
['move_to', values.FN_NATIVE(([x, y]) => { ctx.moveTo(x.value, y.value); })],
|
||||
['line_to', values.FN_NATIVE(([x, y]) => { ctx.lineTo(x.value, y.value); })],
|
||||
['arc', values.FN_NATIVE(([x, y, radius, startAngle, endAngle]) => { ctx.arc(x.value, y.value, radius.value, startAngle.value, endAngle.value); })],
|
||||
['rect', values.FN_NATIVE(([x, y, width, height]) => { ctx.rect(x.value, y.value, width.value, height.value); })],
|
||||
['fill', values.FN_NATIVE(() => { ctx.fill(); })],
|
||||
['stroke', values.FN_NATIVE(() => { ctx.stroke(); })],
|
||||
]));
|
||||
}),
|
||||
'MkPages:chart': values.FN_NATIVE(([id, opts]) => {
|
||||
/* TODO
|
||||
utils.assertString(id);
|
||||
utils.assertObject(opts);
|
||||
const canvas = hpml.canvases[id.value];
|
||||
const color = getComputedStyle(document.documentElement).getPropertyValue('--accent');
|
||||
Chart.defaults.color = '#555';
|
||||
const chart = new Chart(canvas, {
|
||||
type: opts.value.get('type').value,
|
||||
data: {
|
||||
labels: opts.value.get('labels').value.map(x => x.value),
|
||||
datasets: opts.value.get('datasets').value.map(x => ({
|
||||
label: x.value.has('label') ? x.value.get('label').value : '',
|
||||
data: x.value.get('data').value.map(x => x.value),
|
||||
pointRadius: 0,
|
||||
lineTension: 0,
|
||||
borderWidth: 2,
|
||||
borderColor: x.value.has('color') ? x.value.get('color') : color,
|
||||
backgroundColor: tinycolor(x.value.has('color') ? x.value.get('color') : color).setAlpha(0.1).toRgbString(),
|
||||
}))
|
||||
},
|
||||
options: {
|
||||
responsive: false,
|
||||
devicePixelRatio: 1.5,
|
||||
title: {
|
||||
display: opts.value.has('title'),
|
||||
text: opts.value.has('title') ? opts.value.get('title').value : '',
|
||||
fontSize: 14,
|
||||
},
|
||||
layout: {
|
||||
padding: {
|
||||
left: 32,
|
||||
right: 32,
|
||||
top: opts.value.has('title') ? 16 : 32,
|
||||
bottom: 16
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
display: opts.value.get('datasets').value.filter(x => x.value.has('label') && x.value.get('label').value).length === 0 ? false : true,
|
||||
position: 'bottom',
|
||||
labels: {
|
||||
boxWidth: 16,
|
||||
}
|
||||
},
|
||||
tooltips: {
|
||||
enabled: false,
|
||||
},
|
||||
chartArea: {
|
||||
backgroundColor: '#fff'
|
||||
},
|
||||
...(opts.value.get('type').value === 'radar' ? {
|
||||
scale: {
|
||||
ticks: {
|
||||
display: opts.value.has('show_tick_label') ? opts.value.get('show_tick_label').value : false,
|
||||
min: opts.value.has('min') ? opts.value.get('min').value : undefined,
|
||||
max: opts.value.has('max') ? opts.value.get('max').value : undefined,
|
||||
maxTicksLimit: 8,
|
||||
},
|
||||
pointLabels: {
|
||||
fontSize: 12
|
||||
}
|
||||
}
|
||||
} : {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
display: opts.value.has('show_tick_label') ? opts.value.get('show_tick_label').value : true,
|
||||
min: opts.value.has('min') ? opts.value.get('min').value : undefined,
|
||||
max: opts.value.has('max') ? opts.value.get('max').value : undefined,
|
||||
}
|
||||
}]
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
*/
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
export const funcDefs: Record<string, { in: any[]; out: any; category: string; icon: any; }> = {
|
||||
if: { in: ['boolean', 0, 0], out: 0, category: 'flow', icon: 'fas fa-share-alt' },
|
||||
for: { in: ['number', 'function'], out: null, category: 'flow', icon: 'fas fa-recycle' },
|
||||
not: { in: ['boolean'], out: 'boolean', category: 'logical', icon: 'fas fa-flag' },
|
||||
or: { in: ['boolean', 'boolean'], out: 'boolean', category: 'logical', icon: 'fas fa-flag' },
|
||||
and: { in: ['boolean', 'boolean'], out: 'boolean', category: 'logical', icon: 'fas fa-flag' },
|
||||
add: { in: ['number', 'number'], out: 'number', category: 'operation', icon: 'fas fa-plus' },
|
||||
subtract: { in: ['number', 'number'], out: 'number', category: 'operation', icon: 'fas fa-minus' },
|
||||
multiply: { in: ['number', 'number'], out: 'number', category: 'operation', icon: 'fas fa-times' },
|
||||
divide: { in: ['number', 'number'], out: 'number', category: 'operation', icon: 'fas fa-divide' },
|
||||
mod: { in: ['number', 'number'], out: 'number', category: 'operation', icon: 'fas fa-divide' },
|
||||
round: { in: ['number'], out: 'number', category: 'operation', icon: 'fas fa-calculator' },
|
||||
eq: { in: [0, 0], out: 'boolean', category: 'comparison', icon: 'fas fa-equals' },
|
||||
notEq: { in: [0, 0], out: 'boolean', category: 'comparison', icon: 'fas fa-not-equal' },
|
||||
gt: { in: ['number', 'number'], out: 'boolean', category: 'comparison', icon: 'fas fa-greater-than' },
|
||||
lt: { in: ['number', 'number'], out: 'boolean', category: 'comparison', icon: 'fas fa-less-than' },
|
||||
gtEq: { in: ['number', 'number'], out: 'boolean', category: 'comparison', icon: 'fas fa-greater-than-equal' },
|
||||
ltEq: { in: ['number', 'number'], out: 'boolean', category: 'comparison', icon: 'fas fa-less-than-equal' },
|
||||
strLen: { in: ['string'], out: 'number', category: 'text', icon: 'fas fa-quote-right' },
|
||||
strPick: { in: ['string', 'number'], out: 'string', category: 'text', icon: 'fas fa-quote-right' },
|
||||
strReplace: { in: ['string', 'string', 'string'], out: 'string', category: 'text', icon: 'fas fa-quote-right' },
|
||||
strReverse: { in: ['string'], out: 'string', category: 'text', icon: 'fas fa-quote-right' },
|
||||
join: { in: ['stringArray', 'string'], out: 'string', category: 'text', icon: 'fas fa-quote-right' },
|
||||
stringToNumber: { in: ['string'], out: 'number', category: 'convert', icon: 'fas fa-exchange-alt' },
|
||||
numberToString: { in: ['number'], out: 'string', category: 'convert', icon: 'fas fa-exchange-alt' },
|
||||
splitStrByLine: { in: ['string'], out: 'stringArray', category: 'convert', icon: 'fas fa-exchange-alt' },
|
||||
pick: { in: [null, 'number'], out: null, category: 'list', icon: 'fas fa-indent' },
|
||||
listLen: { in: [null], out: 'number', category: 'list', icon: 'fas fa-indent' },
|
||||
rannum: { in: ['number', 'number'], out: 'number', category: 'random', icon: 'fas fa-dice' },
|
||||
dailyRannum: { in: ['number', 'number'], out: 'number', category: 'random', icon: 'fas fa-dice' },
|
||||
seedRannum: { in: [null, 'number', 'number'], out: 'number', category: 'random', icon: 'fas fa-dice' },
|
||||
random: { in: ['number'], out: 'boolean', category: 'random', icon: 'fas fa-dice' },
|
||||
dailyRandom: { in: ['number'], out: 'boolean', category: 'random', icon: 'fas fa-dice' },
|
||||
seedRandom: { in: [null, 'number'], out: 'boolean', category: 'random', icon: 'fas fa-dice' },
|
||||
randomPick: { in: [0], out: 0, category: 'random', icon: 'fas fa-dice' },
|
||||
dailyRandomPick: { in: [0], out: 0, category: 'random', icon: 'fas fa-dice' },
|
||||
seedRandomPick: { in: [null, 0], out: 0, category: 'random', icon: 'fas fa-dice' },
|
||||
DRPWPM: { in: ['stringArray'], out: 'string', category: 'random', icon: 'fas fa-dice' }, // dailyRandomPickWithProbabilityMapping
|
||||
};
|
||||
|
||||
export function initHpmlLib(expr: Expr, scope: HpmlScope, randomSeed: string, visitor?: any) {
|
||||
const date = new Date();
|
||||
const day = `${visitor ? visitor.id : ''} ${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`;
|
||||
|
||||
// SHOULD be fine to ignore since it's intended + function shape isn't defined
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
const funcs: Record<string, Function> = {
|
||||
not: (a: boolean) => !a,
|
||||
or: (a: boolean, b: boolean) => a || b,
|
||||
and: (a: boolean, b: boolean) => a && b,
|
||||
eq: (a: any, b: any) => a === b,
|
||||
notEq: (a: any, b: any) => a !== b,
|
||||
gt: (a: number, b: number) => a > b,
|
||||
lt: (a: number, b: number) => a < b,
|
||||
gtEq: (a: number, b: number) => a >= b,
|
||||
ltEq: (a: number, b: number) => a <= b,
|
||||
if: (bool: boolean, a: any, b: any) => bool ? a : b,
|
||||
for: (times: number, fn: Fn) => {
|
||||
const result: any[] = [];
|
||||
for (let i = 0; i < times; i++) {
|
||||
result.push(fn.exec({
|
||||
[fn.slots[0]]: i + 1,
|
||||
}));
|
||||
}
|
||||
return result;
|
||||
},
|
||||
add: (a: number, b: number) => a + b,
|
||||
subtract: (a: number, b: number) => a - b,
|
||||
multiply: (a: number, b: number) => a * b,
|
||||
divide: (a: number, b: number) => a / b,
|
||||
mod: (a: number, b: number) => a % b,
|
||||
round: (a: number) => Math.round(a),
|
||||
strLen: (a: string) => a.length,
|
||||
strPick: (a: string, b: number) => a[b - 1],
|
||||
strReplace: (a: string, b: string, c: string) => a.split(b).join(c),
|
||||
strReverse: (a: string) => a.split('').reverse().join(''),
|
||||
join: (texts: string[], separator: string) => texts.join(separator || ''),
|
||||
stringToNumber: (a: string) => parseInt(a),
|
||||
numberToString: (a: number) => a.toString(),
|
||||
splitStrByLine: (a: string) => a.split('\n'),
|
||||
pick: (list: any[], i: number) => list[i - 1],
|
||||
listLen: (list: any[]) => list.length,
|
||||
random: (probability: number) => Math.floor(seedrandom(`${randomSeed}:${expr.id}`)() * 100) < probability,
|
||||
rannum: (min: number, max: number) => min + Math.floor(seedrandom(`${randomSeed}:${expr.id}`)() * (max - min + 1)),
|
||||
randomPick: (list: any[]) => list[Math.floor(seedrandom(`${randomSeed}:${expr.id}`)() * list.length)],
|
||||
dailyRandom: (probability: number) => Math.floor(seedrandom(`${day}:${expr.id}`)() * 100) < probability,
|
||||
dailyRannum: (min: number, max: number) => min + Math.floor(seedrandom(`${day}:${expr.id}`)() * (max - min + 1)),
|
||||
dailyRandomPick: (list: any[]) => list[Math.floor(seedrandom(`${day}:${expr.id}`)() * list.length)],
|
||||
seedRandom: (seed: any, probability: number) => Math.floor(seedrandom(seed)() * 100) < probability,
|
||||
seedRannum: (seed: any, min: number, max: number) => min + Math.floor(seedrandom(seed)() * (max - min + 1)),
|
||||
seedRandomPick: (seed: any, list: any[]) => list[Math.floor(seedrandom(seed)() * list.length)],
|
||||
DRPWPM: (list: string[]) => {
|
||||
const xs: any[] = [];
|
||||
let totalFactor = 0;
|
||||
for (const x of list) {
|
||||
const parts = x.split(' ');
|
||||
const factor = parseInt(parts.pop()!, 10);
|
||||
const text = parts.join(' ');
|
||||
totalFactor += factor;
|
||||
xs.push({ factor, text });
|
||||
}
|
||||
const r = seedrandom(`${day}:${expr.id}`)() * totalFactor;
|
||||
let stackedFactor = 0;
|
||||
for (const x of xs) {
|
||||
if (r >= stackedFactor && r <= stackedFactor + x.factor) {
|
||||
return x.text;
|
||||
} else {
|
||||
stackedFactor += x.factor;
|
||||
}
|
||||
}
|
||||
return xs[0].text;
|
||||
},
|
||||
};
|
||||
|
||||
return funcs;
|
||||
}
|
189
packages/client/src/scripts/hpml/type-checker.ts
Normal file
189
packages/client/src/scripts/hpml/type-checker.ts
Normal file
|
@ -0,0 +1,189 @@
|
|||
import autobind from 'autobind-decorator';
|
||||
import { Expr, isLiteralValue, Variable } from './expr';
|
||||
import { funcDefs } from './lib';
|
||||
import { Type, envVarsDef, PageVar } from '.';
|
||||
|
||||
type TypeError = {
|
||||
arg: number;
|
||||
expect: Type;
|
||||
actual: Type;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hpml type checker
|
||||
*/
|
||||
export class HpmlTypeChecker {
|
||||
public variables: Variable[];
|
||||
public pageVars: PageVar[];
|
||||
|
||||
constructor(variables: HpmlTypeChecker['variables'] = [], pageVars: HpmlTypeChecker['pageVars'] = []) {
|
||||
this.variables = variables;
|
||||
this.pageVars = pageVars;
|
||||
}
|
||||
|
||||
@autobind
|
||||
public typeCheck(v: Expr): TypeError | null {
|
||||
if (isLiteralValue(v)) return null;
|
||||
|
||||
const def = funcDefs[v.type || ''];
|
||||
if (def == null) {
|
||||
throw new Error('Unknown type: ' + v.type);
|
||||
}
|
||||
|
||||
const generic: Type[] = [];
|
||||
|
||||
for (let i = 0; i < def.in.length; i++) {
|
||||
const arg = def.in[i];
|
||||
const type = this.infer(v.args[i]);
|
||||
if (type === null) continue;
|
||||
|
||||
if (typeof arg === 'number') {
|
||||
if (generic[arg] === undefined) {
|
||||
generic[arg] = type;
|
||||
} else if (type !== generic[arg]) {
|
||||
return {
|
||||
arg: i,
|
||||
expect: generic[arg],
|
||||
actual: type,
|
||||
};
|
||||
}
|
||||
} else if (type !== arg) {
|
||||
return {
|
||||
arg: i,
|
||||
expect: arg,
|
||||
actual: type,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@autobind
|
||||
public getExpectedType(v: Expr, slot: number): Type {
|
||||
const def = funcDefs[v.type || ''];
|
||||
if (def == null) {
|
||||
throw new Error('Unknown type: ' + v.type);
|
||||
}
|
||||
|
||||
const generic: Type[] = [];
|
||||
|
||||
for (let i = 0; i < def.in.length; i++) {
|
||||
const arg = def.in[i];
|
||||
const type = this.infer(v.args[i]);
|
||||
if (type === null) continue;
|
||||
|
||||
if (typeof arg === 'number') {
|
||||
if (generic[arg] === undefined) {
|
||||
generic[arg] = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof def.in[slot] === 'number') {
|
||||
return generic[def.in[slot]] || null;
|
||||
} else {
|
||||
return def.in[slot];
|
||||
}
|
||||
}
|
||||
|
||||
@autobind
|
||||
public infer(v: Expr): Type {
|
||||
if (v.type === null) return null;
|
||||
if (v.type === 'text') return 'string';
|
||||
if (v.type === 'multiLineText') return 'string';
|
||||
if (v.type === 'textList') return 'stringArray';
|
||||
if (v.type === 'number') return 'number';
|
||||
if (v.type === 'ref') {
|
||||
const variable = this.variables.find(va => va.name === v.value);
|
||||
if (variable) {
|
||||
return this.infer(variable);
|
||||
}
|
||||
|
||||
const pageVar = this.pageVars.find(va => va.name === v.value);
|
||||
if (pageVar) {
|
||||
return pageVar.type;
|
||||
}
|
||||
|
||||
const envVar = envVarsDef[v.value || ''];
|
||||
if (envVar !== undefined) {
|
||||
return envVar;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
if (v.type === 'aiScriptVar') return null;
|
||||
if (v.type === 'fn') return null; // todo
|
||||
if (v.type.startsWith('fn:')) return null; // todo
|
||||
|
||||
const generic: Type[] = [];
|
||||
|
||||
const def = funcDefs[v.type];
|
||||
|
||||
for (let i = 0; i < def.in.length; i++) {
|
||||
const arg = def.in[i];
|
||||
if (typeof arg === 'number') {
|
||||
const type = this.infer(v.args[i]);
|
||||
|
||||
if (generic[arg] === undefined) {
|
||||
generic[arg] = type;
|
||||
} else {
|
||||
if (type !== generic[arg]) {
|
||||
generic[arg] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof def.out === 'number') {
|
||||
return generic[def.out];
|
||||
} else {
|
||||
return def.out;
|
||||
}
|
||||
}
|
||||
|
||||
@autobind
|
||||
public getVarByName(name: string): Variable {
|
||||
const v = this.variables.find(x => x.name === name);
|
||||
if (v !== undefined) {
|
||||
return v;
|
||||
} else {
|
||||
throw new Error(`No such variable '${name}'`);
|
||||
}
|
||||
}
|
||||
|
||||
@autobind
|
||||
public getVarsByType(type: Type): Variable[] {
|
||||
if (type == null) return this.variables;
|
||||
return this.variables.filter(x => (this.infer(x) === null) || (this.infer(x) === type));
|
||||
}
|
||||
|
||||
@autobind
|
||||
public getEnvVarsByType(type: Type): string[] {
|
||||
if (type == null) return Object.keys(envVarsDef);
|
||||
return Object.entries(envVarsDef).filter(([k, v]) => v === null || type === v).map(([k, v]) => k);
|
||||
}
|
||||
|
||||
@autobind
|
||||
public getPageVarsByType(type: Type): string[] {
|
||||
if (type == null) return this.pageVars.map(v => v.name);
|
||||
return this.pageVars.filter(v => type === v.type).map(v => v.name);
|
||||
}
|
||||
|
||||
@autobind
|
||||
public isUsedName(name: string) {
|
||||
if (this.variables.some(v => v.name === name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.pageVars.some(v => v.name === name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (envVarsDef[name]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue