Commit 997fd6b7 authored by Laureline Nevin's avatar Laureline Nevin ⌨️
Browse files

Added petite-vue for reactivity

parent 8a40ef3e
Loading
Loading
Loading
Loading
+85 −88
Changes for index.html: 85 added lines, 88 removed lines.
Original line number Diff line number Diff line
@@ -10,117 +10,117 @@
        let FF_FOUC_FIX;
    </script>
</head>
<body>
<div class="body-content">
<body v-scope>
<div class="body-content invisible">
    <h1 class="title" title="Image Viewer with Online Interactive Relighting">IVOIRe</h1>

    <header class="navbar">
        <div>
            <label for="select-dataset" data-i18n="content:controls.selected">Selected texture</label>
            <span data-i18n="content:colon">:</span>
            <select name="dataset" id="select-dataset" class="btn-dark" disabled>
                <optgroup label="Hosted" class="builtins" data-i18n="attr:label:controls.hosted"></optgroup>
                <optgroup label="In-memory" class="inmemory" data-i18n="attr:label:controls.inmemory">
                    <option class="action" value="create" data-i18n="content:controls.createinmemory">Create from
                        images…
                    </option>
            <label for="select-dataset">{{t('controls.selected')}}</label>
            <span>{{t('colon')}}</span>
            <select name="dataset" id="select-dataset" class="btn-dark" :disabled="datasetsDisabled"
                    :value="dataset" @change="onDatasetSelect($event)">
                <optgroup label="" :label="t('controls.hosted')" class="builtins">
                    <option v-for="ds in datasets.server" :value="ds.id">{{getLocString(ds.name, locale)}}</option>
                </optgroup>
                <optgroup label="" :label="t('controls.inmemory')" class="inmemory">
                    <option v-for="ds in datasets.memory" :value="ds.id">{{getLocString(ds.name, locale)}}</option>
                    <option class="action" value="create">{{t('controls.createinmemory')}}</option>
                </optgroup>
            </select>
            <button id="button-delete-dataset" class="hidden btn-dark"
                    data-i18n="content:controls.deleteinmemory">Delete dataset from memory
            <button id="button-delete-dataset" class="hidden btn-dark">{{t('controls.deleteinmemory')}}
            </button>
        </div>
        <div>
            <button class="btn-dark btn-icon hidden" id="button-fullscreen" aria-label="Fullscreen"
                    title="Fullscreen" data-icon="fullscreen"></button>
            <select aria-label="Language" class="btn-dark" name="lang" id="select-lang"></select>
            <select aria-label="Language" class="btn-dark" name="lang"
                    :value="locale" @change="setLocale($event.target.value)">
                <option v-for="lang in locales" :value="lang.id">{{lang.name}}</option>
            </select>
            <button class="btn-dark" id="button-help">
                <span data-i18n="content:help.button">Help / About</span>
                <span>{{t('help.button')}}</span>
                <svg data-icon="help"></svg>
            </button>
        </div>
    </header>

    <div class="controls">
        <label data-phase="render" for="select-rendermode"><span
                data-i18n="content:controls.rendermode">Render mode</span>
            <span data-i18n="content:colon">:</span></label>
        <select data-phase="render" name="rendermode" id="select-rendermode">
            <option value="relight" data-i18n="content:controls.mode.relight">Relighting (with color)</option>
            <option value="relight_nocolor" data-i18n="content:controls.mode.relightnocolor">Relighting (no color)
            </option>
            <option value="albedo" data-i18n="content:controls.mode.albedo">Albedo</option>
            <option value="normals" data-i18n="content:controls.mode.normals">Normal map</option>
        <label v-show="phase === 'render'" for="select-rendermode"><span>{{t('controls.rendermode')}}</span>
            <span>{{t('colon')}}</span></label>
        <select v-show="phase === 'render'" name="rendermode" id="select-rendermode">
            <option value="relight">{{t('controls.mode.relight')}}</option>
            <option value="relight_nocolor">{{t('controls.mode.relightnocolor')}}</option>
            <option value="albedo">{{t('controls.mode.albedo')}}</option>
            <option value="normals">{{t('controls.mode.normals')}}</option>
        </select>
        <div class="input-box" data-phase="render">
            <label for="input-specular"><span
                    data-i18n="content:controls.specular">Specular reflection</span>
                <span data-i18n="content:colon">:</span>
        <div class="input-box" v-show="phase === 'render'">
            <label for="input-specular"><span>{{t('controls.specular')}}</span>
                <span>{{t('colon')}}</span>
                <span class="value"></span>
                <button class="btn-dark btn-icon btn-slim button-input-edit" data-icon="edit" aria-label="Edit value"
                        title="Edit value"></button>
            </label>
            <input type="range" name="specular" id="input-specular" min="0" max="1" value="0" step=".01"/>
        </div>
        <div class="input-box" data-phase="render">
            <label for="input-diffuse"><span data-i18n="content:controls.diffuse">Diffuse reflection</span>
                <span data-i18n="content:colon">:</span>
        <div class="input-box" v-show="phase === 'render'">
            <label for="input-diffuse"><span>{{t('controls.diffuse')}}</span>
                <span>{{t('colon')}}</span>
                <span class="value"></span>
                <button class="btn-dark btn-icon btn-slim button-input-edit" data-icon="edit" aria-label="Edit value"
                        title="Edit value"></button>
            </label>
            <input type="range" name="diffuse" id="input-diffuse" min="0" max="1" value="0" step=".01"/>
        </div>
        <div class="input-box" data-phase="render">
            <label for="input-shine"><span data-i18n="content:controls.shine">Shine</span>
                <span data-i18n="content:colon">:</span>
        <div class="input-box" v-show="phase === 'render'">
            <label for="input-shine"><span>{{t('controls.shine')}}</span>
                <span>{{t('colon')}}</span>
                <span class="value"></span>
                <button class="btn-dark btn-icon btn-slim button-input-edit" data-icon="edit" aria-label="Edit value"
                        title="Edit value"></button>
            </label>
            <input type="range" name="shine" id="input-shine" min="1" max="100" value="1" step="1"/>
        </div>
        <div class="input-box" data-phase="render">
            <label for="input-ambiant"><span data-i18n="content:controls.ambiant">Ambiant lighting</span>
                <span data-i18n="content:colon">:</span>
        <div class="input-box" v-show="phase === 'render'">
            <label for="input-ambiant"><span>{{t('controls.ambiant')}}</span>
                <span>{{t('colon')}}</span>
                <span class="value"></span>
                <button class="btn-dark btn-icon btn-slim button-input-edit" data-icon="edit" aria-label="Edit value"
                        title="Edit value"></button>
            </label>
            <input type="range" name="ambiant" id="input-ambiant" min="0" max="1" value="0" step=".01"/>
        </div>
        <span data-phase="render">
        <span v-show="phase === 'render'">
            <button class="btn-dark btn-icon" id="button-reset-controls" data-icon="reset"></button>
            <label for="button-reset-controls" data-i18n="content:controls.reset">Reset light settings</label>
            <label for="button-reset-controls">{{t('controls.reset')}}</label>
        </span>
        <span data-phase="render">
        <span v-show="phase === 'render'">
            <button class="btn-dark btn-icon" id="button-export" data-icon="export"></button>
            <label for="button-export" data-i18n="content:export.button">Export render</label>
            <label for="button-export">{{t('export.button')}}</label>
        </span>
        <div class="description-container">
            <div id="dataset-description" class="hidden">
                <h3 data-i18n="content:controls.description">Description</h3>
                <div class="content"></div>
            <div v-if="description">
                <h3>{{t('controls.description')}}</h3>
                <div class="content">{{ description && getLocString(description, locale) }}</div>
            </div>
            <pre><code id="output" class="hidden"></code></pre>
            <pre v-if="output"><code>{{ output }}</code></pre>
        </div>
        <div class="lightball-container">
            <canvas id="ivoire-lightball"></canvas>
            <div class="reset-button-container">
                <button class="btn-dark btn-icon" id="button-reset-lightball" title="Reset light direction settings"
                        data-i18n="attr:title:controls.resetlightball" data-icon="reset"></button>
                <button class="btn-dark btn-icon" id="button-reset-lightball"
                        :title="t('controls.resetlightball')" data-icon="reset" v-if="phase==='render'"></button>
            </div>
        </div>
    </div>

    <main id="app">
        <div class="view-controls">
            <button class="btn-dark btn-icon" id="button-zoom-fit"
                    title="Fit view" data-i18n="attr:title:controls.fitview" data-icon="zoom-fit"></button>
            <button class="btn-dark btn-icon" id="button-zoom-vfit"
                    title="Fit view vertically" data-i18n="attr:title:controls.fitviewv" data-icon="zoom-vfit"></button>
            <button class="btn-dark btn-icon" id="button-zoom-hfit"
                    title="Fit view horizontally" data-i18n="attr:title:controls.fitviewh"
            <button class="btn-dark btn-icon" id="button-zoom-fit" :title="t('controls.fitview')"
                    data-icon="zoom-fit"></button>
            <button class="btn-dark btn-icon" id="button-zoom-vfit" :title="t('controls.fitviewv')"
                    data-icon="zoom-vfit"></button>
            <button class="btn-dark btn-icon" id="button-zoom-hfit" :title="t('controls.fitviewh')"
                    data-icon="zoom-hfit"></button>
        </div>
        <canvas id="ivoire-display"></canvas>
