Compare commits

...

3 commits

Author SHA1 Message Date
fef
a62f6983d3
web: add i18n support 2022-12-14 01:02:24 +01:00
fef
aeb51c7cea
web: more layout improvements 2022-12-14 00:49:48 +01:00
fef
077b7ec8fd
web: add bootstrap icons 2022-12-14 00:48:49 +01:00
11 changed files with 449 additions and 17 deletions

242
package-lock.json generated
View file

@ -9,10 +9,13 @@
"version": "0.1.0", "version": "0.1.0",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {
"@lit/localize": "^0.11.4",
"bootstrap-icons": "^1.10.2",
"lit": "^2.4.1", "lit": "^2.4.1",
"redux": "^4.2.0" "redux": "^4.2.0"
}, },
"devDependencies": { "devDependencies": {
"@lit/localize-tools": "^0.6.5",
"@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0", "@typescript-eslint/parser": "^5.45.0",
"@web/dev-server": "^0.1.35", "@web/dev-server": "^0.1.35",
@ -194,6 +197,49 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true "dev": true
}, },
"node_modules/@lit/localize": {
"version": "0.11.4",
"resolved": "https://registry.npmjs.org/@lit/localize/-/localize-0.11.4.tgz",
"integrity": "sha512-RRIwIX2tAm3+DuEndoXSJrFjGrAK5cb5IXo5K6jcJ6sbgD829B8rSqHC5MaKVUmXTVLIR1bk5IZOZDf9wFereA==",
"dependencies": {
"@lit/reactive-element": "^1.4.0",
"lit": "^2.3.0"
}
},
"node_modules/@lit/localize-tools": {
"version": "0.6.5",
"resolved": "https://registry.npmjs.org/@lit/localize-tools/-/localize-tools-0.6.5.tgz",
"integrity": "sha512-/zBl7PuY5ZKCHD5quqF2SgGpJejPEK6ae6G8r1YJjbK7edTH4Ukaha+c5cBmtyIagFVCD6DpQDBkiLYUZ92UoQ==",
"dev": true,
"dependencies": {
"@lit/localize": "^0.11.0",
"@xmldom/xmldom": "^0.8.2",
"fast-glob": "^3.2.7",
"fs-extra": "^10.0.0",
"jsonschema": "^1.4.0",
"lit": "^2.2.0",
"minimist": "^1.2.5",
"parse5": "^6.0.1",
"source-map-support": "^0.5.19",
"typescript": "~4.7.4"
},
"bin": {
"lit-localize": "bin/lit-localize.js"
}
},
"node_modules/@lit/localize-tools/node_modules/typescript": {
"version": "4.7.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
"integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/@lit/reactive-element": { "node_modules/@lit/reactive-element": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.4.2.tgz", "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.4.2.tgz",
@ -772,6 +818,15 @@
"node": ">=10.0.0" "node": ">=10.0.0"
} }
}, },
"node_modules/@xmldom/xmldom": {
"version": "0.8.6",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.6.tgz",
"integrity": "sha512-uRjjusqpoqfmRkTaNuLJ2VohVr67Q5YwDATW3VU7PfzTj6IRaihGrYI7zckGZjxQPBIp63nfvJbM+Yu5ICh0Bg==",
"dev": true,
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/accepts": { "node_modules/accepts": {
"version": "1.3.8", "version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@ -907,6 +962,11 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/bootstrap-icons": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.10.2.tgz",
"integrity": "sha512-PTPYadRn1AMGr+QTSxe4ZCc+Wzv9DGZxbi3lNse/dajqV31n2/wl/7NX78ZpkvFgRNmH4ogdIQPQmxAfhEV6nA=="
},
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -929,6 +989,12 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
},
"node_modules/builtin-modules": { "node_modules/builtin-modules": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
@ -1744,6 +1810,20 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/fs-extra": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dev": true,
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/fs.realpath": { "node_modules/fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -1849,6 +1929,12 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/graceful-fs": {
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
"dev": true
},
"node_modules/grapheme-splitter": { "node_modules/grapheme-splitter": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
@ -2193,6 +2279,27 @@
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
"dev": true "dev": true
}, },
"node_modules/jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dev": true,
"dependencies": {
"universalify": "^2.0.0"
},
"optionalDependencies": {
"graceful-fs": "^4.1.6"
}
},
"node_modules/jsonschema": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz",
"integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==",
"dev": true,
"engines": {
"node": "*"
}
},
"node_modules/keygrip": { "node_modules/keygrip": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz",
@ -3004,6 +3111,25 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/statuses": { "node_modules/statuses": {
"version": "1.5.0", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
@ -3222,6 +3348,15 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
"dev": true,
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/uri-js": { "node_modules/uri-js": {
"version": "4.4.1", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@ -3496,6 +3631,41 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true "dev": true
}, },
"@lit/localize": {
"version": "0.11.4",
"resolved": "https://registry.npmjs.org/@lit/localize/-/localize-0.11.4.tgz",
"integrity": "sha512-RRIwIX2tAm3+DuEndoXSJrFjGrAK5cb5IXo5K6jcJ6sbgD829B8rSqHC5MaKVUmXTVLIR1bk5IZOZDf9wFereA==",
"requires": {
"@lit/reactive-element": "^1.4.0",
"lit": "^2.3.0"
}
},
"@lit/localize-tools": {
"version": "0.6.5",
"resolved": "https://registry.npmjs.org/@lit/localize-tools/-/localize-tools-0.6.5.tgz",
"integrity": "sha512-/zBl7PuY5ZKCHD5quqF2SgGpJejPEK6ae6G8r1YJjbK7edTH4Ukaha+c5cBmtyIagFVCD6DpQDBkiLYUZ92UoQ==",
"dev": true,
"requires": {
"@lit/localize": "^0.11.0",
"@xmldom/xmldom": "^0.8.2",
"fast-glob": "^3.2.7",
"fs-extra": "^10.0.0",
"jsonschema": "^1.4.0",
"lit": "^2.2.0",
"minimist": "^1.2.5",
"parse5": "^6.0.1",
"source-map-support": "^0.5.19",
"typescript": "~4.7.4"
},
"dependencies": {
"typescript": {
"version": "4.7.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
"integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
"dev": true
}
}
},
"@lit/reactive-element": { "@lit/reactive-element": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.4.2.tgz", "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.4.2.tgz",
@ -3941,6 +4111,12 @@
"parse5": "^6.0.1" "parse5": "^6.0.1"
} }
}, },
"@xmldom/xmldom": {
"version": "0.8.6",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.6.tgz",
"integrity": "sha512-uRjjusqpoqfmRkTaNuLJ2VohVr67Q5YwDATW3VU7PfzTj6IRaihGrYI7zckGZjxQPBIp63nfvJbM+Yu5ICh0Bg==",
"dev": true
},
"accepts": { "accepts": {
"version": "1.3.8", "version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@ -4040,6 +4216,11 @@
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"dev": true "dev": true
}, },
"bootstrap-icons": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.10.2.tgz",
"integrity": "sha512-PTPYadRn1AMGr+QTSxe4ZCc+Wzv9DGZxbi3lNse/dajqV31n2/wl/7NX78ZpkvFgRNmH4ogdIQPQmxAfhEV6nA=="
},
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -4059,6 +4240,12 @@
"fill-range": "^7.0.1" "fill-range": "^7.0.1"
} }
}, },
"buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
},
"builtin-modules": { "builtin-modules": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
@ -4675,6 +4862,17 @@
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
"dev": true "dev": true
}, },
"fs-extra": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dev": true,
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
}
},
"fs.realpath": { "fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -4746,6 +4944,12 @@
"slash": "^3.0.0" "slash": "^3.0.0"
} }
}, },
"graceful-fs": {
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
"dev": true
},
"grapheme-splitter": { "grapheme-splitter": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
@ -4992,6 +5196,22 @@
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
"dev": true "dev": true
}, },
"jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dev": true,
"requires": {
"graceful-fs": "^4.1.6",
"universalify": "^2.0.0"
}
},
"jsonschema": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz",
"integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==",
"dev": true
},
"keygrip": { "keygrip": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz",
@ -5591,6 +5811,22 @@
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true "dev": true
}, },
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"statuses": { "statuses": {
"version": "1.5.0", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
@ -5741,6 +5977,12 @@
"integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==",
"dev": true "dev": true
}, },
"universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
"dev": true
},
"uri-js": { "uri-js": {
"version": "4.4.1", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",

View file

@ -18,6 +18,7 @@
"author": "anna <owo@fef.moe>", "author": "anna <owo@fef.moe>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"devDependencies": { "devDependencies": {
"@lit/localize-tools": "^0.6.5",
"@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0", "@typescript-eslint/parser": "^5.45.0",
"@web/dev-server": "^0.1.35", "@web/dev-server": "^0.1.35",
@ -26,6 +27,8 @@
"typescript": "^4.9.3" "typescript": "^4.9.3"
}, },
"dependencies": { "dependencies": {
"@lit/localize": "^0.11.4",
"bootstrap-icons": "^1.10.2",
"lit": "^2.4.1", "lit": "^2.4.1",
"redux": "^4.2.0" "redux": "^4.2.0"
} }

