Skip to content

Commit

Permalink
feat add a prewiev button + fix readme
Browse files Browse the repository at this point in the history
  • Loading branch information
Floren henri committed Jan 28, 2023
1 parent a4ea74a commit f095e7a
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 64 deletions.
21 changes: 18 additions & 3 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
Stunning-story is an open source website that provides a digital interface for playing and creating gamebooks. Gamebooks are interactive novels where the reader makes choices that determine the outcome of the story. The website allows users to play existing gamebooks or create their own using a user-friendly interface. The scope of the project includes providing an easy-to-use platform for gamebook enthusiasts to play and create their own stories.

The goal of the website is to be accessible to both experienced gamebook creators and those new to the format, providing a platform for players and creators to share and experience a wide range of interactive stories.
## A Ui to play a gamebook Stories:
## Play:

* The gamebook UI is a digital interface that allows users to interact with a gamebook story. It's includes features such as a text-based narrative, choices for the user to make, and the ability to track progress through the story.
* The gamebook UI is a digital interface that allows users to interact with a gamebook story. It's includes features such as a text-based narrative, choices for the user to make, and the ability to track progress through the story.

* The digital interface for playing gamebooks is the interface that users interact with when they are reading and playing a gamebook. It includes features such as a navigation system for moving through the different sections of the gamebook, a display for the text and media elements of the story, and a way for the user to make choices and see the outcome of those choices.
* It also include features such as bookmarks to save the user's progress, the ability to go back to previous choices, and settings for adjusting the appearance of the interface, such as text size and background color.
Expand All @@ -20,7 +20,7 @@ The goal of the website is to be accessible to both experienced gamebook creator

<img src="https://raw.githubusercontent.com/O-Plums/stunning-story/main/repo_info/read.png" width="auto" height="auto" />

## A Builder to build gamebook Stoies:
## Build:

* The builder allows users to create their own gamebooks. It is a user-friendly interface that guides the user through the process of creating a gamebook, from writing the story to adding choices and determining the outcome of those choices.

Expand All @@ -37,6 +37,21 @@ The goal of the website is to be accessible to both experienced gamebook creator

