lesion 1 year ago
commit
0ca9098e19
57 changed files with 1006 additions and 0 deletions
  1. 42 0
      .gitignore
  2. BIN
      assets-src/apple-touch-icon.png
  3. BIN
      assets-src/web-icon.png
  4. 19 0
      framework7.json
  5. 41 0
      package.json
  6. BIN
      public/icons/128x128.png
  7. BIN
      public/icons/144x144.png
  8. BIN
      public/icons/152x152.png
  9. BIN
      public/icons/192x192.png
  10. BIN
      public/icons/256x256.png
  11. BIN
      public/icons/512x512.png
  12. BIN
      public/icons/apple-touch-icon.png
  13. BIN
      public/icons/favicon.png
  14. 88 0
      src/components/Button.vue
  15. 66 0
      src/components/Player.vue
  16. 40 0
      src/components/app.vue
  17. 53 0
      src/css/app.css
  18. 4 0
      src/css/app.less
  19. 56 0
      src/css/icons.css
  20. BIN
      src/fonts/Framework7Icons-Regular.ttf
  21. BIN
      src/fonts/Framework7Icons-Regular.woff
  22. BIN
      src/fonts/Framework7Icons-Regular.woff2
  23. 55 0
      src/fonts/_mixins.scss
  24. 3 0
      src/fonts/_variables.scss
  25. 24 0
      src/fonts/filled.css
  26. 4 0
      src/fonts/filled.scss
  27. BIN
      src/fonts/material-icons-outlined.woff
  28. BIN
      src/fonts/material-icons-outlined.woff2
  29. BIN
      src/fonts/material-icons-round.woff
  30. BIN
      src/fonts/material-icons-round.woff2
  31. BIN
      src/fonts/material-icons-sharp.woff
  32. BIN
      src/fonts/material-icons-sharp.woff2
  33. BIN
      src/fonts/material-icons-two-tone.woff
  34. BIN
      src/fonts/material-icons-two-tone.woff2
  35. 124 0
      src/fonts/material-icons.css
  36. 5 0
      src/fonts/material-icons.scss
  37. BIN
      src/fonts/material-icons.woff
  38. BIN
      src/fonts/material-icons.woff2
  39. 24 0
      src/fonts/outlined.css
  40. 4 0
      src/fonts/outlined.scss
  41. 24 0
      src/fonts/round.css
  42. 4 0
      src/fonts/round.scss
  43. 24 0
      src/fonts/sharp.css
  44. 4 0
      src/fonts/sharp.scss
  45. 24 0
      src/fonts/two-tone.css
  46. 4 0
      src/fonts/two-tone.scss
  47. 34 0
      src/index.html
  48. 30 0
      src/js/app.js
  49. 32 0
      src/js/radiomanifest.js
  50. 27 0
      src/js/routes.js
  51. 14 0
      src/js/store.js
  52. 12 0
      src/pages/404.vue
  53. 46 0
      src/pages/Radio.vue
  54. 19 0
      src/pages/Show.vue
  55. 16 0
      src/pages/home.vue
  56. 6 0
      tailwind.config.js
  57. 34 0
      vite.config.js

+ 42 - 0
.gitignore

@@ -0,0 +1,42 @@
+
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Dependency directories
+node_modules/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+
+# Misc
+.DS_Store
+Thumbs.db
+
+
+
+
+
+# Production build
+www/

BIN
assets-src/apple-touch-icon.png


BIN
assets-src/web-icon.png


+ 19 - 0
framework7.json

@@ -0,0 +1,19 @@
+{
+  "cwd": "/home/les/dev/plaid2",
+  "type": [
+    "web"
+  ],
+  "name": "plaid",
+  "framework": "vue",
+  "template": "single-view",
+  "bundler": "vite",
+  "cssPreProcessor": false,
+  "theming": {
+    "customColor": false,
+    "color": "#007aff",
+    "darkTheme": false,
+    "iconFonts": true,
+    "fillBars": true
+  },
+  "customBuild": false
+}

+ 41 - 0
package.json

