├── src └── journey │ ├── public │ ├── index.tsx │ └── components │ │ ├── app.tsx │ │ └── entry.tsx │ ├── types.mo │ └── main.mo ├── .gitignore ├── dfx.json ├── package.json ├── README.md ├── webpack.config.js └── tsconfig.json /src/journey/public/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { render } from 'react-dom'; 3 | import { JourneyApp } from './components/app'; 4 | 5 | render(, document.getElementById('app')); 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Various IDEs and Editors 2 | .vscode/ 3 | .idea/ 4 | **/*~ 5 | 6 | # Mac OSX temporary files 7 | .DS_Store 8 | **/.DS_Store 9 | 10 | # Build artifacts 11 | canisters/ 12 | 13 | # dfx temporary files 14 | .dfx/ 15 | 16 | # frontend code 17 | node_modules/ 18 | -------------------------------------------------------------------------------- /dfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "canisters": { 3 | "journey": { 4 | "frontend": { 5 | "entrypoint": "src/journey/public/index.tsx" 6 | }, 7 | "main": "src/journey/main.mo" 8 | } 9 | }, 10 | "defaults": { 11 | "build": { 12 | "output": "canisters/" 13 | }, 14 | "start": { 15 | "address": "127.0.0.1", 16 | "port": 8000, 17 | "serve_root": "canisters/journey/assets" 18 | } 19 | }, 20 | "dfx": "0.5.5", 21 | "version": 1 22 | } 23 | -------------------------------------------------------------------------------- /src/journey/public/components/app.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { EntryList, Entry, NewEntry } from './entry'; 3 | import { 4 | HashRouter as Router, 5 | Switch, 6 | Route, Link, 7 | } from 'react-router-dom'; 8 | 9 | export function JourneyApp() { 10 | return 11 | 12 | } /> 13 | 14 | 15 | 16 | New Entry 17 | 18 | 19 | ; 20 | } 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "journey", 3 | "version": "0.1.0", 4 | "description": "", 5 | "keywords": [], 6 | "scripts": { 7 | "build": "webpack" 8 | }, 9 | "devDependencies": { 10 | "@types/react": "^16.9.23", 11 | "@types/react-dom": "^16.9.5", 12 | "react": "^16.13.0", 13 | "react-dom": "^16.13.0", 14 | "terser-webpack-plugin": "2.2.2", 15 | "ts-loader": "^6.2.1", 16 | "typescript": "^3.8.3", 17 | "webpack": "4.41.3", 18 | "webpack-cli": "3.3.10" 19 | }, 20 | "dependencies": { 21 | "@types/react-router-dom": "^5.1.3", 22 | "markdown": "^0.5.0", 23 | "react-router-dom": "^5.1.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # journey 2 | 3 | Welcome to your new journey project and to the internet computer development community. By default, creating a new project adds this README and some template files to your project directory. You can edit these template files to customize your project and to include your own code to speed up the development cycle. 4 | 5 | To get started, you might want to explore the project directory structure and the default configuration file. Working with this project in your development environment will not affect any production deployment or identity tokens. 6 | 7 | To learn more before you start working with journey, see the following documentation available online: 8 | 9 | - [Quick Start](https://sdk.dfinity.org/developers-guide/quickstart.html) 10 | - [Developer's Guide](https://sdk.dfinity.org/developers-guide) 11 | - [Language Reference](https://sdk.dfinity.org/language-guide) 12 | 13 | If you want to start working on your project right away, you might want to try the following commands: 14 | 15 | ```bash 16 | cd journey/ 17 | dfx help 18 | dfx config --help 19 | ``` 20 | -------------------------------------------------------------------------------- /src/journey/types.mo: -------------------------------------------------------------------------------- 1 | module { 2 | public type UserRole = { 3 | #admin; 4 | #editor; 5 | #base; 6 | }; 7 | 8 | public type User = { 9 | id: Principal; 10 | name: Text; 11 | role: UserRole; 12 | description: Text; 13 | }; 14 | 15 | // Externally we return Entry through our API. 16 | public type Entry = { 17 | // How to identify this entry. 18 | id: Nat; 19 | 20 | // The person who created the entry. 21 | author: ?User; 22 | 23 | // The title of the entry. 24 | title: Text; 25 | 26 | // The header (first paragraph) of the entry. In Markdown. 27 | header: Text; 28 | 29 | // The content (which is optional in list). 30 | content: ?Text; 31 | }; 32 | 33 | // Internally, we store the JOIN key author to the author list. 34 | public type InternalEntry = { 35 | // How to identify this entry. 36 | id: Nat; 37 | 38 | // The person who created the entry. 39 | author: Principal; 40 | 41 | // The title of the entry. 42 | title: Text; 43 | 44 | // The content of the entry. In Markdown. 45 | content: Text; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const TerserPlugin = require("terser-webpack-plugin"); 3 | const dfxJson = require("./dfx.json"); 4 | 5 | // List of all aliases for canisters. This creates the module alias for 6 | // the `import ... from "ic:canisters/xyz"` where xyz is the name of a 7 | // canister. 8 | const aliases = Object.entries(dfxJson.canisters).reduce((acc, [name,value]) => { 9 | const outputRoot = path.join(__dirname, dfxJson.defaults.build.output, name); 10 | const filename = path.basename(value.main, ".mo"); 11 | return { 12 | ...acc, 13 | ["ic:canisters/" + name]: path.join(outputRoot, filename + ".js"), 14 | ["ic:idl/" + name]: path.join(outputRoot, filename + ".did.js"), 15 | }; 16 | }, { 17 | // This will later point to the userlib from npm, when we publish the userlib. 18 | "ic:userlib": path.join( 19 | process.env["HOME"], 20 | ".cache/dfinity/versions", 21 | dfxJson.dfx || process.env["DFX_VERSION"], 22 | "js-user-library/", 23 | ), 24 | }); 25 | 26 | /** 27 | * Generate a webpack configuration for a canister. 28 | */ 29 | function generateWebpackConfigForCanister(name, info) { 30 | if (typeof info.frontend !== 'object') { 31 | return; 32 | } 33 | 34 | const outputRoot = path.join(__dirname, dfxJson.defaults.build.output, name); 35 | const inputRoot = __dirname; 36 | 37 | return { 38 | mode: "production", 39 | entry: { 40 | index: path.join(inputRoot, info.frontend.entrypoint), 41 | }, 42 | devtool: "source-map", 43 | optimization: { 44 | minimize: true, 45 | minimizer: [new TerserPlugin()], 46 | }, 47 | resolve: { 48 | alias: aliases, 49 | extensions: ['.tsx', '.ts', '.js'] 50 | }, 51 | output: { 52 | filename: "[name].js", 53 | path: path.join(outputRoot, "assets"), 54 | }, 55 | module: { 56 | rules: [ 57 | { test: /\.([jt]s)x?$/, loader: "ts-loader", exclude: /node_modules/ } 58 | ] 59 | }, 60 | plugins: [ 61 | ], 62 | }; 63 | } 64 | 65 | // If you have webpack configurations you want to build as part of this 66 | // config, add them here. 67 | module.exports = [ 68 | ...Object.entries(dfxJson.canisters).map(([name, info]) => { 69 | return generateWebpackConfigForCanister(name, info); 70 | }).filter(x => !!x), 71 | ]; 72 | -------------------------------------------------------------------------------- /src/journey/public/components/entry.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Components for entries; 3 | * NewEntry 4 | * EntryList 5 | * EntrySummary 6 | * Entry 7 | */ 8 | 9 | import journey from 'ic:canisters/journey'; 10 | import * as React from 'react'; 11 | import { useEffect, useState } from 'react'; 12 | import { Link, Redirect, useParams } from 'react-router-dom'; 13 | 14 | declare const require: any; 15 | const markdown = require('markdown').markdown; 16 | 17 | interface UserIdl { 18 | id: { toNumber(): number }; 19 | name: string; 20 | description: string; 21 | } 22 | 23 | interface EntryIdl { 24 | author: [UserIdl?]; 25 | header: string; 26 | content: [string?]; 27 | title: string; 28 | id: { toNumber(): number }; 29 | } 30 | 31 | export function NewEntry() { 32 | const [content, setContent] = useState(''); 33 | const [title, setTitle] = useState('New Entry'); 34 | const [done, setDone] = useState(false); 35 | const [saving, setSaving] = useState(false); 36 | 37 | async function submit() { 38 | setSaving(true); 39 | 40 | await journey.newEntry(title, content); 41 | setDone(true); 42 | } 43 | 44 | if (done) { 45 | return () 46 | } 47 | if (saving) { 48 | return (); 49 | } 50 | 51 | return ( 52 |
53 |
submit()}> 54 |
Title: setTitle(ev.target.value)} />
55 |
Content:
56 |