├── .gitignore ├── README.md ├── babel.config.js ├── env.example ├── index.html ├── package.json ├── postcss.config.js ├── src ├── App.vue ├── api │ ├── airlock.ts │ ├── index.js │ └── urbitAPI.js ├── components │ └── Start.vue ├── index.css ├── main.js ├── router │ └── index.ts ├── shims-vue.d.ts ├── store │ ├── index.ts │ └── ship.ts ├── types │ └── index.ts └── views │ └── Home.vue ├── tailwind.config.js ├── tsconfig.json ├── vite.config.ts └── vue.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | package-lock.json 3 | yarn.lock 4 | .env 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vite/Vue3/Typescript/Tailwind/Urbit template 2 | 3 | Find a version of this template with: 4 | 5 | - Typed Vuex store 6 | - Vue3 `setup` components 7 | - Composition API 8 | 9 | On the 10 | [vue3-typed-store](https://github.com/vcavallo/vite-vue-urbit-template/tree/vue3-typed-store) 11 | branch. 12 | 13 | 14 | To install this elsewhere: 15 | 16 | ``` 17 | npx degit vcavallo/vite-vue-urbit-template your-project-name 18 | cd your-project-name 19 | 20 | npm install 21 | ``` 22 | 23 | Then: 24 | 25 | - Define a .env file, copied from env.example 26 | - Set the port based on your running fakeship 27 | - Set the desk name to the name of your desk 28 | - `npm run serve` 29 | - Visit the URL that the vite server output shows (probably `localhost:3000`) 30 | - Log in with your `+code` 31 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/cli-plugin-babel/preset"], 3 | }; 4 | -------------------------------------------------------------------------------- /env.example: -------------------------------------------------------------------------------- 1 | VITE_URBIT_TARGET='http://localhost:8080' 2 | VITE_URBIT_DESK='desk-name' 3 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite app 8 | 9 | 10 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-vue3-urbit-template", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vite --host", 7 | "build": "vite build", 8 | "preview": "vite preview" 9 | }, 10 | "dependencies": { 11 | "@urbit/api": "^2.1.0", 12 | "@urbit/http-api": "^2.1.0", 13 | "core-js": "^3.8.3", 14 | "vue": "^3.2.25", 15 | "vue-router": "^4.0.3", 16 | "vuex": "^4.0.0" 17 | }, 18 | "devDependencies": { 19 | "@typescript-eslint/eslint-plugin": "^5.4.0", 20 | "@typescript-eslint/parser": "^5.4.0", 21 | "@urbit/vite-plugin-urbit": "^0.8.0", 22 | "@vitejs/plugin-vue": "^2.3.1", 23 | "@vue/cli-plugin-babel": "~5.0.0", 24 | "@vue/cli-plugin-eslint": "~5.0.0", 25 | "@vue/cli-plugin-router": "~5.0.0", 26 | "@vue/cli-plugin-typescript": "~5.0.0", 27 | "@vue/cli-plugin-vuex": "~5.0.0", 28 | "@vue/cli-service": "~5.0.0", 29 | "@vue/eslint-config-typescript": "^9.1.0", 30 | "eslint": "^7.32.0", 31 | "eslint-config-prettier": "^8.3.0", 32 | "eslint-plugin-prettier": "^4.0.0", 33 | "eslint-plugin-vue": "^8.0.3", 34 | "prettier": "^2.4.1", 35 | "typescript": "~4.5.5", 36 | "vite": "^2.9.9", 37 | "vue-tsc": "^0.29.8", 38 | "prettier-plugin-tailwindcss": "^0.1.5", 39 | "vitawind": "^2.2.4" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 14 | 15 | -------------------------------------------------------------------------------- /src/api/airlock.ts: -------------------------------------------------------------------------------- 1 | import urbitAPI from "./urbitAPI"; 2 | 3 | interface onSubNumber { 4 | (subNumber: number): void; 5 | } 6 | 7 | 8 | export function openAirlockTo( 9 | agent: string, 10 | onEvent, 11 | onSubNumber: onSubNumber 12 | ) { 13 | urbitAPI 14 | .subscribe({ 15 | app: agent, 16 | path: "/website", 17 | event: (data) => { 18 | onEvent(data); 19 | }, 20 | }) 21 | .then((sub: number) => { 22 | onSubNumber(sub); 23 | }); 24 | } 25 | 26 | export function closeAirlock(subscription: number, onClose) { 27 | urbitAPI.unsubscribe(subscription).then(() => { 28 | onClose; 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /src/api/index.js: -------------------------------------------------------------------------------- 1 | import urbitAPI from "./urbitAPI"; 2 | import * as airlock from "./airlock"; 3 | 4 | export default { 5 | ...urbitAPI, 6 | ...airlock, 7 | }; 8 | -------------------------------------------------------------------------------- /src/api/urbitAPI.js: -------------------------------------------------------------------------------- 1 | // import UrbitInterface from "@urbit/http-api"; // for typescript 2 | import connector from "@urbit/http-api"; 3 | 4 | const urbitAPI = new connector("", ""); 5 | urbitAPI.ship = window.ship; 6 | 7 | export default urbitAPI; 8 | -------------------------------------------------------------------------------- /src/components/Start.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import App from "./App.vue"; 3 | import router from "./router"; 4 | import './index.css'; 5 | 6 | import { createStore } from "./store"; 7 | 8 | const app = createApp(App); 9 | const store = createStore(app); 10 | 11 | app.use(store); 12 | app.use(router); 13 | app.mount("#app"); 14 | -------------------------------------------------------------------------------- /src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory, createWebHashHistory, RouteRecordRaw } from "vue-router"; 2 | import Home from "../views/Home.vue"; 3 | 4 | const routes: Array = [ 5 | { 6 | path: "/", 7 | name: "home", 8 | component: Home, 9 | }, 10 | //{ 11 | //path: "/about", 12 | //name: "about", 13 | //// route level code-splitting 14 | //// this generates a separate chunk (about.[hash].js) for this route 15 | //// which is lazy-loaded when the route is visited. 16 | //component: () => 17 | //import([> webpackChunkName: "about" <] "../views/AboutView.vue"), 18 | //}, 19 | ]; 20 | 21 | const router = createRouter({ 22 | history: createWebHashHistory(), 23 | routes, 24 | }); 25 | 26 | export default router; 27 | -------------------------------------------------------------------------------- /src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | declare module '*.vue' { 3 | //import Vue from 'vue' 4 | //export default Vue 5 | import type { DefineComponent } from 'vue' 6 | const component: DefineComponent<{}, {}, any> 7 | export default component 8 | } 9 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createStore as createVuexStore } from "vuex"; 2 | 3 | import ship from "./ship"; 4 | 5 | export const createStore = () => { 6 | return createVuexStore({ 7 | modules: { 8 | ship, 9 | }, 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /src/store/ship.ts: -------------------------------------------------------------------------------- 1 | import airlock from "../api"; 2 | 3 | import { 4 | AgentSubscription, 5 | } from "@/types"; 6 | 7 | export default { 8 | namespaced: true, 9 | state() { 10 | return { 11 | subscriptions: [] as Array, 12 | }; 13 | }, 14 | 15 | getters: { 16 | agentSubscriptions(state): Array | [] { 17 | return state.subscriptions 18 | }, 19 | }, 20 | 21 | mutations: { 22 | addSubscription(state, payload: AgentSubscription) { 23 | state.subscriptions.push(payload); 24 | }, 25 | 26 | unsetSubscription(state, subscription: AgentSubscription) { 27 | const sub = state.subscriptions.find((s) => s === subscription); 28 | state.subscriptions = state.subscriptions.filter((s) => s != sub); 29 | }, 30 | }, 31 | 32 | actions: { 33 | openAirlockToAgent({ dispatch }, agentName: string) { 34 | airlock.openAirlockTo( 35 | agentName, 36 | (data) => { 37 | console.log("agentName ", agentName); 38 | console.log("response ", data); 39 | }, 40 | (subscriptionNumber: number) => { 41 | console.log("got subscription number ", subscriptionNumber); 42 | dispatch("addSubscription", { 43 | agentName, 44 | subscriptionNumber, 45 | } as AgentSubscription); 46 | } 47 | ); 48 | }, 49 | 50 | removeSubscription({ commit }, subscription: AgentSubscription) { 51 | commit("unsetSubscription", subscription); 52 | }, 53 | 54 | addSubscription({ state, commit, dispatch }, payload: AgentSubscription) { 55 | const existing: 56 | | Array 57 | | [] = state.subscriptions.filter((s: AgentSubscription) => { 58 | return s.agentName === payload.agentName; 59 | }); 60 | existing.forEach((sub) => { 61 | dispatch("removeSubscription", sub); 62 | }); 63 | commit("addSubscription", payload); 64 | }, 65 | 66 | closeAgentAirlocks({ commit, getters }) { 67 | const agentSubscriptions: Array | [] = 68 | getters.agentSubscriptions; 69 | agentSubscriptions.forEach((sub) => { 70 | airlock.closeAirlock(sub.subscriptionNumber, [ 71 | commit("unsetSubscription", sub), 72 | ]); 73 | }); 74 | }, 75 | }, 76 | }; 77 | -------------------------------------------------------------------------------- /src/types/index.ts: -------------------------------------------------------------------------------- 1 | export interface AgentSubscription { 2 | agentName: string; 3 | subscriptionNumber: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 16 | 17 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ['index.html','./src/**/*.{js,jsx,ts,tsx,vue,html}'], 3 | theme: { 4 | extend: {}, 5 | }, 6 | plugins: [], 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "noImplicitAny": false, 8 | "noImplicitThis": true, 9 | "noImplicitReturns": true, 10 | "moduleResolution": "node", 11 | "skipLibCheck": true, 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "useDefineForClassFields": true, 16 | "sourceMap": true, 17 | "baseUrl": ".", 18 | "types": [ 19 | "webpack-env", 20 | "vite/client" 21 | ], 22 | "paths": { 23 | "@/*": [ 24 | "src/types/*", 25 | "src/*" 26 | ] 27 | }, 28 | "lib": [ 29 | "esnext", 30 | "dom", 31 | "dom.iterable", 32 | "scripthost" 33 | ] 34 | }, 35 | "include": [ 36 | "src/**/*.ts", 37 | "src/**/*.tsx", 38 | "src/**/*.vue", 39 | "tests/**/*.ts", 40 | "tests/**/*.tsx" 41 | ], 42 | "exclude": [ 43 | "node_modules" 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import vue from "@vitejs/plugin-vue"; 3 | import { urbitPlugin } from "@urbit/vite-plugin-urbit"; 4 | 5 | import path = require("path"); 6 | 7 | import dotenv = require("dotenv"); 8 | dotenv.config(); 9 | const target = process.env.VITE_URBIT_TARGET; 10 | const base = process.env.VITE_URBIT_DESK; 11 | 12 | export default defineConfig({ 13 | plugins: [vue(), urbitPlugin({ base, target })], 14 | resolve: { 15 | alias: { 16 | "@": path.resolve(__dirname, "./src"), 17 | }, 18 | }, 19 | build: { 20 | chunkSizeWarningLimit: 600, 21 | cssCodeSplit: false, 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require("@vue/cli-service"); 2 | 3 | //import dotenv = require("dotenv"); 4 | 5 | //dotenv.config(); 6 | //const base = process.env.URBIT_DESK; 7 | 8 | module.exports = defineConfig({ 9 | transpileDependencies: true, 10 | }); 11 | --------------------------------------------------------------------------------