@@ -0,0 +1,41 @@
+{
+  "name": "plaid",
+  "private": true,
+  "version": "1.0.0",
+  "description": "plaid",
+  "repository": "",
+  "license": "UNLICENSED",
+  "scripts": {
+    "start": "npm run dev",
+    "dev": "cross-env NODE_ENV=development vite",
+    "build": "cross-env NODE_ENV=production vite build",
+    "postinstall": "cpy --flat ./node_modules/framework7-icons/fonts/*.* ./src/fonts/ && cpy --flat ./node_modules/material-icons/iconfont/*.* ./src/fonts/"
+  },
+  "browserslist": [
+    "IOS >= 13",
+    "Safari >= 13",
+    "last 5 Chrome versions",
+    "last 5 Firefox versions",
+    "Samsung >= 12"
+  ],
+  "dependencies": {
+    "dom7": "^4.0.4",
+    "framework7": "^7.1.2",
+    "framework7-icons": "^5.0.5",
+    "framework7-vue": "^7.1.2",
+    "howler": "^2.2.3",
+    "material-icons": "^1.13.1",
+    "skeleton-elements": "^4.0.1",
+    "swiper": "^8.4.6",
+    "tailwindcss": "^3.2.4",
+    "vue": "^3.2.45"
+  },
+  "devDependencies": {
+    "@vitejs/plugin-vue": "^4.0.0",
+    "@vue/compiler-sfc": "^3.2.45",
+    "cpy-cli": "^4.2.0",
+    "cross-env": "^7.0.3",
+    "postcss-preset-env": "^7.8.3",
+    "vite": "^4.0.4"
+  }
+}

BIN
public/icons/128x128.png


BIN
public/icons/144x144.png


BIN
public/icons/152x152.png


BIN
public/icons/192x192.png


BIN
public/icons/256x256.png


BIN
public/icons/512x512.png


BIN
public/icons/apple-touch-icon.png


BIN
public/icons/favicon.png


+ 88 - 0
src/components/Button.vue

@@ -0,0 +1,88 @@
+<template >
+  <div class='playStopButton' @click='togglePlay' :class='{ active: status === "play", loading }'>
+    <!-- //- <svg version="1.1" xmlns="http://www.w3.org/2000/svg" fill='white' xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" xml:space="preserve">
+    //-   <circle id='circle' cx="50%" cy="50%" r="5%" fill/>
+    //- </svg> -->
+    <div id='stop'>
+      <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
+        <g><g transform="translate(0.000000,500.000000) scale(0.100000,-0.100000)"><path d="M3598.3,1507.4l-46.2-48.3v-1354v-1356.1l48.3-44.1l48.3-46.2h1354h1356.1l44.1,48.3l46.2,48.3v1354v1356l-48.3,44.1l-48.3,46.2h-1354h-1356L3598.3,1507.4z"/></g></g>
+      </svg>
+    </div>
+    <div id='play'>
+      <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
+        <g><g transform="translate(0.000000,500.000000) scale(0.100000,-0.100000)"><path d="M3885.7,2036.4c-29.2-29.2-33.4-229.6-33.4-1888.8c0-1241.8,6.3-1872.1,20.9-1899.2c27.1-48,104.4-52.2,194.1-6.3C4286.4-1645.2,7143.6,14,7166.6,41.2c33.4,41.7,33.4,154.4-2.1,196.2c-20.9,27.1-2876,1686.3-3097.2,1799C3983.8,2078.1,3927.5,2078.1,3885.7,2036.4z"/></g></g>
+      </svg>
+    </div>
+  </div>
+
+</template>
+
+<script>
+
+export default {
+  data () {
+    return {
+      loading: false,
+      status: 'stop'
+    }
+  },
+  methods: {
+    play () {
+      this.status = 'play'
+    },
+    stop () {
+      this.status = 'stop'
+    },
+    togglePlay () {
+      this.status = this.status === 'play' ? 'stop' : 'play'
+      this.$emit(this.status)
+    }
+  }
+}
+</script>
+<style scoped>
+.playStopButton {
+  width: 60px;
+  height: 60px;
+  margin: 5px 0px 5px 5px;
+  cursor: pointer;
+  position: relative;
+}
+
+.playStopButton:focus {
+  outline:0;
+}
+
+.playStopButton.active #play {
+  transform: rotate( 90deg ) scale( 0 );
+  opacity: 0;
+}
+
+.playStopButton:not( .active ) #stop  {
+  transform: rotate( -90deg ) scale( 0 );
+  opacity: 0;
+}
+
+.playStopButton  svg {
+  height: 100%;
+  width: 100%;
+}
+
+
+#play, #stop {
+  width: 100%;
+  height: 100%;
+  transition: all .35s ease-in-out;
+  position: absolute;
+  stroke: rgba(248, 113, 113, var(--tw-text-opacity));
+  fill:rgba(248, 113, 113, var(--tw-text-opacity));
+  top: 0px;
+  left: 0px;
+}
+
+#circle {
+  fill: none;
+  stroke: red;
+  stroke-width: 3px;
+}
+</style>