@@ -132,37 +132,34 @@
<dialog id="message" class="drop-shadow">
    <h1></h1>
    <p></p>
    <button class="btn-dark" type="reset" data-i18n="content:ok" autofocus>Ok</button>
    <button class="btn-dark" type="reset" autofocus>{{t('ok')}}</button>
</dialog>
<dialog id="create-inmemory" class="drop-shadow">
    <h1 data-i18n="content:memcreate.title">Upload new texture</h1>
    <h1>{{t('memcreate.title')}}</h1>
    <form action="#">
        <label for="upload-dataset-name" autofocus>
            <span data-i18n="content:memcreate.name">Name</span>
            <span data-i18n="content:colon">:</span>&nbsp;</label>
            <span>{{t('memcreate.name')}}</span>
            <span>{{t('colon')}}</span>&nbsp;</label>
        <input type="text" name="dataset-name" id="upload-dataset-name" placeholder="In-memory" size="50"/>
        <label for="upload-color-image">
            <span data-i18n="content:memcreate.colorimg">Color image</span>
            <span
                    data-i18n="content:colon">:</span>&nbsp;</label>
            <span>{{t('memcreate.colorimg')}}</span>
            <span>{{t('colon')}}</span>&nbsp;</label>
        <input type="file" name="color-image" id="upload-color-image"/>
        <label for="upload-normals-image">
            <span data-i18n="content:memcreate.normalsimg">Normals image</span>
            <span data-i18n="content:colon">:</span>&nbsp;</label>
            <span>{{t('memcreate.normalsimg')}}</span>
            <span>{{t('colon')}}</span>&nbsp;</label>
        <input type="file" name="normals-image" id="upload-normals-image"/>
    </form>
    <p data-i18n="content:memcreate.notice">Note: as the name suggest this data will be stored in your browser's
        memory. Depending on your hardware, uploading very large images may lead to partial or total
        unresponsiveness.</p>
    <button class="btn" type="reset" data-i18n="content:cancel">Cancel</button>
    <button class="btn" type="submit" data-i18n="content:memcreate.create">Create</button>
    <p>{{t('memcreate.notice')}}</p>
    <button class="btn" type="reset">{{t('cancel')}}</button>
    <button class="btn" type="submit">{{t('memcreate.create')}}</button>
