Browse Source

v1.2.0

tags/v1.4.4
Ivan Bravo Bravo 11 months ago
parent
commit
2878fa35dd
88 changed files with 3362 additions and 2824 deletions
  1. 1
    0
      .github/workflows/ci.yml
  2. 10
    14
      README.md
  3. 2
    0
      src/.env-cmdrc.js
  4. 2
    0
      src/.eslintrc.js
  5. 13
    0
      src/assets/css/base/_reset.scss
  6. 14
    13
      src/assets/css/components/_button.scss
  7. 1
    2
      src/assets/css/components/_container.scss
  8. 3
    2
      src/assets/css/components/_form.scss
  9. 2
    2
      src/assets/css/components/_notification.scss
  10. 0
    0
      src/assets/images/dreamnet.png
  11. 0
    0
      src/assets/videos/dreamnet.mp4
  12. 178
    0
      src/components/Layout/Jobbar.vue
  13. 0
    138
      src/components/Layout/Jobs.vue
  14. 13
    6
      src/components/Layout/Navbar.vue
  15. 1
    0
      src/components/Layout/Navigation.vue
  16. 3
    2
      src/components/Layout/Topbar.vue
  17. 2
    2
      src/components/Layout/index.js
  18. 0
    329
      src/components/Nudity/Job.vue
  19. 293
    0
      src/components/Nudity/PhotoRun.vue
  20. 0
    59
      src/components/Nudity/Preview.vue
  21. 0
    290
      src/components/Nudity/Upload.backup.vue
  22. 56
    22
      src/components/Nudity/Upload.vue
  23. 4
    6
      src/components/Nudity/index.js
  24. 4
    1
      src/components/Settings/SettingsPreferences.vue
  25. 25
    16
      src/components/UI/AppPhoto.vue
  26. 38
    23
      src/components/UI/AppUpdate.vue
  27. 26
    16
      src/components/UI/BoxItem.vue
  28. 9
    2
      src/electron-builder.js
  29. 98
    74
      src/electron/src/index.js
  30. 10
    11
      src/electron/src/modules/services/base.js
  31. 36
    20
      src/electron/src/modules/services/settings.js
  32. 52
    29
      src/electron/src/modules/tools/fs.js
  33. 2
    0
      src/electron/src/modules/tools/index.js
  34. 9
    7
      src/electron/src/modules/tools/paths.js
  35. 2
    15
      src/electron/src/modules/tools/photo.js
  36. 73
    56
      src/electron/src/modules/tools/power.js
  37. 19
    10
      src/electron/src/modules/tools/system.js
  38. 0
    2
      src/electron/src/provider.js
  39. 24
    17
      src/layouts/default.vue
  40. 8
    17
      src/middleware/checks.js
  41. 6
    2
      src/mixins/BaseMixin.js
  42. 15
    9
      src/modules/app-error.js
  43. 10
    10
      src/modules/config/cli-errors.json
  44. 29
    56
      src/modules/file.js
  45. 49
    11
      src/modules/helpers.js
  46. 0
    2
      src/modules/models/index.js
  47. 0
    5
      src/modules/models/model.js
  48. 0
    292
      src/modules/models/photo-job.js
  49. 0
    282
      src/modules/models/photo.js
  50. 1
    0
      src/modules/nudify/index.js
  51. 44
    0
      src/modules/nudify/nudify-store.js
  52. 147
    62
      src/modules/nudify/nudify.js
  53. 309
    0
      src/modules/nudify/photo-run.js
  54. 285
    31
      src/modules/nudify/photo.js
  55. 24
    17
      src/modules/updater/base.js
  56. 6
    6
      src/modules/updater/checkpoints.js
  57. 10
    11
      src/modules/updater/dreampower.js
  58. 3
    2
      src/modules/updater/dreamtime.js
  59. 0
    0
      src/modules/updater/index.js
  60. 0
    19
      src/modules/web-error.js
  61. 1
    1
      src/nuxt.config.js
  62. 155
    0
      src/package.copy.json
  63. 5
    3
      src/package.json
  64. 266
    0
      src/pages/about.vue
  65. 3
    3
      src/pages/dreamnet.vue
  66. 9
    11
      src/pages/index.vue
  67. 126
    44
      src/pages/nudify/_id.vue
  68. 46
    77
      src/pages/nudify/_id/crop.vue
  69. 457
    0
      src/pages/nudify/_id/overlay.vue
  70. 1
    1
      src/pages/nudify/_id/preferences.vue
  71. 22
    120
      src/pages/nudify/_id/results.vue
  72. 0
    67
      src/pages/nudify/_id/summary.vue
  73. 106
    0
      src/pages/settings.vue
  74. 44
    0
      src/pages/settings/app.vue
  75. 4
    5
      src/pages/settings/folders.vue
  76. 0
    0
      src/pages/settings/notifications.vue
  77. 0
    0
      src/pages/settings/preferences.vue
  78. 2
    10
      src/pages/settings/processing.vue
  79. 1
    1
      src/pages/settings/telemetry.vue
  80. 0
    312
      src/pages/system/about.vue
  81. 0
    78
      src/pages/system/settings.vue
  82. 0
    0
      src/pages/welcome.vue
  83. 13
    41
      src/plugins/boot.js
  84. 100
    24
      src/scripts/release.js
  85. BIN
      src/static/assets/images/background2.png
  86. BIN
      src/static/assets/images/dreampower.png
  87. BIN
      src/static/assets/images/dreamtime.png
  88. 30
    6
      src/tailwind.config.js

+ 1
- 0
.github/workflows/ci.yml View File

@@ -87,6 +87,7 @@ jobs:
working-directory: src/scripts
continue-on-error: true
env:
SECRET_KEY: ${{ secrets.SECRET_KEY }}
GITHUB_TOKEN: ${{ secrets.TOKEN }}
GITHUB_SHA: ${{ github.sha }}
GITHUB_REF: ${{ github.ref }}

+ 10
- 14
README.md View File

@@ -11,7 +11,7 @@

# DreamTime

DreamTime allows you to use the power of your computer to transform photos of people into **private and FREE entertainment**, better than DeepNude.
DreamTime allows you to use the power of your computer to to undress photos for free, better than DeepNude.

![](assets/preview.png)

@@ -34,6 +34,7 @@ If you want to share or modify this Software please do it for the same purpose a
### GPU Processing