+ 66 - 0
src/components/Player.vue

@@ -0,0 +1,66 @@
+<template>
+  <div class="bg-gray-800 rounded-sm">
+    <div class="flex items-center space-x-3.5 sm:space-x-5 lg:space-x-3.5 xl:space-x-5">
+      <Button class='text-red-400' ref='button' @play='play' @stop='stop' />
+      <div class="min-w-0 flex-auto space-y-0.5">
+        <!-- //- <p class="text-white text-sm sm:text-base lg:text-sm xl:text-base font-semibold uppercase">
+        //-   <abbr title="Episode">Ep.</abbr> 128
+        //- </p> -->
+        <h2 class="text-white text-base sm:text-xl lg:text-base xl:text-xl font-semibold truncate" v-text='title'>
+        </h2>
+        <!-- //- <p class="text-gray-400 text-base sm:text-lg lg:text-base xl:text-lg font-medium">
+        //-   Full Stack Radio
+        //- </p> -->
+      </div>
+    </div>
+  </div>
+
+
+</template>
+
+<script>
+import { Howl } from 'howler'
+import Button from './Button.vue'
+
+export default {
+  components: { Button },
+  data () {
+    return {
+      loading: true,
+      status: 'pause',
+      volume: 100,
+      title: 'RadioBlackout > DIRETTA',
+      subtitle: '',
+      live: true,
+      player: null
+    }
+  },
+  // destroyed () {
+  //   this.$nuxt.$off('play:podcast', this.stop)
+  // },
+  // mounted () {
+  //   this.$nuxt.$on('play:podcast', this.stop)
+  // },
+  methods: {
+    play () {
+      const rnd = Math.random()
+      this.player = new Howl({
+        autoSuspend: false,
+        html5: true,
+        preload: true,
+        src: ['https://stream.radioblackout.org/blackout.ogg?rnd=' + rnd,
+        'https://stream.radioblackout.org/blackout.mp3'],
+      })      
+      this.player.play()
+      this.$nuxt.$emit('play:player')
+    },
+    stop () {
+      if (this.player) {
+        this.player.stop()
+      }
+      this.$refs.button.stop()
+    },
+  }
+}
+</script>
+

+ 40 - 0
src/components/app.vue

@@ -0,0 +1,40 @@
+<script setup>
+  import Player from '../components/Player.vue'  
+  import routes from '../js/routes.js';
+  import store from '../js/store';
+
+  // Framework7 Parameters
+  const f7params = {
+    name: 'plaid', // App name
+    theme: 'ios', // Automatic theme detection
+    view: {
+      browserHistory: true,
+      iosDynamicNavbar: true,
+      xhrCache: false,
+      masterDetailBreakpoint: 800,
+      main: true,
+    },
+
+    // passRouteParamsToRequest: true,
+    // App store
+    store,
+
+    // App routes
+    routes,
+  };
+
+</script>
+<template>
+  <f7-app v-bind="f7params" >
+    <!-- Top Navbar -->
+    <f7-toolbar>
+      <Player />
+    </f7-toolbar>
+    <f7-navbar back-link="Back" title='plaid' />
+
+    <!-- Your main view, should have "view-main" class -->
+    <f7-view main url="/"></f7-view>
+
+    
+  </f7-app>
+</template>

+ 53 - 0
src/css/app.css

@@ -0,0 +1,53 @@
+/* Your app custom styles here */
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+/* Invert navigation bars to fill style */
+:root,
+:root.dark,
+:root .dark {
+  --f7-bars-bg-color: var(--f7-theme-color);
+  --f7-bars-bg-color-rgb: var(--f7-theme-color-rgb);
+  --f7-bars-translucent-opacity: 0.9;
+  --f7-bars-text-color: #fff;
+  --f7-bars-link-color: #fff;
+  --f7-navbar-subtitle-text-color: rgba(255,255,255,0.85);
+  --f7-bars-border-color: transparent;
+  --f7-tabbar-link-active-color: #fff;
+  --f7-tabbar-link-inactive-color: rgba(255,255,255,0.54);
+  --f7-sheet-border-color: transparent;
+  --f7-tabbar-link-active-border-color: #fff;
+}
+.appbar,
+.navbar,
+.toolbar,
+.subnavbar,
+.calendar-header,
+.calendar-footer {
+  --f7-touch-ripple-color: var(--f7-touch-ripple-white);
+  --f7-link-highlight-color: var(--f7-link-highlight-white);
+  --f7-link-touch-ripple-color: var(--f7-touch-ripple-white);
+  --f7-button-text-color: #fff;
+  --f7-button-pressed-bg-color: rgba(255,255,255,0.1);
+}
+.navbar-large-transparent,
+.navbar-large.navbar-transparent {
+  --f7-navbar-large-title-text-color: #000;
+
+  --r: 0;
+  --g: 122;
+  --b: 255;
+  --progress: var(--f7-navbar-large-collapse-progress);
+  --f7-bars-link-color: rgb(
+    calc(var(--r) + (255 - var(--r)) * var(--progress)),
+    calc(var(--g) + (255 - var(--g)) * var(--progress)),
+    calc(var(--b) + (255 - var(--b)) * var(--progress))
+  );
+}
+.dark .navbar-large-transparent,
+.dark .navbar-large.navbar-transparent {
+  --f7-navbar-large-title-text-color: #fff;
+}
+
+/* Your app custom styles here */