</dialog>
<dialog id="export-success">
    <h3 data-i18n="content:export.success">Export result</h3>
    <h3>{{t('export.success')}}</h3>
    <img src="" alt="Exported image">
    <div>
        <button class="btn" id="button-download" data-i18n="content:export.download" autofocus>Download</button>
        <button class="btn" type="reset" data-i18n="content:export.close">Close</button>
        <button class="btn" id="button-download" autofocus>{{t('export.download')}}</button>
        <button class="btn" type="reset">{{t('export.close')}}</button>
    </div>
    <a href="" id="export-download-anchor" class="hidden"></a>
</dialog>
@@ -170,34 +167,34 @@
    <button type="reset" class="btn-close btn-icon" data-icon="close"></button>
    <div class="logos">
        <a target="_blank" href="https://www.greyc.fr">
            <img src="/images/greyc-en.svg" data-i18n="attr:src:help.logos.greyc" alt="GREYC logo"></a>
            <img src="" :src="t('help.logos.greyc')" alt="GREYC logo"></a>
        <a target="_blank" href="https://cnrs.fr"><img src="/images/cnrs.svg" alt="CNRS logo"></a>
        <a target="_blank" href="https://ensicaen.fr"><img src="/images/ensicaen.svg" alt="ENSICAEN logo"></a>
        <a target="_blank" href="https://unicaen.fr"><img src="/images/unicaen.svg" alt="Unicaen logo"></a>
    </div>
    <div class="content">
        <h2 data-i18n="content:help.about.title"></h2>
        <p data-i18n="content:help.about.text"></p>
        <h2 v-html="t('help.about.title')"></h2>
        <p v-html="t('help.about.text')"></p>

        <h3 data-i18n="content:help.howitworks.title"></h3>
        <p data-i18n="content:help.howitworks.text"></p>
        <h3 v-html="t('help.howitworks.title')"></h3>
        <p v-html="t('help.howitworks.text')"></p>

        <h2 data-i18n="content:help.howto.title"></h2>
        <p data-i18n="content:help.howto.text"></p>
        <h2 v-html="t('help.howto.title')"></h2>
        <p v-html="t('help.howto.text')"></p>
        <dl>
            <dt data-i18n="content:controls.rendermode"></dt>
            <dd data-i18n="content:help.rendermode"></dd>
            <dt data-i18n="content:controls.ambiant"></dt>
            <dd data-i18n="content:help.ambiant"></dd>
            <dt data-i18n="content:controls.diffuse"></dt>
            <dd data-i18n="content:help.diffuse"></dd>
            <dt data-i18n="content:controls.specular"></dt>
            <dd data-i18n="content:help.specular"></dd>
            <dt data-i18n="content:controls.shine"></dt>
            <dd data-i18n="content:help.shine"></dd>
            <dt v-html="t('controls.rendermode')"></dt>
            <dd v-html="t('help.rendermode')"></dd>
            <dt v-html="t('controls.ambiant')"></dt>
            <dd v-html="t('help.ambiant')"></dd>
            <dt v-html="t('controls.diffuse')"></dt>
            <dd v-html="t('help.diffuse')"></dd>
            <dt v-html="t('controls.specular')"></dt>
            <dd v-html="t('help.specular')"></dd>
            <dt v-html="t('controls.shine')"></dt>
            <dd v-html="t('help.shine')"></dd>
        </dl>
        <h3 data-i18n="content:help.export.title"></h3>
        <p data-i18n="content:help.export.text"></p>
        <h3 v-html="t('help.export.title')"></h3>
        <p v-html="t('help.export.text')"></p>
    </div>