```
git clone https://github.com/O-Plums/stunning-story
vim dev.env
```
```bash
export accessKeyId=key
export secretAccessKey=key
export GOOGLE_CLIENT_ID=key
export GOOGLE_CLIENT_SECRET=key
export STRAPI_URL=http://localhost:1337
export STRAPI_TOKEN=key
export DISCORD_CLIENT_ID=key
export DISCORD_CLIENT_SECRET=key
export SECRET=key
```
```
source dev.env
```
* Client: The front is build using [NextJS](https://nextjs.org/) and [tailwindcss](https://tailwindcss.com/)

Expand Down
132 changes: 72 additions & 60 deletions client/components/Diagram/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable max-len */
/* eslint-disable react/destructuring-assignment */
/* eslint-disable consistent-return */
import React, { useState, useEffect } from 'react';
Expand All @@ -13,6 +14,7 @@ import {
import EditStory from '@components/Story/EditStory';
import Switch from '@components/Switch';
import useTranslation from 'next-translate/useTranslation';
import { useRouter } from 'next/router';
import DisplayNodes from './displayNode';
import Target from './target';

Expand All @@ -25,6 +27,7 @@ A node can connect back to the story.
*/
export default function Diagram(props: any) {
const { t } = useTranslation('common');
const router = useRouter();

const [story, setStory] = useState(props.story);
const updateXarrow = useXarrow();
Expand Down Expand Up @@ -179,32 +182,43 @@ export default function Diagram(props: any) {
updateXarrow();
}}
>
<div
className={`absolute top-0 flex flex-row ${
!story.publishedAt ? 'bg-gray-500' : 'bg-green-600'
} rounded-br-xl p-2`}
>
<Switch
checked={story.publishedAt}
onChange={async () => {
await updateStory({
...story,
publishedAt: !story.publishedAt ? new Date() : null,
});
setStory({
...story,
publishedAt: !story.publishedAt ? new Date() : null,
});
<div className="flex absolute top-0">
<div
className={` flex flex-row ${
!story.publishedAt ? 'bg-gray-500' : 'bg-green-600'
} rounded-br-xl p-2`}
>
<Switch
checked={story.publishedAt}
onChange={async () => {
await updateStory({
...story,
publishedAt: !story.publishedAt ? new Date() : null,
});
setStory({
...story,
publishedAt: !story.publishedAt ? new Date() : null,
});
}}
label={
!story.publishedAt ? (
<p className="w-20">{t('builder.draft')}</p>
) : (
<p className="w-20">{t('builder.published')}</p>
)
}
/>
</div>
<Button
label="Preview"
className=" ml-2 rounded-t-none"
size="small"
onClick={() => {
router.push(`/builder/preview/${story.slug}`);
}}
label={
!story.publishedAt ? (
<p className="w-20">{t('builder.draft')}</p>
) : (
<p className="w-20">{t('builder.published')}</p>
)
}
/>
</div>

<div className="absolute bottom-2 ml-3 flex flex-row bg-gray-500 rounded-xl p-2 z-50">
<MagnifyingGlassMinusIcon
className="w-7 h-7 mr-2 cursor-pointer"
Expand Down Expand Up @@ -256,52 +270,50 @@ export default function Diagram(props: any) {
>
<Xwrapper>
{storyGraph.length > 0
&& storyGraph.map((node: any) => node.outputs.map(
(output: any, outputIndex: number) => {
if (output.type === 'target') {
return (
<Xarrow
labels={(
<p className="text-xs text-ellipsis w-20 text-center line-clamp-2">
{output.value}
</p>
&& storyGraph.map((node: any) => node.outputs.map((output: any, outputIndex: number) => {
if (output.type === 'target') {
return (
<Xarrow
labels={(
<p className="text-xs text-ellipsis w-20 text-center line-clamp-2">
{output.value}
</p>
)}
start={node.sourceId}
end={output.id}
color="green"
key={`${output.id}`}
/>
);
}
if (output.type === 'node') {
return (
<Xarrow
labels={(
<div className="flex flex-row items-center justify-center w-20">
{output.canBeRemove && (
start={node.sourceId}
end={output.id}
color="green"
key={`${output.id}`}
/>
);
}
if (output.type === 'node') {
return (
<Xarrow
labels={(
<div className="flex flex-row items-center justify-center w-20">
{output.canBeRemove && (
<TrashIcon
className="text-red-400 h-5 w-5 mr-2 cursor-pointer z-50"
onClick={() => {
removeDupicateNode(node.sourceId, outputIndex);
}}
/>
)}
<p className="text-xs text-ellipsis text-center line-clamp-2">
{output.value}
</p>
</div>
)}
<p className="text-xs text-ellipsis text-center line-clamp-2">
{output.value}
</p>
</div>
)}
start={node.sourceId}
end={output.sourceId}
color="purple"
key={`${output.id}`}
/>
);
}
start={node.sourceId}
end={output.sourceId}
color="purple"
key={`${output.id}`}
/>
);
}

return null;
},
))}
return null;
}))}
</Xwrapper>
</div>
{addNewNodeModal && (
Expand Down
34 changes: 33 additions & 1 deletion client/components/Story/Reader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@ import { useRouter } from 'next/router';
import DeviceOrientation, { Orientation } from 'react-screen-orientation';
import { motion } from 'framer-motion';
import useTranslation from 'next-translate/useTranslation';
import { SpeakerWaveIcon, SpeakerXMarkIcon } from '@heroicons/react/24/outline';

const audio = new Audio();

export default function Reader(props: any) {
const { story } = props;
const { t } = useTranslation('common');
const storyGraph = story.storyGraph || [];
const [changeNode, setChangeNode] = useState(true);
const [currentNode, setCurrentNode] = useState(storyGraph[0]);
const [isPlaying, setIsPlaying] = React.useState(false);

const router = useRouter();
const variants = {
hidden: { opacity: 0, x: 200, y: 0 },
Expand All @@ -24,7 +29,12 @@ export default function Reader(props: any) {
if (!changeNode) {
setChangeNode(true);
}
audio.src = story.audio;
return () => {
audio.pause();
};
}, [changeNode]);

return (
<DeviceOrientation lockOrientation="landscape">
<Orientation orientation="portrait" alwaysRender={false}>
Expand All @@ -43,7 +53,29 @@ export default function Reader(props: any) {
transition={{ ztype: 'linear' }}
className="h-3/5 lg:h-3/4 flex flex-col items-center justify-center relative"
>
<div className="absolute top-3 right-10">
<div className="absolute top-3 right-10 flex flex-row items-center">
{story.audio && isPlaying && (
<div className="p-2 mr-2 bg-green-500 z-50 rounded-lg">
<SpeakerWaveIcon
onClick={() => {
setIsPlaying(!isPlaying);
audio.pause();
}}
className="h-5 w-5 text-white"
/>
</div>
)}
{story.audio && !isPlaying && (
<div className="p-2 mr-2 bg-red-500 z-50 rounded-lg">
<SpeakerXMarkIcon
onClick={() => {
setIsPlaying(!isPlaying);
audio.play();
}}
className="h-5 w-5 text-white"
/>
</div>
)}
<Button
label="Restart"
size="small"
Expand Down
45 changes: 45 additions & 0 deletions client/pages/builder/preview/[slug].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import qs from 'qs';
import { fetchCMS } from '@lib/cms';
import dynamic from 'next/dynamic';

const Reader = dynamic(() => import('@components/Story/Reader'), {
ssr: false,
});
export default function OneStory(props: any) {
const { story } = props;
return <Reader story={story} />;
}

export async function getServerSideProps({ query }) {
try {
const cmsQuery = qs.stringify(
{
filters: {
slug: {
$eq: query.slug,
},
},
populate: ['cover', 'first_page', 'nodes', 'pages.answers'],
},
{
encodeValuesOnly: true,
},
);
const [story] = await fetchCMS(
`/api/stories?${cmsQuery}&publicationState=preview`,
);

return {
props: {
story: story.attributes,
},
};
} catch (error) {
return {
props: {
story: {},
},
};
}
}

0 comments on commit f095e7a

Please sign in to comment.