+ 4 - 0
src/css/app.less

@@ -0,0 +1,4 @@
+/* Your app custom styles here */
+@tailwind base;
+@tailwind components;
+@tailwind utilities;

+ 56 - 0
src/css/icons.css

@@ -0,0 +1,56 @@
+/* Material Icons Font (for MD theme) */
+@font-face {
+  font-family: 'Material Icons';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Material Icons'), local('MaterialIcons-Regular'),
+    url(../fonts/material-icons.woff2) format('woff2'),
+    url(../fonts/material-icons.woff) format('woff');
+}
+.material-icons {
+  font-family: 'Material Icons';
+  font-weight: normal;
+  font-style: normal;
+  font-size: 24px;
+  display: inline-block;
+  line-height: 1;
+  text-transform: none;
+  letter-spacing: normal;
+  word-wrap: normal;
+  white-space: nowrap;
+  direction: ltr;
+  -webkit-font-smoothing: antialiased;
+  text-rendering: optimizeLegibility;
+  -moz-osx-font-smoothing: grayscale;
+  font-feature-settings: 'liga';
+}
+
+/* Framework7 Icons Font (for iOS theme) */
+@font-face {
+  font-family: 'Framework7 Icons';
+  font-style: normal;
+  font-weight: 400;
+  src: url('../fonts/Framework7Icons-Regular.woff2') format('woff2'),
+    url('../fonts/Framework7Icons-Regular.woff') format('woff');
+}
+.f7-icons {
+  font-family: 'Framework7 Icons';
+  font-weight: normal;
+  font-style: normal;
+  font-size: 28px;
+  line-height: 1;
+  letter-spacing: normal;
+  text-transform: none;
+  display: inline-block;
+  white-space: nowrap;
+  word-wrap: normal;
+  direction: ltr;
+  -webkit-font-smoothing: antialiased;
+  text-rendering: optimizeLegibility;
+  -moz-osx-font-smoothing: grayscale;
+  -webkit-font-feature-settings: 'liga';
+  -moz-font-feature-settings: 'liga=1';
+  -moz-font-feature-settings: 'liga';
+  font-feature-settings: 'liga';
+  text-align: center;
+}

BIN
src/fonts/Framework7Icons-Regular.ttf


BIN
src/fonts/Framework7Icons-Regular.woff


BIN
src/fonts/Framework7Icons-Regular.woff2


+ 55 - 0
src/fonts/_mixins.scss

@@ -0,0 +1,55 @@
+// @see https://github.com/twbs/bootstrap/blob/main/scss/_functions.scss
+@function material-icons-str-replace($string, $search, $replace: '') {
+  $index: str-index($string, $search);
+  @if $index {
+    @return str-slice($string, 1, $index - 1) + $replace +
+      material-icons-str-replace(
+        str-slice($string, $index + str-length($search)),
+        $search,
+        $replace
+      );
+  }
+  @return $string;
+}
+
+@mixin material-icons-font-class($font-family) {
+  font-family: $font-family;
+  font-weight: normal;
+  font-style: normal;
+  font-size: $material-icons-font-size;
+  line-height: 1;
+  letter-spacing: normal;
+  text-transform: none;
+  display: inline-block;
+  white-space: nowrap;
+  word-wrap: normal;
+  direction: ltr;
+  -webkit-font-smoothing: antialiased; // Support for all WebKit browsers
+  -moz-osx-font-smoothing: grayscale; // Support for Firefox
+  text-rendering: optimizeLegibility; // Support for Safari and Chrome
+  font-feature-settings: 'liga'; // Support for IE
+}
+
+@mixin material-icons-font($font-family) {
+  $class-name: to-lower-case($font-family);
+  $class-name: material-icons-str-replace($class-name, ' ', '-');
+  $font-file: $material-icons-font-path + $class-name;
+
+  @font-face {
+    font-family: $font-family;
+    font-style: normal;
+    font-weight: 400;
+    font-display: $material-icons-font-display;
+    src: url('#{$font-file}.woff2') format('woff2'),
+      url('#{$font-file}.woff') format('woff');
+  }
+
+  .#{$class-name} {
+    @include material-icons-font-class($font-family);
+  }
+}
+
+@mixin material-icons() {
+  @warn "material-icons() Sass mixin has been deprecated as of 1.0. Use '@extend .material-icons;' instead of '@include material-icons();'.";
+  @include material-icons-font-class('Material Icons');
+}