View file

@ -0,0 +1 @@
../../node_modules/bootstrap-icons/bootstrap-icons.svg

View file

@ -1,5 +1,5 @@
<!doctype html> <!doctype html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes"> <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">

View file

@ -18,6 +18,10 @@
--accent-text-color: #e0d1e1; --accent-text-color: #e0d1e1;
--accent-highlight-text-color: var(--accent-text-color); --accent-highlight-text-color: var(--accent-text-color);
--success-color: #00ff00;
--warning-color: #d78318;
--error-color: #f21736;
/* border radius for smaller components like buttons */ /* border radius for smaller components like buttons */
--border-radius: 8px; --border-radius: 8px;
/* border radius for larger components like modals */ /* border radius for larger components like modals */

View file

@ -1,5 +1,6 @@
import {LitElement, html} from "lit"; import {LitElement, html} from "lit";
import {customElement} from "lit/decorators.js"; import {customElement} from "lit/decorators.js";
import {msg} from "@lit/localize";
import "./features/compose-form"; import "./features/compose-form";
import "./layout/column-layout"; import "./layout/column-layout";
@ -11,13 +12,15 @@ export default class NyanoBlog extends LitElement {
protected render() { protected render() {
return html` return html`
<column-layout> <column-layout>
<side-panel slot="left" headline="Compose"> <side-panel slot="left" headline="${msg("Compose")}">
<compose-form></compose-form> <compose-form></compose-form>
</side-panel> </side-panel>
<div slot="left-bottom">bottom left slot</div>
<div slot="main">main slot</div> <div slot="main">main slot</div>
<side-panel slot="right" headline="Notifications"> <side-panel slot="right" headline="${msg("Notifications")}">
<scroll-list style="max-height: 400px"> <scroll-list style="max-height: 400px">
<p>test uwu</p> <p>test uwu</p>
<p>test uwu</p> <p>test uwu</p>
@ -34,6 +37,8 @@ export default class NyanoBlog extends LitElement {
<p>test uwu</p> <p>test uwu</p>
</scroll-list> </scroll-list>
</side-panel> </side-panel>
<div slot="right-bottom">bottom right slot</div>
</column-layout> </column-layout>
`; `;
} }

View file

@ -0,0 +1,59 @@
import {LitElement, html, css} from "lit";
import {customElement, property, state} from "lit/decorators.js";
import withSharedStyles from "../theme";
import "./svg-icon";
@customElement("icon-button")
export default class IconButton extends LitElement {
@property({type: String, attribute: true})
public icon = "";
@property({type: String, attribute: true})
public color = "var(--text-color)";
@property({type: String, attribute: true})
public label = "";
@property({type: Boolean, attribute: true})
public disabled = false;
@state()
private pressed = false;
protected render() {
return html`
<button
?disabled=${this.disabled}
class="${this.pressed ? "pressed" : ""}"
@mousedown=${() => this.pressed = true}
@mouseup=${() => this.pressed = false}
@mouseleave=${() => this.pressed = false}
title="${this.label}"
>
<svg-icon id="#icon" icon="${this.icon}" color="${this.color}" size="20"></svg-icon>
</button>
`;
}
static get styles() {
return withSharedStyles(css`
button {
background-color: transparent;
border: none;
box-shadow: none;
transition: transform var(--anim-duration-short) ease-in-out;
transform-origin: center;
}
button.pressed {
transform: scale(90%);
}
button:not(:disabled):hover {
cursor: pointer;
}
`);
}
}

View file

@ -0,0 +1,36 @@
import {LitElement, html, css} from "lit";
import {customElement, property} from "lit/decorators.js";
@customElement("svg-icon")
export default class SVGIcon extends LitElement {
@property({type: String, attribute: true})
public icon = "";
@property({type: String, attribute: true})
public color = "var(--text-color)";
@property({type: Number, attribute: true})
public size = 24;
protected render() {
// i have svg
return html`
<svg id="asshole" class="bi" width="${this.size}" height="${this.size}" fill="${this.color}">
<use href="/img/bootstrap-icons.svg#${this.icon}" width="${this.size}" height="${this.size}"/>
</svg>
`;
}
static get styles() {
return css`
:host {
display: inline-block;
color: var(--text-color);
}
#asshole {
overflow: hidden;
}
`;
}
}

View file

@ -1,10 +1,12 @@
import {LitElement, html, css} from "lit"; import {LitElement, html, css} from "lit";
import {customElement, query, state} from "lit/decorators.js"; import {customElement, query, state} from "lit/decorators.js";
import {msg, str} from "@lit/localize";
import { maxNoteChars } from "../config"; import { maxNoteChars } from "../config";
import withSharedStyles from "../theme"; import withSharedStyles from "../theme";
import "../components/button"; import "../components/button";
import "../components/icon-button";
import "../components/input-field"; import "../components/input-field";
import InputField from "../components/input-field"; import InputField from "../components/input-field";
@ -22,32 +24,67 @@ export default class ComposeForm extends LitElement {
@state() @state()
private content = ""; private content = "";
private get remainingChars() {
return maxNoteChars - this.summary.length - this.content.length;
}
protected render() { protected render() {
return html` return html`
<input-field <input-field
id="summary" id="summary"
placeholder="Content warning (optional)" placeholder="${msg("Content warning (optional)")}"
maxlength="${maxNoteChars - this.content.length}" maxlength="${maxNoteChars - this.content.length}"
@input=${() => this.summary = this.summaryInput.value} @input=${() => this.summary = this.summaryInput.value}
></input-field> ></input-field>
<textarea <textarea
id="content" id="content"
placeholder="Say something nice" placeholder="${msg("Say something nice")}"
@input=${() => this.content = this.contentInput.value} @input=${() => this.content = this.contentInput.value}
maxlength="${maxNoteChars - this.summary.length}" maxlength="${maxNoteChars - this.summary.length}"
></textarea> ></textarea>
<div id="bar"> <div id="bar">
<div id="actions"> <div id="actions">
<icon-button icon="paperclip" label="${msg("Add attachment")}"></icon-button>
<icon-button icon="list-ul" label="${msg("Add poll")}"></icon-button>
<icon-button icon="emoji-laughing" label="${msg("Insert emogi")}"></icon-button>
<icon-button icon="${this.getGlobeIconName()}" label="${msg("Note visibility")}"></icon-button>
</div> </div>
<div id="length"> <div
${maxNoteChars - this.summary.length - this.content.length} id="remaining-chars"
class="${this.getRemainingCharsClass()}"
aria-description="${msg(str`${this.remainingChars} characters remaining`)}"
>
${this.remainingChars}
</div> </div>
<nyano-button ?disabled=${this.content.length === 0}>Meow!</nyano-button> <nyano-button ?disabled=${this.content.length === 0}>${msg("Meow!")}</nyano-button>
</div> </div>
`; `;
} }
private getRemainingCharsClass() {
const remaining = maxNoteChars - this.summary.length - this.content.length;
if (remaining > 20) {
return "";
} else if (remaining > 0) {
return "warning";
} else {
return "error";
}
}
private getGlobeIconName() {
const offset = new Date().getTimezoneOffset();
if (offset < -7 * 60) {
return "globe-asia-australia";
} else if (offset < -2 * 60) {
return "globe-central-south-asia";
} else if (offset < 3 * 60) {
return "globe-europe-africa";
} else {
return "globe-americas";
}
}
static get styles() { static get styles() {
return withSharedStyles(css` return withSharedStyles(css`
textarea { textarea {
@ -81,13 +118,28 @@ export default class ComposeForm extends LitElement {
#actions { #actions {
flex: 1; flex: 1;
display: flex;
flex-direction: row;
padding: 8px 0;
} }
#length { #actions > * {
padding: 8px 16px; flex: 1;
}
#remaining-chars {
padding: 8px 16px 8px 0;
font-weight: bold; font-weight: bold;
} }
#remaining-chars.almost-full {
color: var(--warning-color);
}
#remaining-chars.full {
color: var(--error-color);
}
nyano-button { nyano-button {
margin: 0; margin: 0;
} }

View file

@ -7,13 +7,27 @@ export default class ColumnLayout extends LitElement {
protected render() { protected render() {
return html` return html`
<div class="sidebar left"> <div class="sidebar left">
<slot name="left"/> <div class="container">
<slot name="left"/>
</div>
<div class="col-spacer"></div>
<div class="container">
<slot name="left-bottom"/>
</div>
</div> </div>
<main class="main">
<div class="main">
<slot name="main"/> <slot name="main"/>
</main> </div>
<div class="sidebar right"> <div class="sidebar right">
<slot name="right"/> <div class="container">
<slot name="right"/>
</div>
<div class="col-spacer"></div>
<div class="container">
<slot name="right-bottom"/>
</div>
</div> </div>
`; `;
} }
@ -24,15 +38,17 @@ export default class ColumnLayout extends LitElement {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
padding: 12px; padding: 12px;
height: calc(100vh - 24px);
} }
main { .main {
flex: 1; flex: 1;
} }
.sidebar { .sidebar {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%;
} }
.sidebar.left { .sidebar.left {
@ -41,7 +57,14 @@ export default class ColumnLayout extends LitElement {
.sidebar.right { .sidebar.right {
padding-left: 12px; padding-left: 12px;
}
.content {
display: block;
}
.col-spacer {
flex: 1;
} }
`); `);
} }

View file

@ -3,6 +3,12 @@ import {customElement, property} from "lit/decorators.js";
import withSharedStyles from "../theme"; import withSharedStyles from "../theme";
/**
* Container for widgets on the left and right sides of the app.
* This is not useful on its own; the actual component lives within
* the slot. The only thing this does is create a card-like box
* with a headline.
*/
@customElement("side-panel") @customElement("side-panel")
export default class SidePanel extends LitElement { export default class SidePanel extends LitElement {
@property({type: String, attribute: true}) @property({type: String, attribute: true})
@ -28,7 +34,8 @@ export default class SidePanel extends LitElement {
} }
h2 { h2 {
margin: 0 0 var(--border-radius-large) 0; margin: 0 0 16px 0;
line-height: 1.2;
} }
`); `);
} }