mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 08:59:35 +01:00
dedicated directory for story web version
This commit is contained in:
parent
432d72c80c
commit
0ad614699c
15 changed files with 204 additions and 137 deletions
|
|
@ -1,39 +0,0 @@
|
|||
import apiClient from './classes/api-client.js'
|
||||
import eventBus from './classes/event-bus.js';
|
||||
import storage from './classes/storage.js';
|
||||
|
||||
|
||||
import { render } from 'preact';
|
||||
import { html } from 'htm/preact';
|
||||
import TopMenu from './components/TopMenu.js'
|
||||
import ParametersDialog from './components/ParametersDialog.js';
|
||||
|
||||
export function App() {
|
||||
|
||||
this.params = storage.getItem('server') || {
|
||||
serverUrl: '127.0.0.1',
|
||||
serverPort: 8081,
|
||||
};
|
||||
|
||||
storage.setItem('server', this.params);
|
||||
|
||||
// try to connect to the server
|
||||
apiClient.setBaseUrl(`http://${this.params.serverUrl}:${this.params.serverPort}/api/v1`);
|
||||
apiClient.get('/library/list')
|
||||
.then(data => {
|
||||
console.log('Server is up and running', data);
|
||||
eventBus.publish('server-state-changed', {connected: true});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Server is down', error);
|
||||
eventBus.publish('server-state-changed', {connected: false});
|
||||
});
|
||||
|
||||
|
||||
return html`
|
||||
<${TopMenu} />
|
||||
<${ParametersDialog} />
|
||||
`;
|
||||
}
|
||||
|
||||
render(html`<${App} />`, document.getElementById('app'));
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="title" content="OpenStoryTeller Web Player">
|
||||
<meta name="description" content="OpenStoryTeller Web Player">
|
||||
<meta name="keywords" content="story, player, teller">
|
||||
|
||||
<title>OpenStoryTeller Web Player</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link rel="stylesheet" href="main.css">
|
||||
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"preact": "https://esm.sh/preact@10.23.1",
|
||||
"preact/hooks": "https://esm.sh/preact@10.23.1/hooks",
|
||||
"htm/preact": "https://esm.sh/htm@3.1.1/preact?external=preact"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="shortcut icon" href="https://www.raylib.com/favicon.ico">
|
||||
<style>
|
||||
body {
|
||||
line-height: 1;
|
||||
font-family: 'Inter', sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
canvas.emscripten { border: 0px none; background-color: black; display: inline; }
|
||||
#canvas-container {
|
||||
width: 100%;
|
||||
text-align:center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="min-width: min-content;">
|
||||
<main>
|
||||
<div id="app"></div>
|
||||
|
||||
<div id="canvas-container" class="block fixed">
|
||||
<canvas class=emscripten id=canvas oncontextmenu=event.preventDefault() tabindex=-1></canvas>
|
||||
</div>
|
||||
<p id="output" />
|
||||
|
||||
</main>
|
||||
|
||||
<script>
|
||||
var Module = {
|
||||
print: (function() {
|
||||
var element = document.getElementById('output');
|
||||
if (element) element.value = ''; // clear browser cache
|
||||
return function(text) {
|
||||
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
|
||||
console.log(text);
|
||||
if (element) {
|
||||
element.value += text + "\n";
|
||||
element.scrollTop = element.scrollHeight; // focus on bottom
|
||||
}
|
||||
};
|
||||
})(),
|
||||
canvas: (function() {
|
||||
var canvas = document.getElementById('canvas');
|
||||
return canvas;
|
||||
})(),
|
||||
locateFile: function(s) {
|
||||
return 'bin/' + s;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script async type="text/javascript" src="bin/story-player.js"></script>
|
||||
<script src="app.js" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
55
story-player-web/app.js
Normal file
55
story-player-web/app.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import apiClient from './classes/api-client.js'
|
||||
import eventBus from './classes/event-bus.js';
|
||||
import storage from './classes/storage.js';
|
||||
|
||||
|
||||
import { render } from 'preact';
|
||||
import { createContext } from "preact";
|
||||
import { html } from 'htm/preact';
|
||||
import TopMenu from './components/TopMenu.js'
|
||||
import ParametersDialog from './components/ParametersDialog.js';
|
||||
import StoryPlayer from './components/StoryPlayer.js';
|
||||
import StoriesList from './components/StoriesList.js';
|
||||
|
||||
export const AppContext = createContext("appContext");
|
||||
|
||||
export function App() {
|
||||
|
||||
const DefaultContext = {
|
||||
stories: []
|
||||
};
|
||||
|
||||
this.params = storage.getItem('server') || {
|
||||
serverUrl: '127.0.0.1',
|
||||
serverPort: 8081,
|
||||
};
|
||||
|
||||
storage.setItem('server', this.params);
|
||||
|
||||
// try to connect to the server
|
||||
apiClient.setBaseUrl(`http://${this.params.serverUrl}:${this.params.serverPort}/api/v1`);
|
||||
apiClient.get('/library/list')
|
||||
.then(data => {
|
||||
console.log('Server is up and running', data);
|
||||
eventBus.publish('server-state-changed', {connected: true});
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('Server is down');
|
||||
eventBus.publish('server-state-changed', {connected: false});
|
||||
});
|
||||
|
||||
|
||||
return html`
|
||||
<AppContext.Provider value="${DefaultContext}">
|
||||
<${TopMenu} />
|
||||
<${ParametersDialog} />
|
||||
|
||||
<div style="display: flex; flex-direction:row;">
|
||||
<${StoryPlayer} />
|
||||
<${StoriesList} />
|
||||
</div>
|
||||
</AppContext.Provider>
|
||||
`;
|
||||
}
|
||||
|
||||
render(html`<${App} />`, document.getElementById('app'));
|
||||
BIN
story-player-web/assets/Inter-Regular.ttf
Normal file
BIN
story-player-web/assets/Inter-Regular.ttf
Normal file
Binary file not shown.
BIN
story-player-web/assets/logo-color.png
Normal file
BIN
story-player-web/assets/logo-color.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 116 KiB |
|
|
@ -8,6 +8,9 @@ class ApiClient {
|
|||
}
|
||||
|
||||
async request(endpoint, method = 'GET', data = null, headers = {}) {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 5000);
|
||||
|
||||
const config = {
|
||||
method,
|
||||
headers: {
|
||||
|
|
@ -20,17 +23,18 @@ class ApiClient {
|
|||
config.body = JSON.stringify(data);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${this.baseURL}${endpoint}`, config);
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(errorData.message || 'Something went wrong');
|
||||
|
||||
const promise = fetch(`${this.baseURL}${endpoint}`, config).then(async (response) => {
|
||||
|
||||
const data = await response.json();
|
||||
if (response.ok) {
|
||||
return data;
|
||||
} else {
|
||||
return Promise.reject(data);
|
||||
}
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('API request error:', error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
return promise.finally(() => clearTimeout(timeout));
|
||||
|
||||
}
|
||||
|
||||
get(endpoint, headers = {}) {
|
||||
59
story-player-web/components/StoriesList.js
Normal file
59
story-player-web/components/StoriesList.js
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import { html } from 'htm/preact';
|
||||
import eventBus from '../classes/event-bus.js';
|
||||
import { useState } from 'preact/hooks';
|
||||
|
||||
|
||||
function StoriesList() {
|
||||
|
||||
return html`
|
||||
<style>
|
||||
.card-container {
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex: 1;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 1.2em;
|
||||
margin: 0 0 10px 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.card-description {
|
||||
font-size: 0.9em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.card-image {
|
||||
width: 120px;
|
||||
height: 90px;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
<div>
|
||||
<div class="card-container">
|
||||
<div class="block card">
|
||||
<div class="card-content">
|
||||
<h2 class="card-title">Titre de la Carte 1</h2>
|
||||
<p class="card-description">Description de la carte 1. Voici une brève description pour cette carte.</p>
|
||||
</div>
|
||||
<img src="https://placehold.co/100x75" alt="Image de la carte 1" class="card-image" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
`;
|
||||
}
|
||||
export default StoriesList;
|
||||
26
story-player-web/components/StoryPlayer.js
Normal file
26
story-player-web/components/StoryPlayer.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { html } from 'htm/preact';
|
||||
import eventBus from '../classes/event-bus.js';
|
||||
import { useState } from 'preact/hooks';
|
||||
|
||||
|
||||
function StoryPlayer() {
|
||||
|
||||
return html`
|
||||
<style>
|
||||
|
||||
</style>
|
||||
<div style="width: 400px; height: 500px;">
|
||||
<div class="block fixed" style="width: 320px; height: 240px;">
|
||||
|
||||
</div>
|
||||
<div style="display: flex; ">
|
||||
<div class="block accent btn">⇦</div>
|
||||
<div class="block accent btn">✓</div>
|
||||
<div class="block accent btn">⇨</div>
|
||||
<div class="block accent btn">⏎</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
export default StoryPlayer;
|
||||
|
|
@ -56,9 +56,7 @@ function TopMenu() {
|
|||
</style>
|
||||
<div class="flexRow">
|
||||
<${MessageComponent} show=${error} message=${message} />
|
||||
<div class="block accent" onClick="${handleClick}">
|
||||
Paramètres
|
||||
</div>
|
||||
<div class="block accent btn" onClick="${handleClick}">Paramètres</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
45
story-player-web/index.html
Normal file
45
story-player-web/index.html
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<!doctype html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="title" content="OpenStoryTeller Web Player">
|
||||
<meta name="description" content="OpenStoryTeller Web Player">
|
||||
<meta name="keywords" content="story, player, teller">
|
||||
|
||||
<title>OpenStoryTeller Web Player</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link rel="stylesheet" href="main.css">
|
||||
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"preact": "https://esm.sh/preact@10.23.1",
|
||||
"preact/hooks": "https://esm.sh/preact@10.23.1/hooks",
|
||||
"htm/preact": "https://esm.sh/htm@3.1.1/preact?external=preact"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<link rel="shortcut icon" href="https://www.raylib.com/favicon.ico">
|
||||
<style>
|
||||
body {
|
||||
line-height: 1;
|
||||
font-family: 'Inter', sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="min-width: min-content;">
|
||||
<div id="app"></div>
|
||||
|
||||
<script src="storyvm.js"></script>
|
||||
<script src="app.js" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -199,7 +199,6 @@ body {
|
|||
border-radius: 3px;
|
||||
padding: 4px 8px;
|
||||
background: var(--block-background-color);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
|
||||
|
|
@ -283,6 +282,10 @@ body {
|
|||
cursor: initial !important;
|
||||
}
|
||||
|
||||
.block.btn {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* FIXED STYLES */
|
||||
.block.fixed:hover,
|
||||
.block.fixed:hover::before,
|
||||
Loading…
Reference in a new issue