+ 3 - 0
src/fonts/_variables.scss

@@ -0,0 +1,3 @@
+$material-icons-font-path: './' !default;
+$material-icons-font-size: 24px !default;
+$material-icons-font-display: block !default;

+ 24 - 0
src/fonts/filled.css

@@ -0,0 +1,24 @@
+@font-face {
+  font-family: "Material Icons";
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: url("./material-icons.woff2") format("woff2"), url("./material-icons.woff") format("woff");
+}
+.material-icons {
+  font-family: "Material Icons";
+  font-weight: normal;
+  font-style: normal;
+  font-size: 24px;
+  line-height: 1;
+  letter-spacing: normal;
+  text-transform: none;
+  display: inline-block;
+  white-space: nowrap;
+  word-wrap: normal;
+  direction: ltr;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  text-rendering: optimizeLegibility;
+  font-feature-settings: "liga";
+}

+ 4 - 0
src/fonts/filled.scss

@@ -0,0 +1,4 @@
+@import 'variables';
+@import 'mixins';
+
+@include material-icons-font('Material Icons');

BIN
src/fonts/material-icons-outlined.woff


BIN
src/fonts/material-icons-outlined.woff2


BIN
src/fonts/material-icons-round.woff


BIN
src/fonts/material-icons-round.woff2


BIN
src/fonts/material-icons-sharp.woff


BIN
src/fonts/material-icons-sharp.woff2


BIN
src/fonts/material-icons-two-tone.woff


BIN
src/fonts/material-icons-two-tone.woff2


+ 124 - 0
src/fonts/material-icons.css

@@ -0,0 +1,124 @@
+@font-face {
+  font-family: "Material Icons";
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: url("./material-icons.woff2") format("woff2"), url("./material-icons.woff") format("woff");
+}
+.material-icons {
+  font-family: "Material Icons";
+  font-weight: normal;
+  font-style: normal;
+  font-size: 24px;
+  line-height: 1;
+  letter-spacing: normal;
+  text-transform: none;
+  display: inline-block;
+  white-space: nowrap;
+  word-wrap: normal;
+  direction: ltr;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  text-rendering: optimizeLegibility;
+  font-feature-settings: "liga";
+}
+
+@font-face {
+  font-family: "Material Icons Outlined";
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: url("./material-icons-outlined.woff2") format("woff2"), url("./material-icons-outlined.woff") format("woff");
+}
+.material-icons-outlined {
+  font-family: "Material Icons Outlined";
+  font-weight: normal;
+  font-style: normal;
+  font-size: 24px;
+  line-height: 1;
+  letter-spacing: normal;
+  text-transform: none;
+  display: inline-block;
+  white-space: nowrap;
+  word-wrap: normal;
+  direction: ltr;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  text-rendering: optimizeLegibility;
+  font-feature-settings: "liga";
+}
+
+@font-face {
+  font-family: "Material Icons Round";
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: url("./material-icons-round.woff2") format("woff2"), url("./material-icons-round.woff") format("woff");
+}
+.material-icons-round {
+  font-family: "Material Icons Round";
+  font-weight: normal;
+  font-style: normal;
+  font-size: 24px;
+  line-height: 1;
+  letter-spacing: normal;
+  text-transform: none;
+  display: inline-block;
+  white-space: nowrap;
+  word-wrap: normal;
+  direction: ltr;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  text-rendering: optimizeLegibility;
+  font-feature-settings: "liga";
+}
+
+@font-face {
+  font-family: "Material Icons Sharp";
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: url("./material-icons-sharp.woff2") format("woff2"), url("./material-icons-sharp.woff") format("woff");
+}
+.material-icons-sharp {
+  font-family: "Material Icons Sharp";
+  font-weight: normal;
+  font-style: normal;
+  font-size: 24px;
+  line-height: 1;
+  letter-spacing: normal;
+  text-transform: none;
+  display: inline-block;
+  white-space: nowrap;
+  word-wrap: normal;
+  direction: ltr;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  text-rendering: optimizeLegibility;
+  font-feature-settings: "liga";
+}
+
+@font-face {
+  font-family: "Material Icons Two Tone";
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: url("./material-icons-two-tone.woff2") format("woff2"), url("./material-icons-two-tone.woff") format("woff");
+}
+.material-icons-two-tone {
+  font-family: "Material Icons Two Tone";
+  font-weight: normal;
+  font-style: normal;
+  font-size: 24px;
+  line-height: 1;
+  letter-spacing: normal;
+  text-transform: none;
+  display: inline-block;
+  white-space: nowrap;
+  word-wrap: normal;
+  direction: ltr;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  text-rendering: optimizeLegibility;
+  font-feature-settings: "liga";
+}