</dialog>
<script type="module" src="/src/main.ts"></script>
+10 −2
Changes for package-lock.json: 10 added lines, 2 removed lines.
Original line number Diff line number Diff line
{
  "name": "IVOIRe",
  "name": "ivoire",
  "version": "0.1.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "IVOIRe",
      "name": "ivoire",
      "version": "0.1.0",
      "dependencies": {
        "gl-matrix": "^3.4.3",
@@ -13,6 +13,7 @@
      },
      "devDependencies": {
        "@modyfi/vite-plugin-yaml": "^1.1.1",
        "petite-vue": "^0.4.1",
        "prettier": "^3.3.1",
        "sass-embedded": "^1.89.1",
        "typescript": "^5.2.2",
@@ -2060,6 +2061,13 @@
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/petite-vue": {
      "version": "0.4.1",
      "resolved": "https://registry.npmjs.org/petite-vue/-/petite-vue-0.4.1.tgz",
      "integrity": "sha512-/gtYKQe9r1OV4IEwn2RsPXAHgFTe1nVq4QhldAP6/l8DSe9I754K6Oe1+Ff6dbnT5P8X2XP7PTUZkGRz5uFnFQ==",
      "dev": true,
      "license": "MIT"
    },
    "node_modules/picocolors": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+1 −0
Changes for package.json: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
  },
  "devDependencies": {
    "@modyfi/vite-plugin-yaml": "^1.1.1",
    "petite-vue": "^0.4.1",
    "prettier": "^3.3.1",
    "sass-embedded": "^1.89.1",
    "typescript": "^5.2.2",
+7 −19
Changes for scripts/check-lang.js: 7 added lines, 19 removed lines.
Original line number Diff line number Diff line
import path from "path";
import * as fs from "node:fs/promises";
import path from 'path';
import * as fs from 'node:fs/promises';
import * as yaml from 'yaml';

const projRoot = path.resolve(import.meta.dirname, "..");
@@ -27,29 +27,17 @@ for (const langFile of await fs.readdir(langDir))

const keys = await fs.readFile(path.resolve(projRoot, 'index.html'), 'utf8').then((data) => {
    /** @type string[] */ const keys = [];
    for (const [match, value] of data.toString().matchAll(/\bdata-i18n="([^"]+)"/g)) {
        const parts = value.split(':');
        let valid = true, key;
        if (parts[0] === 'content') {
            if (parts.length !== 2)
                valid = false;
            key = parts[1];
        } else if (parts[0] === 'attr') {
            if (parts.length !== 3)
                valid = false;
            key = parts[2];
        } else
            valid = false;
        if (valid) {
    for (const [match, value] of data.toString().matchAll(/t\('([^']+)'\)/g)) {
        if (value.match(/^[a-z]+(\.[a-z]+)*$/i)) {
            console.debug(`Found key ${value}`);
            keys.push(key);
            keys.push(value);
        } else {
            console.debug(`Invalid data-i18n attr: ${match}`);
            console.debug(`Invalid translation key: ${match}`);
            exit = 1;
        }
    }
    if (!keys.length) {
        console.error("Error found no i18n attributes in HTML file");
        console.error("Error found no translation key in HTML file");
        exit = 1;
    }
    return keys;
+122 −115

File changed.

Preview size limit exceeded, changes collapsed.

Loading