+
+
+
+
-
-
-
- (。>﹏<)
diff --git a/src/App.scss b/src/App.scss
index 408ba402..5e7d3656 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -919,7 +919,6 @@ option {
pointer-events: none;
transition: opacity 2s;
opacity: 1;
- z-index: 9999999999999999999999999999;
&.hidden {
opacity: 0;
@@ -938,13 +937,80 @@ option {
}
}
+ #mascot-container {
+ perspective: 60em;
+ perspective-origin: 0 -15em;
+ transform-style: preserve-3d;
+ }
+
#throbber {
- animation-duration: 2s;
+ animation-duration: 3s;
animation-name: bounce;
animation-iteration-count: infinite;
animation-direction: normal;
transform-origin: bottom center;
+ --defaultY: 0;
+
+ &.dead {
+ animation-name: dead;
+ animation-duration: 3s;
+ // animation-iteration-count: 1;
+ animation-iteration-count: 1;
+ transform: rotateX(90deg) rotateY(0) rotateZ(-45deg);
+ }
+
+ @keyframes dead {
+ 0% {
+ transform: rotateX(0) rotateY(0) rotateZ(0);
+ }
+
+ 5% {
+ transform: rotateX(0) rotateY(0) rotateZ(1deg);
+ }
+
+ 10% {
+ transform: rotateX(0) rotateY(0) rotateZ(-2deg);
+ }
+
+ 15% {
+ transform: rotateX(0) rotateY(0) rotateZ(3deg);
+ }
+
+ 20% {
+ transform: rotateX(0) rotateY(0) rotateZ(0);
+ }
+
+ 25% {
+ transform: rotateX(0) rotateY(0) rotateZ(0);
+ }
+
+ 30% {
+ transform: rotateX(10deg) rotateY(0) rotateZ(0);
+ }
+
+ 35% {
+ transform: rotateX(-10deg) rotateY(0) rotateZ(0);
+ }
+
+ 40% {
+ transform: rotateX(10deg) rotateY(0) rotateZ(0);
+ }
+
+ 45% {
+ transform: rotateX(-10deg) rotateY(0) rotateZ(0);
+ }
+
+ 50% {
+ transform: rotateX(10deg) rotateY(0) rotateZ(0);
+ }
+
+ 100% {
+ transform: rotateX(90deg) rotateY(0) rotateZ(-45deg);
+ transition-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); /* easeInQuint */
+ }
+ }
+
@keyframes bounce {
0% {
scale: 1 1;
@@ -955,24 +1021,28 @@ option {
10% {
scale: 1.2 0.8;
translate: 0 0;
+ transform: rotateZ(var(--defaultZ));
animation-timing-function: ease-out;
}
30% {
scale: 0.9 1.1;
translate: 0 -40%;
+ transform: rotateZ(var(--defaultZ));
animation-timing-function: ease-in;
}
40% {
scale: 1.1 0.9;
translate: 0 -50%;
+ transform: rotateZ(var(--defaultZ));
animation-timing-function: ease-in;
}
45% {
scale: 0.9 1.1;
translate: 0 -45%;
+ transform: rotateZ(var(--defaultZ));
animation-timing-function: ease-in;
}
@@ -985,30 +1055,35 @@ option {
55% {
scale: 0.985 1.025;
translate: 0 -35%;
+ transform: rotateZ(var(--defaultZ));
animation-timing-function: ease-in;
}
60% {
scale: 1.0125 0.9985;
translate: 0 -30%;
+ transform: rotateZ(var(--defaultZ));
animation-timing-function: ease-in;
}
80% {
scale: 1.0063 0.9938;
translate: 0 -10%;
+ transform: rotateZ(var(--defaultZ));
animation-timing-function: ease-in-ou;
}
90% {
scale: 1.2 0.8;
translate: 0 0;
+ transform: rotateZ(var(--defaultZ));
animation-timing-function: ease-out;
}
100% {
scale: 1 1;
translate: 0 0;
+ transform: rotateZ(var(--defaultZ));
animation-timing-function: ease-out;
}
}
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 6691ff3e..356b09fa 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -327,11 +327,7 @@ const setConfig = async ({ store }) => {
const checkOAuthToken = async ({ store }) => {
if (store.getters.getUserToken()) {
- try {
- await store.dispatch('loginUser', store.getters.getUserToken())
- } catch (e) {
- console.error(e)
- }
+ return store.dispatch('loginUser', store.getters.getUserToken())
}
return Promise.resolve()
}
@@ -349,10 +345,15 @@ const afterStoreSetup = async ({ store, i18n }) => {
const server = (typeof overrides.target !== 'undefined') ? overrides.target : window.location.origin
store.dispatch('setInstanceOption', { name: 'server', value: server })
+ document.querySelector('#status').textContent = i18n.global.t('splash.settings')
await setConfig({ store })
- await store.dispatch('setTheme')
-
document.querySelector('#status').textContent = i18n.global.t('splash.theme')
+ try {
+ await store.dispatch('setTheme').catch((e) => { console.log(e) })
+ } catch (e) {
+ return Promise.reject(e)
+ }
+
applyConfig(store.state.config, i18n.global)
// Now we can try getting the server settings and logging in
@@ -363,7 +364,7 @@ const afterStoreSetup = async ({ store, i18n }) => {
getInstancePanel({ store }),
getNodeInfo({ store }),
getInstanceConfig({ store })
- ])
+ ]).catch(e => Promise.reject(e))
// Start fetching things that don't need to block the UI
store.dispatch('fetchMutes')
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 0d4609b5..8d6a9bfe 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -1406,11 +1406,12 @@
"loading": "Loading...",
"theme": "Applying theme, please wait warmly...",
"instance": "Getting instance info...",
- "splines": "Reticulating splines...",
- "almost": "Almost there!",
- "fun_1": "Drink more water!",
+ "settings": "Applying settings...",
+ "almost": "Reticulating splines...",
+ "fun_1": "Drink more water",
"fun_2": "Take it easy!",
- "fun_3": "Suya..",
- "fun_4": "#cofe"
+ "fun_3": "Suya...",
+ "fun_4": "My Pleroma machine is full power!",
+ "error": "Something went wrong"
}
}
diff --git a/src/main.js b/src/main.js
index 580c5005..40347e6d 100644
--- a/src/main.js
+++ b/src/main.js
@@ -48,6 +48,16 @@ const i18n = createI18n({
messages.setLanguage(i18n.global, currentLocale)
+const splashError = (i18n, e) => {
+ document.querySelector('#mascot').src = (Math.floor(Math.random() * 2) > 0)
+ ? '/static/pleromatan_orz_fox.png'
+ : '/static/pleromatan_orz.png'
+ document.querySelector('#mascot').classList.add('orz')
+ document.querySelector('#throbber').classList.add('dead')
+ document.querySelector('#status').textContent = i18n.global.t('splash.error')
+ console.error('PleromaFE failed to initialize: ', e)
+}
+
const persistedStateOptions = {
paths: [
'serverSideStorage.cache',
@@ -58,57 +68,61 @@ const persistedStateOptions = {
};
(async () => {
- let storageError = false
- const plugins = [pushNotifications]
try {
- const persistedState = await createPersistedState(persistedStateOptions)
- plugins.push(persistedState)
- } catch (e) {
- console.error(e)
- storageError = true
- }
- document.querySelector('#status').removeAttribute('class')
- document.querySelector('#status').textContent = i18n.global.t('splash.loading')
- const store = createStore({
- modules: {
- i18n: {
- getters: {
- i18n: () => i18n.global
- }
+ let storageError
+ const plugins = [pushNotifications]
+ try {
+ const persistedState = await createPersistedState(persistedStateOptions)
+ plugins.push(persistedState)
+ } catch (e) {
+ console.error('Storage error', e)
+ storageError = e
+ }
+ document.querySelector('#status').removeAttribute('class')
+ document.querySelector('#status').textContent = i18n.global.t('splash.loading')
+ const store = createStore({
+ modules: {
+ i18n: {
+ getters: {
+ i18n: () => i18n.global
+ }
+ },
+ interface: interfaceModule,
+ instance: instanceModule,
+ // TODO refactor users/statuses modules, they depend on each other
+ users: usersModule,
+ statuses: statusesModule,
+ notifications: notificationsModule,
+ lists: listsModule,
+ api: apiModule,
+ config: configModule,
+ profileConfig: profileConfigModule,
+ serverSideStorage: serverSideStorageModule,
+ adminSettings: adminSettingsModule,
+ shout: shoutModule,
+ oauth: oauthModule,
+ authFlow: authFlowModule,
+ mediaViewer: mediaViewerModule,
+ oauthTokens: oauthTokensModule,
+ reports: reportsModule,
+ polls: pollsModule,
+ postStatus: postStatusModule,
+ editStatus: editStatusModule,
+ statusHistory: statusHistoryModule,
+ chats: chatsModule,
+ announcements: announcementsModule
},
- interface: interfaceModule,
- instance: instanceModule,
- // TODO refactor users/statuses modules, they depend on each other
- users: usersModule,
- statuses: statusesModule,
- notifications: notificationsModule,
- lists: listsModule,
- api: apiModule,
- config: configModule,
- profileConfig: profileConfigModule,
- serverSideStorage: serverSideStorageModule,
- adminSettings: adminSettingsModule,
- shout: shoutModule,
- oauth: oauthModule,
- authFlow: authFlowModule,
- mediaViewer: mediaViewerModule,
- oauthTokens: oauthTokensModule,
- reports: reportsModule,
- polls: pollsModule,
- postStatus: postStatusModule,
- editStatus: editStatusModule,
- statusHistory: statusHistoryModule,
- chats: chatsModule,
- announcements: announcementsModule
- },
- plugins,
- strict: false // Socket modifies itself, let's ignore this for now.
- // strict: process.env.NODE_ENV !== 'production'
- })
- if (storageError) {
- store.dispatch('pushGlobalNotice', { messageKey: 'errors.storage_unavailable', level: 'error' })
+ plugins,
+ strict: false // Socket modifies itself, let's ignore this for now.
+ // strict: process.env.NODE_ENV !== 'production'
+ })
+ if (storageError) {
+ store.dispatch('pushGlobalNotice', { messageKey: 'errors.storage_unavailable', level: 'error' })
+ }
+ return await afterStoreSetup({ store, i18n })
+ } catch (e) {
+ splashError(i18n, e)
}
- afterStoreSetup({ store, i18n })
})()
// These are inlined by webpack's DefinePlugin
diff --git a/src/modules/interface.js b/src/modules/interface.js
index 3f180cf5..68b51015 100644
--- a/src/modules/interface.js
+++ b/src/modules/interface.js
@@ -230,27 +230,27 @@ const interfaceMod = {
const forceRecompile = forceThemeRecompilation || recompile
- let promise = null
+ let result = null
if (themeData) {
- promise = Promise.resolve(normalizeThemeData(themeData))
+ result = normalizeThemeData(themeData)
} else if (themeName) {
- promise = getPreset(themeName).then(themeData => normalizeThemeData(themeData))
+ result = normalizeThemeData(getPreset(themeName))
+ .then(themeData => normalizeThemeData(themeData))
} else if (userThemeSource || userThemeSnapshot) {
- promise = Promise.resolve(normalizeThemeData({
+ result = normalizeThemeData({
_pleroma_theme_version: 2,
theme: userThemeSnapshot,
source: userThemeSource
- }))
- } else if (actualThemeName && actualThemeName !== 'custom') {
- promise = getPreset(actualThemeName).then(themeData => {
- const realThemeData = normalizeThemeData(themeData)
- if (actualThemeName === instanceThemeName) {
- // This sole line is the reason why this whole block is above the recompilation check
- commit('setInstanceOption', { name: 'themeData', value: { theme: realThemeData } })
- }
- return realThemeData
})
+ } else if (actualThemeName && actualThemeName !== 'custom') {
+ const themeData = actualThemeName
+ const realThemeData = normalizeThemeData(themeData)
+ if (actualThemeName === instanceThemeName) {
+ // This sole line is the reason why this whole block is above the recompilation check
+ commit('setInstanceOption', { name: 'themeData', value: { theme: realThemeData } })
+ }
+ result = realThemeData
} else {
throw new Error('Cannot load any theme!')
}
@@ -259,95 +259,91 @@ const interfaceMod = {
// cache (tryLoadCache return true if load successful)
if (!forceRecompile && !themeDebug && tryLoadCache()) {
dispatch('setThemeApplied')
- return
+ return Promise.resolve()
}
- promise
- .then(realThemeData => {
- const theme2ruleset = convertTheme2To3(realThemeData)
+ const realThemeData = result
+ const theme2ruleset = convertTheme2To3(realThemeData)
- if (saveData) {
- commit('setOption', { name: 'theme', value: themeName || actualThemeName })
- commit('setOption', { name: 'customTheme', value: realThemeData })
- commit('setOption', { name: 'customThemeSource', value: realThemeData })
+ if (saveData) {
+ commit('setOption', { name: 'theme', value: themeName || actualThemeName })
+ commit('setOption', { name: 'customTheme', value: realThemeData })
+ commit('setOption', { name: 'customThemeSource', value: realThemeData })
+ }
+ const hacks = []
+
+ Object.entries(theme3hacks).forEach(([key, value]) => {
+ switch (key) {
+ case 'fonts': {
+ Object.entries(theme3hacks.fonts).forEach(([fontKey, font]) => {
+ if (!font?.family) return
+ switch (fontKey) {
+ case 'interface':
+ hacks.push({
+ component: 'Root',
+ directives: {
+ '--font': 'generic | ' + font.family
+ }
+ })
+ break
+ case 'input':
+ hacks.push({
+ component: 'Input',
+ directives: {
+ '--font': 'generic | ' + font.family
+ }
+ })
+ break
+ case 'post':
+ hacks.push({
+ component: 'RichContent',
+ directives: {
+ '--font': 'generic | ' + font.family
+ }
+ })
+ break
+ case 'monospace':
+ hacks.push({
+ component: 'Root',
+ directives: {
+ '--monoFont': 'generic | ' + font.family
+ }
+ })
+ break
+ }
+ })
+ break
}
- const hacks = []
-
- Object.entries(theme3hacks).forEach(([key, value]) => {
- switch (key) {
- case 'fonts': {
- Object.entries(theme3hacks.fonts).forEach(([fontKey, font]) => {
- if (!font?.family) return
- switch (fontKey) {
- case 'interface':
- hacks.push({
- component: 'Root',
- directives: {
- '--font': 'generic | ' + font.family
- }
- })
- break
- case 'input':
- hacks.push({
- component: 'Input',
- directives: {
- '--font': 'generic | ' + font.family
- }
- })
- break
- case 'post':
- hacks.push({
- component: 'RichContent',
- directives: {
- '--font': 'generic | ' + font.family
- }
- })
- break
- case 'monospace':
- hacks.push({
- component: 'Root',
- directives: {
- '--monoFont': 'generic | ' + font.family
- }
- })
- break
- }
- })
- break
+ case 'underlay': {
+ if (value !== 'none') {
+ const newRule = {
+ component: 'Underlay',
+ directives: {}
}
- case 'underlay': {
- if (value !== 'none') {
- const newRule = {
- component: 'Underlay',
- directives: {}
- }
- if (value === 'opaque') {
- newRule.directives.opacity = 1
- newRule.directives.background = '--wallpaper'
- }
- if (value === 'transparent') {
- newRule.directives.opacity = 0
- }
- hacks.push(newRule)
- }
- break
+ if (value === 'opaque') {
+ newRule.directives.opacity = 1
+ newRule.directives.background = '--wallpaper'
}
+ if (value === 'transparent') {
+ newRule.directives.opacity = 0
+ }
+ hacks.push(newRule)
}
- })
+ break
+ }
+ }
+ })
- const ruleset = [
- ...theme2ruleset,
- ...hacks
- ]
+ const ruleset = [
+ ...theme2ruleset,
+ ...hacks
+ ]
- applyTheme(
- ruleset,
- () => dispatch('setThemeApplied'),
- themeDebug
- )
- })
-
- return promise
+ applyTheme(
+ ruleset,
+ () => dispatch('setThemeApplied'),
+ themeDebug
+ )
}
}
}
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 2b3f88a8..c1603f39 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -43,16 +43,16 @@ const adoptStyleSheets = (styles) => {
// is nothing to do here.
}
-export const generateTheme = async (inputRuleset, callbacks, debug) => {
+export const generateTheme = (inputRuleset, callbacks, debug) => {
const {
onNewRule = (rule, isLazy) => {},
onLazyFinished = () => {},
onEagerFinished = () => {}
} = callbacks
- // Assuming that "worst case scenario background" is panel background since it's the most likely one
const themes3 = init({
inputRuleset,
+ // Assuming that "worst case scenario background" is panel background since it's the most likely one
ultimateBackgroundColor: inputRuleset[0].directives['--bg'].split('|')[1].trim(),
debug
})
@@ -146,11 +146,11 @@ export const tryLoadCache = () => {
}
}
-export const applyTheme = async (input, onFinish = (data) => {}, debug) => {
+export const applyTheme = (input, onFinish = (data) => {}, debug) => {
const eagerStyles = createStyleSheet(EAGER_STYLE_ID)
const lazyStyles = createStyleSheet(LAZY_STYLE_ID)
- const { lazyProcessFunc } = await generateTheme(
+ const { lazyProcessFunc } = generateTheme(
input,
{
onNewRule (rule, isLazy) {
@@ -185,8 +185,6 @@ export const applyTheme = async (input, onFinish = (data) => {}, debug) => {
)
setTimeout(lazyProcessFunc, 0)
-
- return Promise.resolve()
}
const extractStyleConfig = ({
diff --git a/src/services/theme_data/theme_data_3.service.js b/src/services/theme_data/theme_data_3.service.js
index cf58da11..056b78f7 100644
--- a/src/services/theme_data/theme_data_3.service.js
+++ b/src/services/theme_data/theme_data_3.service.js
@@ -196,6 +196,11 @@ export const init = ({
return rule
})
+ const i = 4
+ if (2 + 2 === i) {
+ throw new Error('test')
+ }
+
const ruleset = rulesetUnsorted
.map((data, index) => ({ data, index }))
.sort(({ data: a, index: ai }, { data: b, index: bi }) => {
diff --git a/static/pleromatan_orz.png b/static/pleromatan_orz.png
new file mode 100644
index 00000000..aa54411f
Binary files /dev/null and b/static/pleromatan_orz.png differ
diff --git a/static/pleromatan_orz_fox.png b/static/pleromatan_orz_fox.png
new file mode 100644
index 00000000..936e42f1
Binary files /dev/null and b/static/pleromatan_orz_fox.png differ