+ 5 - 0
src/fonts/material-icons.scss

@@ -0,0 +1,5 @@
+@import 'filled';
+@import 'outlined';
+@import 'round';
+@import 'sharp';
+@import 'two-tone';

BIN
src/fonts/material-icons.woff


BIN
src/fonts/material-icons.woff2


+ 24 - 0
src/fonts/outlined.css

@@ -0,0 +1,24 @@
+@font-face {
+  font-family: "Material Icons Outlined";
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: url("./material-icons-outlined.woff2") format("woff2"), url("./material-icons-outlined.woff") format("woff");
+}
+.material-icons-outlined {
+  font-family: "Material Icons Outlined";
+  font-weight: normal;
+  font-style: normal;
+  font-size: 24px;
+  line-height: 1;
+  letter-spacing: normal;
+  text-transform: none;
+  display: inline-block;
+  white-space: nowrap;
+  word-wrap: normal;
+  direction: ltr;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  text-rendering: optimizeLegibility;
+  font-feature-settings: "liga";
+}

+ 4 - 0
src/fonts/outlined.scss

@@ -0,0 +1,4 @@
+@import 'variables';
+@import 'mixins';
+
+@include material-icons-font('Material Icons Outlined');

+ 24 - 0
src/fonts/round.css

@@ -0,0 +1,24 @@
+@font-face {
+  font-family: "Material Icons Round";
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: url("./material-icons-round.woff2") format("woff2"), url("./material-icons-round.woff") format("woff");
+}
+.material-icons-round {
+  font-family: "Material Icons Round";
+  font-weight: normal;
+  font-style: normal;
+  font-size: 24px;
+  line-height: 1;
+  letter-spacing: normal;
+  text-transform: none;
+  display: inline-block;
+  white-space: nowrap;
+  word-wrap: normal;
+  direction: ltr;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  text-rendering: optimizeLegibility;
+  font-feature-settings: "liga";
+}

+ 4 - 0
src/fonts/round.scss

@@ -0,0 +1,4 @@
+@import 'variables';
+@import 'mixins';
+
+@include material-icons-font('Material Icons Round');

+ 24 - 0
src/fonts/sharp.css

@@ -0,0 +1,24 @@
+@font-face {
+  font-family: "Material Icons Sharp";
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: url("./material-icons-sharp.woff2") format("woff2"), url("./material-icons-sharp.woff") format("woff");
+}
+.material-icons-sharp {
+  font-family: "Material Icons Sharp";
+  font-weight: normal;
+  font-style: normal;
+  font-size: 24px;
+  line-height: 1;
+  letter-spacing: normal;
+  text-transform: none;
+  display: inline-block;
+  white-space: nowrap;
+  word-wrap: normal;
+  direction: ltr;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  text-rendering: optimizeLegibility;
+  font-feature-settings: "liga";
+}

+ 4 - 0
src/fonts/sharp.scss

@@ -0,0 +1,4 @@
+@import 'variables';
+@import 'mixins';
+
+@include material-icons-font('Material Icons Sharp');

+ 24 - 0
src/fonts/two-tone.css

@@ -0,0 +1,24 @@
+@font-face {
+  font-family: "Material Icons Two Tone";
+  font-style: normal;
+  font-weight: 400;
+  font-display: block;
+  src: url("./material-icons-two-tone.woff2") format("woff2"), url("./material-icons-two-tone.woff") format("woff");
+}
+.material-icons-two-tone {
+  font-family: "Material Icons Two Tone";
+  font-weight: normal;
+  font-style: normal;
+  font-size: 24px;
+  line-height: 1;
+  letter-spacing: normal;
+  text-transform: none;
+  display: inline-block;
+  white-space: nowrap;
+  word-wrap: normal;
+  direction: ltr;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  text-rendering: optimizeLegibility;
+  font-feature-settings: "liga";
+}