- NVIDIA GPU with minimum [3.5 CUDA compute capability.](https://developer.nvidia.com/cuda-gpus)
- **6 GB+** of VRAM.
- [Latest NVIDIA drivers.](https://www.nvidia.com/Download/index.aspx)

> ๐Ÿ‘‰ If you do not have an NVIDIA or compatible GPU you can use CPU processing.
@@ -46,11 +47,11 @@ If you want to share or modify this Software please do it for the same purpose a

### Mirrors

[![Windows](https://img.shields.io/badge/windows-v1.1.1-0078D6?logo=windows&logoColor=white&style=for-the-badge)](https://catalina.dreamnet.tech/ipns/QmUvudWPzRa7hgDSVFiwzFzviAZJohTrvHJNhnvytuPv3H/Releases/DreamTime/v1.1.1/DreamTime-v1.1.1-windows.exe)
[![Windows](https://img.shields.io/badge/windows-v1.1.2-0078D6?logo=windows&logoColor=white&style=for-the-badge)](https://catalina.dreamnet.tech/ipns/QmUvudWPzRa7hgDSVFiwzFzviAZJohTrvHJNhnvytuPv3H/Releases/DreamTime/v1.1.2/DreamTime-v1.1.2-windows.exe)

[![Ubuntu](https://img.shields.io/badge/ubuntu-v1.1.1-E95420?logo=ubuntu&logoColor=white&style=for-the-badge)](https://catalina.dreamnet.tech/ipns/QmUvudWPzRa7hgDSVFiwzFzviAZJohTrvHJNhnvytuPv3H/Releases/DreamTime/v1.1.1/DreamTime-v1.1.1-ubuntu.deb)
[![Ubuntu](https://img.shields.io/badge/ubuntu-v1.1.2-E95420?logo=ubuntu&logoColor=white&style=for-the-badge)](https://catalina.dreamnet.tech/ipns/QmUvudWPzRa7hgDSVFiwzFzviAZJohTrvHJNhnvytuPv3H/Releases/DreamTime/v1.1.2/DreamTime-v1.1.2-ubuntu.deb)

[![macOS](https://img.shields.io/badge/macos-v1.1.1-999999?logo=Apple&logoColor=white&style=for-the-badge)](https://catalina.dreamnet.tech/ipns/QmUvudWPzRa7hgDSVFiwzFzviAZJohTrvHJNhnvytuPv3H/Releases/DreamTime/v1.1.1/DreamTime-v1.1.1-macos.dmg)
[![macOS](https://img.shields.io/badge/macos-v1.1.2-999999?logo=Apple&logoColor=white&style=for-the-badge)](https://catalina.dreamnet.tech/ipns/QmUvudWPzRa7hgDSVFiwzFzviAZJohTrvHJNhnvytuPv3H/Releases/DreamTime/v1.1.2/DreamTime-v1.1.2-macos.dmg)

# DreamNet

@@ -100,7 +101,7 @@ We do not store any personal information or photos that have been processed with
- [SCSS](https://sass-lang.com/): CSS Preprocessor
- [TailwindCSS](https://tailwindcss.com/): CSS Framework
- [VueJS](https://vuejs.org/), [NuxtJS](https://nuxtjs.org/): The JavaScript frameworks. _(VueJS is the best #changemymind)_
- [Electron](https://electronjs.org/): The software used to "transform" DreamTime from a website to a desktop program.
- [Electron](https://electronjs.org/): The software used to "transform" DreamTime from a website to a desktop program. ([Electron Haters](https://youtu.be/OLpeX4RRo28))

## Setup

@@ -114,9 +115,11 @@ Install dependencies:

Start development enviroment:

`yarn dev:nuxt`
`yarn start:nuxt`

`yarn dev:electron`
`yarn start:babel`

`yarn start:electron`

Build:

@@ -125,10 +128,3 @@ Build:
## Pull Requests

Pull Requests of all kinds are welcome! Please make sure you do it in the **canary branch**.

## โš  Drastic Changes in v1.0.0+

Because DreamTime has been the **victim of users who take the source code and sell it without complying with the LICENSE conditions**, we are forced to implement certain very unfriendly changes for an open-source project, we apologize for all the inconvenience this may cause, these changes are **temporary** until DreamTime has been noticed on social networks to prevent people from falling into a possible SCAM.

To avoid an alert with information from DreamTime
when you start your program, please make sure you **don't change the name or type of license** on your fork.

+ 2
- 0
src/.env-cmdrc.js View File

@@ -5,12 +5,14 @@ module.exports = {
"NUCLEUS_APPID": "5d353cecbe5ccc0133cf90f4"
},
"development": {
"name": "development",
"NODE_ENV": "development",
"LOG": "debug",
"DEVTOOLS": true,
"ROLLBAR_ACCESS_TOKEN": "6ccfcf317ca54e67830b41570ce23d2a"
},
"production": {
"name": "production",
"NODE_ENV": "production",
"LOG": "info"
},

+ 2
- 0
src/.eslintrc.js View File

@@ -40,6 +40,8 @@ module.exports = {
"import/no-extraneous-dependencies": "off",
"import/named": "off",
"import/no-cycle": "off",
"promise/no-callback-in-promise": "off",
"promise/catch-or-return": "off",
"linebreak-style": "warn",
"lodash/import-scope": [
"off",

+ 13
- 0
src/assets/css/base/_reset.scss View File

@@ -23,6 +23,7 @@ html {
}

body,
html,
#__nuxt,
#__layout {
@apply h-full;
@@ -61,4 +62,16 @@ body,
&:hover {
@apply bg-primary-700;
}
}

.swal2-html-container {
pre {
@apply text-xs overflow-auto bg-gray-300 p-2;
}
}

.swal2-footer {
code {
@apply text-sm text-center;
}
}

+ 14
- 13
src/assets/css/components/_button.scss View File

@@ -1,16 +1,17 @@
.button {
@apply inline-flex items-center justify-center;
@apply px-4 rounded uppercase font-semibold outline-none;
@apply text-primary-500 border border-primary-500-30;
@apply border border-primary-500-30;
@apply px-4 rounded-sm outline-none;
@apply text-primary-400 font-semibold uppercase;
height: 40px;
transition: all 0.2s ease-in-out;

&:hover {
@apply bg-primary-500-10;
@apply bg-primary-500-20;
}

&:active {
@apply bg-primary-500-20;
@apply bg-primary-500-30;
}

&.button--xs {
@@ -28,32 +29,32 @@
height: 51px;
}

&.is-active,
&.button--active,
&.nuxt-link-exact-active {
@apply text-white bg-primary-500;
}

&.is-danger {
@apply text-danger;
&.button--danger {
@apply text-danger-400 border-danger-500-30;

&:hover {
@apply bg-danger-500-10;
@apply bg-danger-500-20;
}

&:active {
@apply bg-danger-500-20;
@apply bg-danger-500-30;
}
}

&.is-success {
@apply text-success;
&.button--success {
@apply text-success-400 border-success-500-30;

&:hover {
@apply bg-success-500-10;
@apply bg-success-500-20;
}

&:active {
@apply bg-success-500-20;
@apply bg-success-500-30;
}
}
}

+ 1
- 2
src/assets/css/components/_container.scss View File

@@ -20,6 +20,5 @@
}

.content__body {
@apply pt-6 pl-6 pr-6;
//height: calc(100vh - 70px);
@apply p-6;
}

+ 3
- 2
src/assets/css/components/_form.scss View File

@@ -11,7 +11,8 @@
}

.input {
@apply border border-dark-800 bg-dark-600 rounded py-2 px-4 w-full text-generic-300 shadow-inner;
@apply border border-dark-300 bg-dark-600;
@apply rounded py-2 px-4 w-full text-generic-300 shadow-inner;
outline: none !important;
transition: all .2s ease-in-out;

@@ -20,7 +21,7 @@
}

&::placeholder {
@apply text-generic-400;
@apply text-generic-700;
}
}


+ 2
- 2
src/assets/css/components/_notification.scss View File

@@ -1,12 +1,12 @@
.notification {
@apply mb-4 p-4 bg-dark-600 border-2 border-dark-300 text-sm text-generic-100 rounded;
@apply mb-4 p-2 bg-transparent border-2 border-dark-500 text-sm text-generic-100 rounded-sm;

a {
@apply underline;
}

&.is-warning {
@apply bg-warning border-warning;
@apply text-warning border-warning;
}

&.is-danger {

src/static/assets/images/dreamnet.png → src/assets/images/dreamnet.png View File


src/static/assets/videos/dreamnet.mp4 → src/assets/videos/dreamnet.mp4 View File


+ 178
- 0
src/components/Layout/Jobbar.vue View File

@@ -0,0 +1,178 @@
<template>
<div class="layout__jobbar">
<div class="jobs__section">
<div class="section__title">
<span class="icon"><font-awesome-icon icon="running" /></span>
<span>Queue</span>
</div>

<div class="jobs__list">
<figure
v-for="(photo, index) of $nudify.waiting"
:key="index"
class="job"
:class="{ 'job--running': photo.running }"
@click.prevent="openJob(photo.id)">
<img :src="photo.file.dataURL">
</figure>
</div>
</div>

<div class="jobs__section">
<div class="section__title">
<div class="flex-1">
<span class="icon"><font-awesome-icon icon="clipboard-list" /></span>
<span>Pending</span>
</div>

<button v-show="$nudify.pending.length > 0" class="button button--xs" @click.prevent="$nudify.runAll()">
Run all
</button>
</div>

<div class="jobs__list">
<figure
v-for="(photo, index) of $nudify.pending"
:key="index"
class="job"
@click.prevent="openJob(photo.id)">
<img :src="photo.file.dataURL">
</figure>
</div>
</div>

<div class="jobs__section">
<div class="section__title">
<div class="flex-1">
<span class="icon"><font-awesome-icon icon="clipboard-check" /></span>
<span>Finished</span>
</div>

<button v-show="$nudify.finished.length > 0" class="button button--xs" @click.prevent="$nudify.runAll('finished')">
Rerun all
</button>
</div>

<div class="jobs__list">
<figure
v-for="(photo, index) of $nudify.finished"
:key="index"
class="job"
:class="{ 'job--failed': photo.failed }"
@click.prevent="openJob(photo.id)">
<img :src="photo.file.dataURL">
</figure>
</div>
</div>
</div>
</template>

<script>
export default {
methods: {
openJob(photoId) {
this.$router.push(`/nudify/${photoId}`)
},
},
}
</script>

<style lang="scss" scoped>
.layout__jobbar {
@apply relative bg-dark-500 z-10;
@apply flex flex-col py-2;
width: 200px;

&::after {
@apply border-r border-dark-300;
@apply block bottom-0 right-0 pointer-events-none absolute;
content: " ";
top: 50px;
}
}

.jobs__section {
@apply flex-1 flex flex-col;
@apply overflow-hidden;
}

.section__title {
@apply px-4 pt-2 text-sm text-white font-semibold;
@apply flex items-center;

.icon {
@apply mr-2;
}
}

.jobs__list {
@apply flex-1 flex flex-wrap justify-between;
@apply px-4 py-2 overflow-y-auto max-h-full;

.job {
@apply mb-2 cursor-pointer;
width: calc(1/3*100% - (1 - 1/3)*1rem);
height: 42px;
transition: all .1s ease-in-out;

&.job--running {

img {
@apply border-primary-500;
}
}

&.job--failed {
img {
@apply border-danger-500;
}
}

&:hover {
@apply z-30;
transform: scale(1.5)
}

img {
@apply border-2 border-transparent;
@apply w-full h-full rounded-full;
}
}

.job__preview {
@apply mr-4 h-full;
width: 42px;

img {
width: 42px;
height: 42px;
}
}

.job__name {
@apply flex-1 overflow-hidden whitespace-no-wrap;
text-overflow: ellipsis;
}
}

.layout-jobs {
@apply p-2 shadow h-screen flex flex-col;
width: 200px;

.jobs-pending {
@apply flex-1 border-b border-gray-300 mb-2;
}

.jobs-recent {
height: 250px;
}

.job-section {
@apply mb-4;
}

.section-title {
@apply font-bold;
}
}
</style>

+ 0
- 138
src/components/Layout/Jobs.vue View File

@@ -1,138 +0,0 @@
<template>
<div class="layout__jobs">
<div class="jobs__section">
<div class="section__title">
<span class="icon"><font-awesome-icon icon="running" /></span>
<span>Running</span>
</div>
</div>

<div class="jobs__section">
<div class="section__title">
<div class="flex-1">
<span class="icon"><font-awesome-icon icon="clipboard-list" /></span>
<span>Pending</span>
</div>

<button class="button button--xs">
Run all
</button>
</div>

<div class="jobs__list">
<div v-for="(photo, index) of pending" :key="index" class="job" @click.prevent="openJob(photo.id)">
<figure class="job__preview">
<img :src="photo.file.dataUrl">
</figure>

<span class="job__name">{{ photo.file.fullname }}</span>
</div>
</div>
</div>

<div class="jobs__section">
<div class="section__title">
<span class="icon"><font-awesome-icon icon="clipboard-check" /></span>
<span>Done</span>
</div>
</div>
</div>
</template>

<script>
import { events } from '~/modules'
import { Nudify } from '~/modules/nudify'

export default {
data: () => ({
running: [],
pending: [],
done: [],
}),

created() {
events.on('nudify.add', () => {
this.running = Nudify.running
this.pending = Nudify.pending
this.done = Nudify.done
})
},

methods: {
openJob(photoId) {
this.$router.push(`/nudify/${photoId}`)
},
},
}
</script>

<style lang="scss" scoped>
.layout__jobs {
@apply h-screen bg-dark-500;
@apply flex flex-col;
width: 200px;
}

.jobs__section {
@apply flex-1 flex flex-col;
@apply overflow-hidden;
}

.section__title {
@apply px-4 pt-2 text-sm uppercase font-semibold;
@apply flex items-center;

.icon {
@apply mr-2;
}
}

.jobs__list {
@apply flex-1 overflow-y-auto max-h-full;

.job {
@apply px-4 py-2 flex items-center cursor-pointer;
transition: all .1s ease-in-out;

&:hover {
@apply bg-dark-300 text-white;
}
}

.job__preview {
@apply mr-4 h-full;
width: 42px;

img {
width: 42px;
height: 42px;
}
}

.job__name {
@apply flex-1 overflow-hidden whitespace-no-wrap;
text-overflow: ellipsis;
}
}

.layout-jobs {
@apply p-2 shadow h-screen flex flex-col;
width: 200px;

.jobs-pending {
@apply flex-1 border-b border-gray-300 mb-2;
}

.jobs-recent {
height: 250px;
}

.job-section {
@apply mb-4;
}

.section-title {
@apply font-bold;
}
}
</style>

+ 13
- 6
src/components/Layout/Navbar.vue View File

@@ -9,7 +9,7 @@
About
</nuxt-link>

<nuxt-link class="navbar__item" to="/dreamnet">
<nuxt-link v-if="$provider.tools.system.canNudify" class="navbar__item" to="/dreamnet">
DreamNet
</nuxt-link>
</div>
@@ -27,22 +27,29 @@
<font-awesome-icon icon="code" />
</nuxt-link>

<nuxt-link v-tooltip="{placement: 'bottom', content: 'Donate'}" class="navbar__icon" to="/donate">
<font-awesome-icon icon="donate" />
</nuxt-link>
<a v-tooltip="{placement: 'bottom', content: 'Donate and get benefits!'}" class="navbar__icon" :href="donateUrl" target="_blank">
<font-awesome-icon :icon="['fab', 'patreon']" />
</a>
</div>
</div>
</template>

<script>
export default {
const { nucleus } = $provider.services

export default {
computed: {
donateUrl() {
return nucleus.urls?.support?.patreon || 'https://www.patreon.com/dreamnet'
},
},
}
</script>

<style lang="scss" scoped>
.layout__navbar {
@apply flex bg-dark-500 shadow-lg z-10;
@apply flex bg-dark-500 z-10;
@apply border-b border-dark-300;
height: 50px;

.navbar__left,

+ 1
- 0
src/components/Layout/Navigation.vue View File

@@ -85,6 +85,7 @@ export default {

.layout-menu {
@apply pb-6 shadow h-screen bg-dark-500 relative;
@apply border-r border-dark-300;
width: 200px;

.menu {

+ 3
- 2
src/components/Layout/Topbar.vue View File

@@ -82,8 +82,9 @@ export default {
}

.layout__topbar {
@apply flex bg-black text-white z-50;
@apply flex bg-black text-white;
height: 30px;
z-index: 9999999;

.topbar__left {
@apply flex-1 flex;
@@ -120,7 +121,7 @@ export default {
height: 30px;

&:hover {
@apply bg-black-50;
@apply bg-gray-700;

&.close {
@apply bg-danger-500;

+ 2
- 2
src/components/Layout/index.js View File

@@ -3,9 +3,9 @@ import Vue from 'vue'
import LayoutTopbar from './Topbar'
import LayoutNavigation from './Navigation'
import LayoutNavbar from './Navbar'
import LayoutJobs from './Jobs'
import LayoutJobbar from './Jobbar'

Vue.component('layout-topbar', LayoutTopbar)
Vue.component('layout-navbar', LayoutNavbar)
Vue.component('layout-jobbar', LayoutJobbar)
Vue.component('layout-navigation', LayoutNavigation)
Vue.component('layout-jobs', LayoutJobs)

+ 0
- 329
src/components/Nudity/Job.vue View File

@@ -1,329 +0,0 @@
<template>
<div class="c-nudity-job">
<figure class="__preview">
<img v-if="job.hasFinished" :src="outputDataURL">
<span v-else v-tooltip="'Loading...'">๐Ÿ’ญ</span>
</figure>

<div class="__content">
<!-- Actions -->
<details class="__section" open>
<summary class="__title">
Actions
</summary>

<div class="__buttons">
<button v-if="job.hasFinished" class="button is-success" @click.prevent="save">
Save
</button>
<button v-if="job.hasFinished || job.hasFailed" class="button is-danger is-sm" @click.prevent="rerun">
Rerun
</button>
</div>
</details>

<details v-if="job.hasFinished || job.isLoading" class="__section" open>
<summary class="__title">
Duration
</summary>

<div class="__status">
<p>{{ job.timer.duration }}s</p>
</div>
</details>

<details v-else-if="job.hasFailed" class="__section" open>
<summary class="__title">
Status
</summary>

<div class="__status text-danger">
<p>Fail</p>
</div>
</details>

<details v-else class="__section" open>
<summary class="__title">
Status
</summary>

<div class="__status">
<p>Pending...</p>
</div>
</details>

<!-- Preferences -->
<details class="__section">
<summary class="__title">
Preferences
</summary>

<div class="__preferences">
<p>
<span class="__name">Boobs size</span>
<span class="__value">{{ job.preferences.body.boobs.size | size }}</span>
</p>

<p>
<span class="__name">Areola size</span>
<span class="__value">{{ job.preferences.body.areola.size | size }}</span>
</p>

<p>
<span class="__name">Nipple size</span>
<span class="__value">{{ job.preferences.body.nipple.size | size }}</span>
</p>

<p>
<span class="__name">Vagina size</span>
<span class="__value">{{ job.preferences.body.vagina.size | size }}</span>
</p>

<p>
<span class="__name">Pubic Hair size</span>
<span class="__value">{{ job.preferences.body.pubicHair.size | size }}</span>
</p>
</div>
</details>

<!-- Console -->
<details class="__section">
<summary class="__title">
Console
</summary>

<div class="__console">
<li v-for="(item, index) in job.cli.lines" :key="index" :class="item.css">
> {{ item.text }}
</li>
</div>
</details>
</div>
</div>
</template>

<script>
import _ from 'lodash'

const { shell } = $provider.api

export default {
filters: {
size(value) {
return Number.parseFloat(value).toFixed(2)
},
},
props: {
job: {
type: Object,
required: true,
},
},

data: () => ({
outputDataURL: undefined,
}),

watch: {
async 'job.hasFinished'(value) {
if (value) {
this.outputDataURL = await this.job.file.readAsDataURL()
}
},
},

methods: {
view() {},

save() {
const savePath = shell.showSaveDialog({
defaultPath: this.job.getFileName(),
filters: [
{ name: 'PNG', extensions: ['png'] },
// { name: 'JPEG', extensions: ['jpg'] }
],
})

if (_.isNil(savePath)) {
return
}

this.job.file.copy(savePath)
},

rerun() {
this.job.photo.rerunJob(this.job.id)
},
},
}
</script>

<style lang="scss">
.c-nudity-job {
@apply flex;

.__preview {
@apply flex justify-center items-center
rounded rounded-tr-none rounded-br-none
border-2 border-dark-500 border-r-0
text-3xl;
width: 125px;
height: 125px;

img {
@apply w-full h-full rounded rounded-tr-none rounded-br-none;
transition: all 0.15s ease-in-out;

&:hover {
@apply rounded z-50;
transform: scale(3);
}
}
}

.__content {
@apply flex-1 flex flex-col
bg-dark-500
rounded
rounded-tl-none
rounded-bl-none
px-4
shadow;

width: 200px;

.__section {
@apply py-2;

&:not(:last-child) {
@apply border-b border-dark-400;
}

.__title {
@apply text-xs uppercase text-generic-300 mb-2 cursor-pointer;
}

.__status {
@apply flex justify-center
text-xl font-bold;
}

.__buttons {
@apply flex justify-center items-center;
}

.__console {
@apply p-2 bg-black overflow-auto rounded;
height: 150px;

li {
@apply font-mono text-xs text-generic-100 mb-2 block;

&.text-danger {
@apply text-danger;
}
}
}

.__preferences {
p {
@apply text-sm;

.__name {
@apply inline-block text-generic-300;
width: 150px;
}

.__value {
@apply inline-block font-bold text-generic-100;
}
}
}
}
}
}

/*
.c-nudity-job {
@apply flex pb-4;
height: 170px;

&:not(:first-child) {
@apply pt-4;
}

&:not(:last-child) {
@apply border-b border-dark-400;
}

.job-section {
@apply p-2 mb-0;
width: 200px;

&:not(:last-child) {
@apply mr-5;
}
}

.job-photos {
@apply flex-1 inline-flex;
width: auto;
}

.job-status {
@apply flex flex-col justify-center items-center;
width: 150px;

& > div {
@apply text-center;
}

.buttons {
@apply flex flex-col justify-center items-center mt-3;
}

.status-title {
@apply font-semibold text-xl text-generic-300;

&.text-danger {
@apply text-danger;
}
}

.status-text {
@apply text-sm;
}
}

.job-console {
@apply bg-black overflow-auto rounded;

li {
@apply font-mono text-xs text-generic-100 mb-3 block;

&.text-danger {
@apply text-danger;
}
}
}

.job-preferences {
@apply flex flex-col justify-center items-center;

p {
@apply text-sm;

.preference-name {
@apply inline-block;
width: 150px;
}

.preference-value {
@apply inline-block;
@apply font-bold;
}
}
}
}
*/
</style>

+ 293
- 0
src/components/Nudity/PhotoRun.vue View File

@@ -0,0 +1,293 @@
<template>
<div class="c-photo-run">
<figure class="run__preview">
<app-photo v-if="previewDataURL" :src="previewDataURL" />
</figure>

<div class="box run__content">
<div class="box__content">
<details v-show="run.running || run.failed" class="run__section" open>
<summary class="section__title">
Status
</summary>

<div class="section__content">
<p v-show="run.running" class="text-white font-bold text-xl">
<font-awesome-icon icon="running" /> Running ({{ run.timer.duration }}s)
</p>

<p v-show="run.failed" class="text-danger-500 font-bold text-xl">
<font-awesome-icon icon="exclamation-circle" /> Error!
</p>
</div>
</details>

<details class="run__section" open>
<summary class="section__title">
Actions
</summary>

<div class="section__content">
<button v-show="run.finished" class="button button--success" @click.prevent="save">
Save
</button>

<button v-show="run.finished" class="button button--danger" @click.prevent="rerun">
Rerun
</button>

<button v-show="run.running" class="button button--danger" @click.prevent="cancel">
Cancel
</button>
</div>
</details>

<details class="run__section">
<summary class="section__title">
Preferences
</summary>

<div class="section__preferences">
<p>
<span class="preference__name">Boobs size</span>
<span class="preference__value">{{ run.preferences.body.boobs.size | size }}</span>
</p>

<p>
<span class="preference__name">Areola size</span>
<span class="preference__value">{{ run.preferences.body.areola.size | size }}</span>
</p>

<p>
<span class="preference__name">Nipple size</span>
<span class="preference__value">{{ run.preferences.body.nipple.size | size }}</span>
</p>

<p>
<span class="preference__name">Vagina size</span>
<span class="preference__value">{{ run.preferences.body.vagina.size | size }}</span>
</p>

<p>
<span class="preference__name">Pubic Hair size</span>
<span class="preference__value">{{ run.preferences.body.pubicHair.size | size }}</span>
</p>
</div>
</details>

<details class="run__section">
<summary class="section__title">
Console
</summary>

<div class="section__console">
<li v-for="(item, index) in run.cli.lines" :key="index" :class="item.css">
> {{ item.text }}
</li>
</div>
</details>
</div>
</div>
</div>
</template>

<script>
import { isNil } from 'lodash'

const { showSaveDialogSync } = $provider.api.dialog

export default {
filters: {
size(value) {
return Number.parseFloat(value).toFixed(2)
},
},

props: {
run: {
type: Object,
required: true,
},
},

data: () => ({
outputDataURL: undefined,
}),

computed: {
previewDataURL() {
return this.run.outputFile.dataURL
},
},

watch: {
'run.finished'(value) {
if (value) {
this.outputDataURL = this.run.outputFile.dataURL
}
},
},

methods: {
save() {
const savePath = showSaveDialogSync({
defaultPath: this.run.outputName,
filters: [
{ name: 'PNG', extensions: ['png'] },
],
})

if (isNil(savePath)) {
return
}

this.run.outputFile.copy(savePath)
},

rerun() {
this.run.photo.rerun(this.run)
},

cancel() {
this.run.photo.cancelRun(this.run)
},
},
}
</script>

<style lang="scss">
.c-photo-run {
@apply flex flex-col;


/*
.__preview {
@apply flex justify-center items-center
rounded rounded-tr-none rounded-br-none
border-2 border-dark-500 border-r-0
text-3xl;
width: 125px;
height: 125px;

img {
@apply w-full h-full rounded rounded-tr-none rounded-br-none;
transition: all 0.15s ease-in-out;

&:hover {
@apply rounded z-50;
transform: scale(3);
}
}
}

.__content {
@apply flex-1 flex flex-col
bg-dark-500
rounded
rounded-tl-none
rounded-bl-none
px-4
shadow;

width: 200px;

.__section {
@apply py-2;

&:not(:last-child) {
@apply border-b border-dark-400;
}

.__title {
@apply text-xs uppercase text-generic-300 mb-2 cursor-pointer;
}

.__status {
@apply flex justify-center
text-xl font-bold;
}

.__buttons {
@apply flex justify-center items-center;
}

.__console {
@apply p-2 bg-black overflow-auto rounded;
height: 150px;

li {
@apply font-mono text-xs text-generic-100 mb-2 block;

&.text-danger {
@apply text-danger;
}
}
}

.__preferences {
p {
@apply text-sm;

.__name {
@apply inline-block text-generic-300;
width: 150px;
}

.__value {
@apply inline-block font-bold text-generic-100;
}
}
}
}
}
*/
}

.run__preview {
@apply flex justify-center;
}

.run__content {
.run__section {
&:not(:last-child) {
@apply mb-4;
}
}

.section__title {
@apply text-generic-300 font-semibold cursor-pointer outline-none;
}

.section__content {
@apply px-4 pt-2 text-center;
}
}

.section__preferences {
p {
@apply text-sm;

.preference__name {
@apply inline-block text-generic-300;
width: 150px;
}

.preference__value {
@apply inline-block font-bold text-generic-100;
}
}
}

.section__console {
@apply p-2 bg-black overflow-auto rounded;
height: 150px;

li {
@apply font-mono text-xs text-generic-100 mb-2 block;

&.text-danger {
@apply text-danger-500;
}
}
}
</style>

+ 0
- 59
src/components/Nudity/Preview.vue View File

@@ -1,59 +0,0 @@
<template>
<figure class="cnudity-preview">
<img :src="nudityPreview" :style="{ 'width': width + 'px', 'height': height + 'px' }">
</figure>
</template>

<script>
export default {
props: {
width: {
type: Number,
default: 312,
},

height: {
type: Number,
default: 312,
},

type: {
type: String,
default: 'output',
},
},

data: () => ({
nudityPreview: undefined,
}),

async created() {
this.nudityPreview = await this.getPreviewDataURL()
},

methods: {
async getPreviewDataURL() {
if (!this.$nudity.hasModelPhoto()) {
// eslint-disable-next-line global-require
return require('~/assets/images/d1hpv9d-e1c2c577-d272-41b0-bd73-a89209108efd.jpg')
}

if (this.type === 'output') {
return this.$nudity.modelPhoto.getOutputFile().readAsDataURL()
}

if (this.type === 'cropped') {
return this.$nudity.modelPhoto.getCroppedFile().readAsDataURL()
}

return this.$nudity.modelPhoto.getSourceFile().readAsDataURL()
},
},
}
</script>

<style lang="scss">
.cnudity-preview {
@apply flex justify-center items-center py-4;
}
</style>

+ 0
- 290
src/components/Nudity/Upload.backup.vue View File

@@ -1,290 +0,0 @@
/*
* Filename: c:\src\dream\apps\dreamtime\src\components\Nudity\Upload.backup.vue
* Path: c:\src\dream\apps\dreamtime\src
* Created Date: Saturday, November 16th 2019, 3:43:30 pm
* Author: Ivan Bravo Bravo <ivan@dreamnet.tech>
*
* Copyright (c) 2019 DreamNet
*/
<template>
<div class="c-nudity-upload">
<!-- Dropzone -->
<div
:class="{'is-dragging': isDraggingFile}"
class="upload-dropzone"
@dragenter="onDragEnter"
@dragover="onDragOver"
@dragleave="onDragLeave"
@drop="onDrop">
<p class="dropzone-hint">๐Ÿ‘‡ Drop the photo here!</p>
</div>

<!-- Hidden input -->
<input
v-show="false"
ref="photo"
type="file"
accept="image/jpeg, image/png"
@change="onPhotoSelected" />

<div class="box py-5">
<div class="upload-url">
<input v-model="webAddress" type="url" class="input" placeholder="๐ŸŒ or enter a web address..." />

<button class="button" @click="onURL">
Go!
</button>
</div>

<!-- Action button -->
<button class="button" @click.prevent="$refs.photo.click()">
๐Ÿ“‚ or open a photo...
</button>
</div>
</div>
</template>

<script>
import _ from 'lodash'
import swal from 'sweetalert'
import { Photo } from '~/modules/models'
import { File } from '~/modules'

export default {
props: {
model: {
type: String,
default: undefined
}
},

data: () => ({
webAddress: '',

// Indicates if the user is dragging a file in the window (we apply the drag style)
isDraggingFile: false
}),

created() {
// Restarts the information of a previous process
this.$nudify.reset()
},

methods: {
/**
* File selected, start a new transformation process
*/
startFromFile(inputFile) {
if (_.isNil(inputFile)) {
swal(
'Upload failed',
'It seems that you have not selected a photo!',
'info'
)
return
}

// New File instance
const file = File.fromPath(inputFile.path)

this.start(file)
},

/**
*
*/
async startFromURL(url) {
if (_.isNil(url)) {
swal('Upload failed', 'This does not seem like a valid URL', 'info')
return
}

swal({
title: 'Loading...',
text: 'We are downloading the photo and preparing it!',
button: false,
closeOnClickOutside: false,
closeOnEsc: false
})

try {
// New File instance
const file = await File.fromURL(url)

swal.close()

this.start(file)
} catch (err) {
swal({
icon: 'error',
title: 'Upload failed',
text: `An error has occurred downloading the photo or saving it in the temporary folder, please make sure you are connected to the Internet and that ${
$dream.name
} has permissions to save files.`
})

$rollbar.warn(err)
}
},

/**
*
*/
start(file) {
// Create a photo for the model ("null" model for now)
const photo = new Photo(null, file)

// Get any error message from the file
const validationErrorMessage = photo.getValidationErrorMessage()

if (!_.isNil(validationErrorMessage)) {
swal('Upload failed', validationErrorMessage, 'error')
return
}

// Start the transformation process!
this.$nudify.start(photo)

// It's time to crop the photo
this.$router.push('/nudity/hub')
},

/**
*
*/
onPhotoSelected(event) {
const { files } = event.target

if (files.length === 0) {
return
}

$nucleus.track('UPLOAD_SELECTED')

this.startFromFile(files[0])
event.target.value = ''
},

/**
*
*/
onURL() {
if (_.isNil(this.webAddress) || this.webAddress.length === 0) {
swal('Upload failed', 'Please enter a valid web address', 'error')
return
}

$nucleus.track('UPLOAD_URL')

this.startFromURL(this.webAddress)
},

/**
*
*/
onDragEnter(event) {
event.dataTransfer.dropEffect = 'copy'
this.isDraggingFile = true
},

/**
*
*/
onDragLeave() {
this.isDraggingFile = false
},

/**
*
*/
onDragOver(event) {
event.preventDefault()
event.stopPropagation()
event.dataTransfer.dropEffect = 'copy'
this.isDraggingFile = true
},

/**
*
*/
onDrop(event) {
event.preventDefault()
event.stopPropagation()
this.isDraggingFile = false

const { files } = event.dataTransfer
const externalURL = event.dataTransfer.getData('url')

if (files.length > 0) {
$nucleus.track('UPLOAD_DROP')
this.startFromFile(files[0])
} else if (externalURL.length > 0) {
$nucleus.track('UPLOAD_DROP_URL')
this.startFromURL(externalURL)
}
}
}
}
</script>

<style lang="scss">
.c-nudity-upload {
@apply w-full
relative
text-center
mb-4;

.upload-dropzone {
@apply flex
items-center
justify-center
bg-dark-400
rounded
border-transparent
border-2
border-dashed
mb-4;

height: 150px;
transition: all 0.1s linear;

&.is-dragging {
@apply bg-dark-700 border-white;

.dropzone-hint {
@apply text-white;
}
}

.dropzone-hint {
@apply text-generic-300 uppercase;
transition: all 0.1s linear;
}
}

.upload-url {
@apply mb-4 flex;

.input {
@apply flex-1 mr-4;
}
}

&.is-dragging {
@apply border-white border-dotted;

.dragging-overlay {
//display: block;
}
}

.dragging-overlay {
@apply bg-white absolute top-0 left-0 right-0 bottom-0 hidden;
opacity: 0.3;
}

.fu-hint {
@apply text-sm text-gray-600;
}
}
</style>

+ 56
- 22
src/components/Nudity/Upload.vue View File

@@ -1,5 +1,25 @@
<template>
<div class="c-uploader">
<div class="uploader__settings box box--items">
<div class="box__content">
<box-item
label="On Upload"
description="Select what should be done when uploading a new photo.">
<select v-model="$settings.app.uploadMode" class="input">
<option value="none">
Stay
</option>
<option value="add-queue">
Start photo transformation
</option>
<option value="go-preferences">
Change photo preferences
</option>
</select>
</box-item>
</div>
</div>

<!-- Dropzone -->
<div
class="uploader__dropzone"
@@ -33,6 +53,7 @@
ref="photo"
type="file"
accept="image/jpeg, image/png"
multiple
@change="openFile">

<button class="button" @click.prevent="$refs.photo.click()">
@@ -54,7 +75,7 @@
</div>

<div class="box__content">
<button class="button" @click.prevent="openDirectory">
<button class="button" @click.prevent="openFolder">
<span>import folder</span>
</button>
</div>
@@ -109,14 +130,14 @@
/* eslint-disable no-param-reassign */
import {
isNil, isEmpty, startsWith,
map,
map, isArray,
} from 'lodash'
import swal from 'sweetalert'
import { Nudify, Photo } from '~/modules/nudify'
import { File } from '~/modules'
import Swal from 'sweetalert2'
import { Nudify } from '~/modules/nudify'

const { nucleus, rollbar } = $provider.services
const { nucleus } = $provider.services
const { instagram } = $provider.tools
const { dialog } = $provider.api

export default {
props: {
@@ -141,25 +162,29 @@ export default {
* File selected, start a new transformation process
*/
addFile(file) {
if (isNil(file)) {
return
}

Nudify.addFile(file.path)
},

async addFiles(files) {
if (files.length > 1) {
swal({
title: 'Importing files...',
text: 'One moment, please.',
button: false,
closeOnClickOutside: false,
closeOnEsc: false,
})
if (!isArray(files)) {
return
}

Swal.fire({
title: 'Importing files...',
text: 'One moment, please.',
showConfirmButton: false,
allowOutsideClick: false,
allowEscapeKey: false,
})

await Nudify.addFiles(files)

if (files.length > 1) {
swal.close()
}
Swal.close()
},

/**
@@ -172,9 +197,11 @@ export default {
return
}

const paths = map(files, 'path')

nucleus.track('UPLOAD_FILE')

this.addFile(files[0])
this.addFiles(paths)

event.target.value = ''
},
@@ -182,8 +209,12 @@ export default {
/**
*
*/
openDirectory() {
openFolder() {
const paths = dialog.showOpenDialogSync({
properties: ['openDirectory'],
})

this.addFiles(paths)
},

/**
@@ -191,13 +222,14 @@ export default {
*/
openUrl() {
if (isEmpty(this.webAddress) || (!startsWith(this.webAddress, 'http://') && !startsWith(this.webAddress, 'https://'))) {
swal('Upload failed.', 'Please enter a valid web address.', 'error')
return
throw new AppError('Please enter a valid web address.', { title: 'Upload failed.', level: 'warning' })
}

nucleus.track('UPLOAD_URL')

Nudify.addUrl(this.webAddress)

this.webAddress = ''
},

/**
@@ -215,6 +247,8 @@ export default {
}

Nudify.addUrl(post.downloadUrl)

this.instagramPhoto = ''
},

/**
@@ -303,7 +337,7 @@ export default {
.uploader__dropzone {
@apply flex items-center justify-center;
@apply bg-dark-500 mb-6;
@apply rounded border-2 border-dashed border-dark-400;
@apply rounded border-2 border-dashed border-dark-100;
height: 200px;
transition: all 0.1s linear;


+ 4
- 6
src/components/Nudity/index.js View File

@@ -1,8 +1,6 @@
import Vue from 'vue'
import NudityPreview from './Preview'
import NudityUpload from './Upload'
import Job from './Job'
import NudifyUpload from './Upload'
import NudifyPhotoRun from './PhotoRun'

Vue.component('nudity-preview', NudityPreview)
Vue.component('nudity-upload', NudityUpload)
Vue.component('nudity-job', Job)
Vue.component('nudify-upload', NudifyUpload)
Vue.component('nudify-photo-run', NudifyPhotoRun)

+ 4
- 1
src/components/Settings/SettingsPreferences.vue View File

@@ -321,8 +321,11 @@
<option value="cropjs">
Manual Crop (Not recommended)
</option>
<option value="overlay">
Overlay
</option>
<option value="auto-rescale">
Fixed Scale
Fixed scale
</option>
<option value="auto-resize">
Scale and pad

+ 25
- 16
src/components/UI/AppPhoto.vue View File

@@ -1,8 +1,8 @@
<template>
<figure class="app-photo">
<figure class="c-photo" :class="{'photo--hover': hover}">
<img :src="src">

<p class="app-photo-label">
<p v-if="$slots.default" class="photo__label">
<slot />
</p>
</figure>
@@ -12,32 +12,41 @@
export default {
props: {
src: {
type: undefined,
type: String,
required: true,
},

hover: {
type: Boolean,
default: true,
},
},
}
</script>

<style lang="scss">
.app-photo {
@apply relative flex flex-col;
<style lang="scss" scoped>
.c-photo {
@apply relative flex flex-col z-50;
box-sizing: content-box;
width: 125px;
transition: all 0.2s ease-in-out;
max-width: 200px;

img {
@apply w-full rounded-t shadow-md;
height: 125px;
transition: all 0.15s ease-in-out;
&.photo--hover:hover {
transform: scale(1.5);

&:hover {
@apply rounded z-50;
transform: scale(2.5);
img {
@apply rounded;
}
}

.app-photo-label {
@apply p-2 bg-dark-600 text-generic-300 text-sm rounded-b font-semibold text-center;
img {
@apply w-full rounded-t shadow-md;
height: auto;
}

.photo__label {
@apply p-2 rounded-b bg-dark-500;
@apply text-generic-300 text-sm font-semibold text-center;
}
}
</style>

+ 38
- 23
src/components/UI/AppUpdate.vue View File

@@ -1,42 +1,44 @@
<template>
<!-- Cannot update, only show the version... -->
<box-section-item
<box-item
v-if="!updater.enabled"
:label="currentVersion"
icon="๐ŸŒ" />
icon="globe" />

<!-- Updated! -->
<box-section-item
<box-item
v-else-if="!updater.available"
:label="`${projectTitle} is up to date.`"
:description="currentVersion"
icon="๐ŸŒ" />
icon="globe" />

<!-- Update available -->
<box-section-item
<box-item
v-else-if="!updater.update.active"
:label="`${projectTitle} ${updater.latest.tag_name} available.`"
icon="๐ŸŒ"
icon="fire-alt"
class="update-item">
<button v-tooltip="'Download and install the update automatically.'" type="button" class="button is-sm" @click.prevent="updater.download()">
<button v-tooltip="'Download and install the update automatically.'" type="button" class="button is-sm" @click.prevent="updater.start()">
Update
</button>
<app-external-link v-tooltip="'Download the update manually.'" :href="downloadURL" class="button is-sm">

<a v-tooltip="'Download the update manually.'" :href="downloadURL" target="_blank" class="button is-sm">
Manual
</app-external-link>
</box-section-item>
</a>
</box-item>

<!-- update... -->
<!-- eslint-disable-next-line vue/valid-template-root --->
<box-section-item
<box-item
v-else
:label="updater.update.text"
icon="๐ŸŒ">
:label="updater.update.status"
icon="globe">
<template slot="description">
<p v-if="updater.update.text === 'Downloading...'" class="item-description">
<strong>{{ updater.update.progress | progress }}</strong> - {{ updater.update.mbWritten | size }}/{{ updater.update.mbTotal | size }} MB.
<p v-if="updater.update.status === 'Downloading...'" class="item__description">
<strong>{{ updater.update.progress | progress }}</strong> - {{ updater.update.written | size }}/{{ updater.update.total | size }} MB.
</p>
<p v-else class="item-description">

<p v-else class="item__description">
Wait a few minutes, please do not close the program.
</p>
</template>
@@ -44,21 +46,36 @@
<button type="button" class="button is-danger is-sm" @click.prevent="updater.cancel()">
Cancel
</button>
</box-section-item>
</box-item>
</template>

<script>
import { isString, toNumber } from 'lodash'

/* eslint import/namespace: ['error', { allowComputed: true }] */
import * as updateProviders from '~/modules/updater'

const { shell } = $provider.api
const { getPath } = $provider.tools.paths

export default {
filters: {
progress(value) {
if (isString(value)) {
// eslint-disable-next-line no-param-reassign
value = toNumber(value)
}

const progress = (value * 100).toFixed(2)
return `${progress}%`
},

size(value) {
if (isString(value)) {
// eslint-disable-next-line no-param-reassign
value = toNumber(value)
}

return value.toFixed(2)
},
},
@@ -77,13 +94,10 @@ export default {

data: () => ({
currentVersion: 'v0.0.0',
updater: {},
}),

computed: {
updater() {
return $provider.updater[this.project]
},

downloadURL() {
return this.updater.downloadUrls[0]
},
@@ -91,6 +105,7 @@ export default {

created() {
this.currentVersion = this.updater.currentVersion
this.updater = updateProviders[this.project]
},

beforeDestroy() {
@@ -131,11 +146,11 @@ export default {
background: theme('colors.dark.300') !important;
}

.item-label {
.item__label {
@apply text-white;
}

.item-description {
.item__description {
@apply text-generic-600;
}
}

+ 26
- 16
src/components/UI/BoxItem.vue View File

@@ -1,14 +1,19 @@
<template>
<div v-if="isVisible" class="box__item" :class="cssClass" @click="click">
<div v-if="icon" class="item__icon">
<img v-if="isImageIcon" :src="icon">
<font-awesome-icon v-else :icon="icon" />
</div>
<slot name="icon">
<div v-if="icon" class="item__icon">
<img v-if="isImageIcon" :src="icon">
<font-awesome-icon v-else :icon="icon" />
</div>
</slot>

<div class="item__content">
<div class="item__text">
<span class="item__label" v-html="label" />
<span v-if="description" class="item__description" v-html="description" />

<slot name="description">
<span v-if="description" class="item__description" v-html="description" />
</slot>
</div>

<div class="item__action">
@@ -19,7 +24,8 @@
</template>

<script>
import _ from 'lodash'
import { isNil, startsWith } from 'lodash'
import { dream } from '~/modules'