+ 4 - 0
src/fonts/two-tone.scss

@@ -0,0 +1,4 @@
+@import 'variables';
+@import 'mixins';
+
+@include material-icons-font('Material Icons Two Tone');

+ 34 - 0
src/index.html

@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <!--
+  Customize this policy to fit your own app's needs. For more guidance, please refer to the docs:
+      https://cordova.apache.org/docs/en/latest/
+  Some notes:
+    * https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly
+    * Disables use of inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:
+      * Enable inline JS: add 'unsafe-inline' to default-src
+  -->
+  <meta http-equiv="Content-Security-Policy" content="default-src * 'self' 'unsafe-inline' 'unsafe-eval' data: content:">
+  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, viewport-fit=cover">
+
+  <meta name="theme-color" content="#007aff">
+  <meta name="format-detection" content="telephone=no">
+  <meta name="msapplication-tap-highlight" content="no">
+  <title>plaid</title>
+  
+  <meta name="apple-mobile-web-app-capable" content="yes">
+  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
+  <link rel="apple-touch-icon" href="icons/apple-touch-icon.png">
+  <link rel="icon" href="icons/favicon.png">
+  
+  
+  <!-- built styles file will be auto injected -->
+</head>
+<body>
+  <div id="app"></div>
+  
+  <script type="module" src="./js/app.js"></script>
+</body>
+</html>

+ 30 - 0
src/js/app.js

@@ -0,0 +1,30 @@
+// Import Vue
+import { createApp } from 'vue';
+
+// Import Framework7
+import Framework7 from 'framework7/lite-bundle';
+
+// Import Framework7-Vue Plugin
+import Framework7Vue, { registerComponents } from 'framework7-vue/bundle';
+
+// Import Framework7 Styles
+import 'framework7/css/bundle';
+
+// Import Icons and App Custom Styles
+import '../css/icons.css';
+import '../css/app.css';
+
+// Import App Component
+import App from '../components/app.vue';
+
+// Init Framework7-Vue Plugin
+Framework7.use(Framework7Vue);
+
+// Init App
+const app = createApp(App);
+
+// Register Framework7 Vue components
+registerComponents(app);
+
+// Mount the app
+app.mount('#app');

+ 32 - 0
src/js/radiomanifest.js

@@ -0,0 +1,32 @@
+import radiomanifest from 'radiomanifest'
+
+const cachedRadiomanifest = {}
+
+
+const RM = {
+
+  radio: {
+    'ROR': { name: 'Radio Onda Rossa', description: 'un segnale che disturba', url: 'https://www.ondarossa.info' },
+    'Spore':  { name: 'Radio Spore', description: 'una voce senza padrone', url: 'https://radiospore.oziosi.org' },
+    // 'RBO': { }
+  },
+
+  currentRadio : null,
+
+  async get (id) {
+    // check if this radio id exists
+    if (!RM.radio[id]) {
+      throw new Error('This radio id does not exists!')
+    }
+
+    // check if is cached, load it otherwise
+    if (!cachedRadiomanifest[id]) {
+      const radio = RM.radio[id]
+      cachedRadiomanifest[id] = await radiomanifest.get(radio.url)
+    }
+    this.currentRadio = cachedRadiomanifest[id]
+    return cachedRadiomanifest[id]
+  }
+}
+
+export default RM

+ 27 - 0
src/js/routes.js

@@ -0,0 +1,27 @@
+
+import HomePage from '../pages/home.vue'
+import RadioPage from '../pages/Radio.vue'
+import ShowPage from '../pages/Show.vue'
+import NotFoundPage from '../pages/404.vue'
+
+var routes = [
+  {
+    path: '/',
+    master: true,
+    component: HomePage,
+    detailRoutes: [{
+      path: '/radio/:radioName',
+      component: RadioPage,
+    },
+    {
+      path: '/radio/:radioName/:showName',
+      component: ShowPage
+    }],
+  },
+  {
+    path: '(.*)',
+    component: NotFoundPage,
+  },
+]
+
+export default routes

+ 14 - 0
src/js/store.js

@@ -0,0 +1,14 @@
+
+import { createStore } from 'framework7/lite'
+
+const store = createStore({
+  state: {
+    radios: [
+      { id: 1, name: 'Radio Onda Rossa', description: 'un segnale che disturba', url: 'https://www.ondarossa.info' },
+      { id: 2, name: 'Radio Spore', description: 'una voce senza padrone', url: 'https://radiospore.oziosi.org' },
+    ],
+  },
+  actions: {
+  },
+})
+export default store;

+ 12 - 0
src/pages/404.vue

@@ -0,0 +1,12 @@
+<template>
+  <f7-page>
+    <f7-navbar title="Not found" back-link="Back"></f7-navbar>
+    <f7-block strong>
+      <p>Sorry</p>
+      <p>Requested content not found.</p>
+    </f7-block>
+  </f7-page>
+</template>
+<script>
+  export default {};
+</script>

+ 46 - 0
src/pages/Radio.vue

@@ -0,0 +1,46 @@
+<template>
+  <f7-page name="radio">
+    <img :src='Radio.logo' id='logo'/> 
+    <f7-block-title>{{Radio.name}}</f7-block-title>
+    <f7-block-header>{{Radio.description}}</f7-block-header>
+
+    <f7-preloader v-if='loading' />
+    <f7-list v-else>
+        <f7-list-item v-for='show in Radio.shows' :key='show.name' :title='show.name' :link='`/radio/show/${show.name}`' :footer='show.description'/>
+    </f7-list>
+  </f7-page>    
+</template>
+
+<script>
+import radiomanifest from '../js/radiomanifest'
+
+export default {
+  name: 'radio',
+  data () {
+    return {
+      loading: true,
+      radioId: null,
+      radio: { name: '' },
+      Radio: { }
+    }
+  },
+  props: { f7route: Object, f7router: Object },
+  async mounted () {
+    try {
+      this.Radio = await radiomanifest.get(this.f7route.params.radioName)
+      // this.Radio.schedule.getNowShow(new Date())
+      console.error(this.Radio)
+      this.loading = false
+    } catch (e) {
+      console.error('le cose non vanno mai sempre bene!', e)
+    }
+  }
+}
+
+</script>
+<style>
+#logo {
+  margin-left: 10px;
+  max-width: 40px;
+}
+</style>

+ 19 - 0
src/pages/Show.vue

@@ -0,0 +1,19 @@
+<script setup>
+import radiomanifest from '../js/radiomanifest'
+const { f7Route } = defineProps({ f7Route: Object })
+
+const Radio = radiomanifest.currentRadio
+
+// ma non c'e' Radio.schedule.getShowPodcast ?
+
+</script>
+
+<template>
+  <f7-page name="show">
+
+    <f7-block-title>{{Radio.name}}</f7-block-title>
+    <f7-block-header>{{Radio.description}}</f7-block-header>
+    
+
+  </f7-page>    
+</template>

+ 16 - 0
src/pages/home.vue

@@ -0,0 +1,16 @@
+<script setup>
+import radiomanifest from '../js/radiomanifest'
+
+</script>
+<template>
+  <f7-page name="home">
+
+    <!-- Page content-->
+    <f7-block-title>Radio</f7-block-title>
+    <f7-list>
+      <f7-list-item v-for='(radio, id) in radiomanifest.radio' :key='id' :link="`/radio/${id}`" :title="radio.name" />
+    </f7-list>
+
+
+  </f7-page>
+</template>

+ 6 - 0
tailwind.config.js

@@ -0,0 +1,6 @@
+module.exports = {
+    purge: {
+      content: ['./src/index.html', './src/**/*.{vue,svelte,js,ts}'], 
+    },
+    plugins: [],
+  }

+ 34 - 0
vite.config.js

@@ -0,0 +1,34 @@
+
+import path from 'path';
+import vue from '@vitejs/plugin-vue';
+
+const SRC_DIR = path.resolve(__dirname, './src');
+const PUBLIC_DIR = path.resolve(__dirname, './public');
+const BUILD_DIR = path.resolve(__dirname, './www',);
+
+export default {
+  plugins: [
+    vue(),
+
+  ],
+  root: SRC_DIR,
+  base: '',
+  publicDir: PUBLIC_DIR,
+  build: {
+    outDir: BUILD_DIR,
+    assetsInlineLimit: 0,
+    emptyOutDir: true,
+    rollupOptions: {
+      treeshake: false,
+    },
+  },
+  resolve: {
+    alias: {
+      '@': SRC_DIR,
+    },
+  },
+  server: {
+    host: true,
+  },
+
+};