} folds
*/
static #parseFolds(folds) {
- if (!Array.isArray(folds)) return;
+ if (this.type !== "editor") return [];
+ if (!Array.isArray(folds)) return [];
+
const foldDataAr = [];
+
folds.forEach((fold) => {
+ if (!fold || !fold.range) return;
+
const { range } = fold;
const { start, end } = range;
- const foldData = new Fold(
- new Range(start.row, start.column, end.row, end.column),
- fold.placeholder,
- );
- if (fold.ranges.length > 0) {
- const subFolds = parseFolds(fold.ranges);
- foldData.subFolds = subFolds;
- foldData.ranges = subFolds;
- }
+ if (!start || !end) return;
+
+ try {
+ const foldData = new Fold(
+ new Range(start.row, start.column, end.row, end.column),
+ fold.placeholder,
+ );
+
+ if (Array.isArray(fold.ranges) && fold.ranges.length > 0) {
+ const subFolds = EditorFile.#parseFolds(fold.ranges);
+ foldData.subFolds = subFolds;
+ foldData.ranges = subFolds;
+ }
- foldDataAr.push(foldData);
+ foldDataAr.push(foldData);
+ } catch (error) {
+ console.warn("Error parsing fold:", error);
+ }
});
+
return foldDataAr;
}
@@ -945,6 +1045,7 @@ export default class EditorFile {
* Setup Ace EditSession for the file
*/
#setupSession() {
+ if (this.type !== "editor") return;
const { value: settings } = appSettings;
this.session.setTabSize(settings.tabSize);
@@ -963,13 +1064,18 @@ export default class EditorFile {
#destroy() {
this.#emit("close", createFileEvent(this));
appSettings.off("update:openFileListPos", this.#onFilePosChange);
- this.session.off("changeScrollTop", EditorFile.#onscrolltop);
- this.session.off("changeScrollLeft", EditorFile.#onscrollleft);
- this.session.off("changeFold", EditorFile.#onfold);
- this.#removeCache();
- this.session.destroy();
+ if (this.type === "editor") {
+ this.session?.off("changeScrollTop", EditorFile.#onscrolltop);
+ this.session?.off("changeScrollLeft", EditorFile.#onscrollleft);
+ this.session?.off("changeFold", EditorFile.#onfold);
+ this.#removeCache();
+ this.session?.destroy();
+ delete this.session;
+ } else if (this.content) {
+ this.content.remove();
+ }
+
this.#tab.remove();
- delete this.session;
this.#tab = null;
}
diff --git a/src/lib/editorManager.js b/src/lib/editorManager.js
index d91c5976a..f77a33039 100644
--- a/src/lib/editorManager.js
+++ b/src/lib/editorManager.js
@@ -573,7 +573,8 @@ async function EditorManager($header, $body) {
*/
function toggleProblemButton() {
const fileWithProblems = manager.files.find((file) => {
- const annotations = file.session.getAnnotations();
+ if (file.type !== "editor") return false;
+ const annotations = file?.session?.getAnnotations();
return !!annotations.length;
});
@@ -631,20 +632,37 @@ async function EditorManager($header, $body) {
const file = manager.getFile(id);
manager.activeFile?.tab.classList.remove("active");
+
+ // Hide previous content if it was non-editor
+ if (manager.activeFile?.type !== "editor" && manager.activeFile?.content) {
+ manager.activeFile.content.style.display = "none";
+ }
+
manager.activeFile = file;
- editor.setSession(file.session);
- $header.text = file.filename;
- $hScrollbar.hideImmediately();
- $vScrollbar.hideImmediately();
+ if (file.type === "editor") {
+ editor.setSession(file.session);
+ editor.setReadOnly(!file.editable || !!file.loading);
+ $container.style.display = "block";
- setVScrollValue();
- if (!appSettings.value.textWrap) {
- setHScrollValue();
- }
+ $hScrollbar.hideImmediately();
+ $vScrollbar.hideImmediately();
- editor.setReadOnly(!file.editable || !!file.loading);
+ setVScrollValue();
+ if (!appSettings.value.textWrap) {
+ setHScrollValue();
+ }
+ } else {
+ $container.style.display = "none";
+ if (file.content) {
+ file.content.style.display = "block";
+ if (!file.content.parentElement) {
+ $container.parentElement.appendChild(file.content);
+ }
+ }
+ }
+ $header.text = file.filename;
manager.onupdate("switch-file");
events.emit("switch-file", file);
}
diff --git a/src/lib/main.js b/src/lib/main.js
index a7c724ce0..888a0e15b 100644
--- a/src/lib/main.js
+++ b/src/lib/main.js
@@ -566,6 +566,10 @@ function createFileMenu({ top, bottom, toggler }) {
innerHTML: () => {
const file = window.editorManager.activeFile;
+ if (file.type === "page") {
+ return "";
+ }
+
if (file.loading) {
$menu.classList.add("disabled");
} else {
@@ -573,15 +577,18 @@ function createFileMenu({ top, bottom, toggler }) {
}
const { label: encoding } = getEncoding(file.encoding);
-
+ const isEditorFile = file.type === "editor";
return mustache.render($_fileMenu, {
...strings,
- file_mode: (file.session.getMode().$id || "").split("/").pop(),
- file_encoding: encoding,
+ file_mode: isEditorFile
+ ? (file.session?.getMode()?.$id || "").split("/").pop()
+ : "",
+ file_encoding: isEditorFile ? encoding : "",
file_read_only: !file.editable,
file_on_disk: !!file.uri,
- file_eol: file.eol,
+ file_eol: isEditorFile ? file.eol : "",
copy_text: !!window.editorManager.editor.getCopyText(),
+ is_editor: isEditorFile,
});
},
});
diff --git a/src/lib/openFile.js b/src/lib/openFile.js
index 1df892f4f..dfd81b7e0 100644
--- a/src/lib/openFile.js
+++ b/src/lib/openFile.js
@@ -1,5 +1,5 @@
+import AudioPlayer from "components/audioPlayer";
import alert from "dialogs/alert";
-import box from "dialogs/box";
import confirm from "dialogs/confirm";
import loader from "dialogs/loader";
import fsOperation from "fileSystem";
@@ -60,6 +60,7 @@ export default async function openFile(file, options = {}) {
if (
cursorPos &&
+ existingCursorPos &&
existingCursorPos.row !== cursorPos.row &&
existingCursorPos.column !== cursorPos.column
) {
@@ -101,34 +102,241 @@ export default async function openFile(file, options = {}) {
return;
}
- const videoRegex = /\.(mp4|webm|ogg)$/i;
- const imageRegex = /\.(jpe?g|png|gif|webp)$/i;
- const audioRegex = /\.(mp3|wav|ogg)$/i;
+ const videoRegex = /\.(mp4|webm|ogg|mov|avi|wmv|flv|mkv|3gp)$/i;
+ const imageRegex = /\.(jpe?g|png|gif|webp|bmp|ico|avif|apng|tiff?)$/i;
+ const audioRegex = /\.(mp3|wav|ogg|m4a|aac|wma|flac|opus|3gp|mid|midi)$/i;
if (videoRegex.test(name)) {
const objectUrl = await fileToDataUrl(uri);
- box(
- name,
- ` `,
+ const videoContainer = (
+
);
+
+ const videoEl = (
+
+ );
+
+ videoContainer.append(videoEl);
+
+ new EditorFile(name, {
+ uri,
+ type: "video",
+ tabIcon: "file file_type_video",
+ content: videoContainer,
+ render: true,
+ });
return;
}
if (imageRegex.test(name)) {
const objectUrl = await fileToDataUrl(uri);
- box(
- name,
- ` `,
+ const imageContainer = (
+
+ );
+
+ const imgEl = (
+
);
+
+ let scale = 1;
+ let startX = 0;
+ let startY = 0;
+ let translateX = 0;
+ let translateY = 0;
+ let lastX = 0;
+ let lastY = 0;
+
+ function getBoundaries() {
+ const containerRect = imageContainer.getBoundingClientRect();
+ const imgRect = imgEl.getBoundingClientRect();
+
+ const maxX =
+ (imgRect.width * scale - containerRect.width) / (2 * scale);
+ const maxY =
+ (imgRect.height * scale - containerRect.height) / (2 * scale);
+
+ return {
+ maxX: Math.max(0, maxX),
+ maxY: Math.max(0, maxY),
+ minX: -Math.max(0, maxX),
+ minY: -Math.max(0, maxY),
+ };
+ }
+
+ function constrainTranslation() {
+ const bounds = getBoundaries();
+ translateX = Math.min(Math.max(translateX, bounds.minX), bounds.maxX);
+ translateY = Math.min(Math.max(translateY, bounds.minY), bounds.maxY);
+ }
+
+ // Zoom with mouse wheel
+ imageContainer.addEventListener("wheel", (e) => {
+ e.preventDefault();
+ const delta = e.deltaY > 0 ? -0.1 : 0.1;
+ const oldScale = scale;
+ scale = Math.max(0.1, Math.min(5, scale + delta));
+
+ // Adjust translation to zoom toward mouse position
+ const rect = imgEl.getBoundingClientRect();
+ const mouseX = e.clientX - rect.left;
+ const mouseY = e.clientY - rect.top;
+
+ const scaleChange = scale / oldScale;
+ translateX = mouseX - (mouseX - translateX) * scaleChange;
+ translateY = mouseY - (mouseY - translateY) * scaleChange;
+
+ constrainTranslation();
+ imgEl.style.transform = `scale(${scale}) translate(${translateX}px, ${translateY}px)`;
+ });
+
+ // Pan image with mouse drag or touch
+ imageContainer.addEventListener("mousedown", startDrag);
+ imageContainer.addEventListener("touchstart", (e) => {
+ if (e.touches.length === 1) {
+ startDrag(e.touches[0]);
+ } else if (e.touches.length === 2) {
+ const touch1 = e.touches[0];
+ const touch2 = e.touches[1];
+ startX = Math.abs(touch1.clientX - touch2.clientX);
+ startY = Math.abs(touch1.clientY - touch2.clientY);
+ }
+ });
+
+ function startDrag(e) {
+ lastX = e.clientX;
+ lastY = e.clientY;
+ document.addEventListener("mousemove", onDrag);
+ document.addEventListener("mouseup", stopDrag);
+ document.addEventListener("touchmove", onTouchDrag);
+ document.addEventListener("touchend", stopDrag);
+ }
+
+ function onDrag(e) {
+ const deltaX = e.clientX - lastX;
+ const deltaY = e.clientY - lastY;
+ translateX += deltaX / scale;
+ translateY += deltaY / scale;
+ lastX = e.clientX;
+ lastY = e.clientY;
+ constrainTranslation();
+ imgEl.style.transform = `scale(${scale}) translate(${translateX}px, ${translateY}px)`;
+ }
+
+ function onTouchDrag(e) {
+ if (e.touches.length === 1) {
+ const touch = e.touches[0];
+ const deltaX = touch.clientX - lastX;
+ const deltaY = touch.clientY - lastY;
+ translateX += deltaX / scale;
+ translateY += deltaY / scale;
+ lastX = touch.clientX;
+ lastY = touch.clientY;
+ constrainTranslation();
+ imgEl.style.transform = `scale(${scale}) translate(${translateX}px, ${translateY}px)`;
+ } else if (e.touches.length === 2) {
+ e.preventDefault();
+ const touch1 = e.touches[0];
+ const touch2 = e.touches[1];
+ const currentX = Math.abs(touch1.clientX - touch2.clientX);
+ const currentY = Math.abs(touch1.clientY - touch2.clientY);
+
+ const startDist = Math.sqrt(startX * startX + startY * startY);
+ const currentDist = Math.sqrt(
+ currentX * currentX + currentY * currentY,
+ );
+
+ const delta = (currentDist - startDist) / 100;
+ scale = Math.max(0.1, Math.min(5, scale + delta));
+ constrainTranslation();
+ imgEl.style.transform = `scale(${scale}) translate(${translateX}px, ${translateY}px)`;
+
+ startX = currentX;
+ startY = currentY;
+ }
+ }
+
+ function stopDrag() {
+ document.removeEventListener("mousemove", onDrag);
+ document.removeEventListener("mouseup", stopDrag);
+ document.removeEventListener("touchmove", onTouchDrag);
+ document.removeEventListener("touchend", stopDrag);
+ }
+
+ imageContainer.append(imgEl);
+
+ new EditorFile(name, {
+ uri,
+ type: "image",
+ tabIcon: "file file_type_image",
+ content: imageContainer,
+ render: true,
+ });
return;
}
if (audioRegex.test(name)) {
const objectUrl = await fileToDataUrl(uri);
- box(
- name,
- ` `,
+ const audioContainer = (
+
);
+
+ const audioPlayer = new AudioPlayer(audioContainer);
+ audioPlayer.loadTrack(objectUrl);
+
+ const audioTab = new EditorFile(name, {
+ uri,
+ type: "audio",
+ tabIcon: "file file_type_audio",
+ content: audioPlayer.container,
+ render: true,
+ });
+ audioTab.onclose = () => {
+ audioPlayer.cleanup();
+ };
return;
}
diff --git a/src/lib/saveState.js b/src/lib/saveState.js
index 5bb4a78bf..68786378a 100644
--- a/src/lib/saveState.js
+++ b/src/lib/saveState.js
@@ -11,6 +11,7 @@ export default () => {
const { value: settings } = appSettings;
files.forEach((file) => {
+ if (file.type !== "editor") return;
if (file.id === constants.DEFAULT_FILE_SESSION) return;
const fileJson = {
@@ -55,12 +56,18 @@ export default () => {
};
function parseFolds(folds) {
- return folds.map((fold) => {
- const { range, ranges, placeholder } = fold;
- return {
- range,
- ranges: parseFolds(ranges),
- placeholder,
- };
- });
+ if (!Array.isArray(folds)) return [];
+
+ return folds
+ .map((fold) => {
+ if (!fold || !fold.range) return null;
+
+ const { range, ranges, placeholder } = fold;
+ return {
+ range,
+ ranges: parseFolds(ranges || []),
+ placeholder,
+ };
+ })
+ .filter(Boolean);
}
diff --git a/src/lib/showFileInfo.js b/src/lib/showFileInfo.js
index 8ff60ad5c..39b3c79ec 100644
--- a/src/lib/showFileInfo.js
+++ b/src/lib/showFileInfo.js
@@ -17,24 +17,30 @@ export default async function showFileInfo(url) {
try {
const fs = fsOperation(url);
const stats = await fs.stat();
- const value = await fs.readFile(settings.value.defaultFileEncoding);
let { name, lastModified, length, type } = stats;
length = filesize(length);
lastModified = new Date(lastModified).toLocaleString();
const protocol = Url.getProtocol(url);
+ const fileType = type.toLowerCase();
const options = {
name,
lastModified,
length,
type,
- lineCount: value.split(/\n+/).length,
- wordCount: value.split(/\s+|\n+/).length,
lang: strings,
showUri: helpers.getVirtualPath(url),
+ isEditor:
+ fileType === "text/plain" || editorManager.activeFile.type === "editor",
};
+ if (editorManager.activeFile.type === "editor") {
+ const value = await fs.readFile(settings.value.defaultFileEncoding);
+ options.lineCount = value.split(/\n+/).length;
+ options.wordCount = value.split(/\s+|\n+/).length;
+ }
+
if (/s?ftp:/.test(protocol)) {
options.shareUri = Url.join(CACHE_STORAGE, name);
const fs = fsOperation(options.shareUri);
diff --git a/src/pages/problems/problems.js b/src/pages/problems/problems.js
index d9988c69a..df7156ffa 100644
--- a/src/pages/problems/problems.js
+++ b/src/pages/problems/problems.js
@@ -11,8 +11,9 @@ export default function Problems() {
const $content =
;
files.forEach((file) => {
+ if (file.type !== "editor") return;
/**@type {[]} */
- const annotations = file.session.getAnnotations();
+ const annotations = file.session?.getAnnotations();
if (!annotations.length) return;
$content.append(
diff --git a/src/plugins/sdcard/src/android/SDcard.java b/src/plugins/sdcard/src/android/SDcard.java
index 12a5dc022..31de8d309 100644
--- a/src/plugins/sdcard/src/android/SDcard.java
+++ b/src/plugins/sdcard/src/android/SDcard.java
@@ -316,8 +316,12 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (uri == null) {
activityResultCallback.error("No file selected");
} else {
- takePermission(uri);
- activityResultCallback.success(uri.toString());
+ try {
+ takePermission(uri);
+ activityResultCallback.success(uri.toString());
+ } catch (Exception e) {
+ activityResultCallback.error("Error taking permission: " + e.getMessage());
+ }
}
activityResultCallback.success(uri.toString());
}
diff --git a/src/styles/main.scss b/src/styles/main.scss
index 1884d5160..fad7a5956 100644
--- a/src/styles/main.scss
+++ b/src/styles/main.scss
@@ -1,831 +1,848 @@
-@import './mixins.scss';
-@import './keyframes.scss';
-@import './fileInfo.scss';
-@import './markdown.scss';
-
-:root {
- --scrollbar-width: 4px;
-}
-
-* {
- margin: 0;
- padding: 0;
-
- &:focus {
- outline: none;
- }
-}
-
-html {
- overflow: auto;
-}
-
-html,
-body {
- width: 100%;
- height: 100%;
- font-size: 14px;
-}
-
-body {
- user-select: none;
- font-family: 'Roboto', sans-serif;
- -webkit-tap-highlight-color: transparent;
- background-color: #9999ff;
- background-color: var(--primary-color);
- color: #252525;
- color: var(--secondary-text-color);
-
- &.no-animation * {
- animation: none !important;
- transition: none !important;
- box-shadow: none !important;
- }
-
- &:not(.loading).title-loading {
- &.title-loading-hide {
- &::after {
- background-image: none;
- transform: translateX(-50%) translateY(-100%) scale3d(0.5, 0.5, 1);
- opacity: 0;
- animation: hide-loader 100ms ease-in 1;
- }
- }
-
- &::after {
- content: '';
- background-color: #3333ff;
- background-color: var(--primary-color);
- border-radius: 50%;
- position: fixed;
- height: 40px;
- width: 40px;
- top: 6px;
- left: 50%;
- transform: translateX(-50%);
- background-image: url(https://localhost/__cdvfile_assets__/www/res/tail-spin.svg);
- background-repeat: no-repeat;
- background-position: center;
- background-size: 30px;
- box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.2);
- box-shadow: 0 0 4px 0 var(--box-shadow-color);
- border: solid 1px transparent;
- border: solid 1px var(--popup-border-color);
- animation: appear 100ms ease-out 1;
- box-sizing: border-box;
- z-index: 999;
- }
- }
-
- .main {
- position: relative;
- }
-}
-
-a {
- color: #615efd;
- color: var(--link-text-color);
-}
-
-.open-file-list {
- position: relative;
- height: 30px;
- width: 100%;
- background-color: #9999ff;
- background-color: var(--primary-color);
- overflow-x: auto !important;
- overflow-y: hidden !important;
- display: flex;
- flex-direction: row !important;
- color: white;
- color: var(--primary-text-color);
- z-index: 5;
-
- li.tile {
- $width: 120px;
- height: 100%;
- overflow: hidden;
- font-size: 0.8em;
- align-items: center;
- margin: 0;
- padding: 0;
- color: inherit;
- min-width: $width;
- min-width: var(--file-tab-width);
- max-width: $width;
- max-width: var(--file-tab-width);
-
- .text {
- display: inline-block;
- white-space: nowrap;
- max-width: $width;
- max-width: var(--file-tab-width);
- overflow: hidden;
- text-overflow: ellipsis;
- margin: 0;
- padding: 0;
- color: inherit;
- }
-
- &.notice {
- &::before {
- content: '•';
- color: #ffda0c;
- font-size: 1.5em;
- margin-left: 2.5px;
- text-shadow: 0px 0px 2px rgba(0, 0, 0, 0.5);
- }
- }
-
- &.active {
- border-top: solid 2px gold;
- background-color: rgba(0, 0, 0, 0.2);
- }
-
- .file,
- .icon {
- height: 24px;
- width: 24px;
- font-size: 1em;
- background-size: 22px;
- background-position: center;
- color: inherit;
- }
- }
-}
-
-a.icon {
- pointer-events: all !important;
- color: white;
-
- &:focus,
- &:active {
- border: none;
- outline: none;
- }
-}
-
-.no-scroll {
- &::-webkit-scrollbar {
- width: 0px;
- height: 0px;
- }
-}
-
-.list,
-.prompt,
-.scroll {
- &::-webkit-scrollbar {
- width: var(--scrollbar-width);
- height: var(--scrollbar-width);
- }
-
- &::-webkit-scrollbar-track {
- background: transparent;
- }
-
- &::-webkit-scrollbar-thumb {
- background: rgba(0, 0, 0, 0.333);
- background: var(--scrollbar-color);
- border-radius: calc(var(--scrollbar-width) / 2);
- }
-}
-
-.icon {
- user-select: none;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 50%;
- text-decoration: none;
- text-rendering: auto;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- background-position: center;
- background-size: 24px;
- background-repeat: no-repeat;
-
- &.hidden {
- display: none !important;
- }
-
- &.color {
- display: flex;
-
- &::before {
- content: '';
- height: 16px;
- width: 16px;
- border: solid 1px #a90000;
- border: solid 1px var(--active-color);
- background-color: currentColor;
- color: inherit !important;
- }
-
- &.dark {
- color: #252525;
- }
-
- &.light {
- color: #ffffff;
- }
- }
-
- &.notice {
- @include icon-badge;
- }
-
- &.angularjs::before {
- content: '\e92f';
- color: #dd0031;
- }
-
- &.html::before {
- content: '\e939';
- color: #e34f26;
- }
-
- &.disabled {
- opacity: 0.6;
- pointer-events: none;
- }
-
- &.dull {
- opacity: 0.6;
- }
-
- &:focus {
- border: rgba(0, 0, 0, 0.1);
- }
-
- &:not(.floating):active {
- transition: all 100ms ease;
- background-color: rgba(0, 0, 0, 0.2) !important;
- background-color: var(--active-icon-color) !important;
- }
-
- &.active {
- background-color: rgba(0, 0, 0, 0.2) !important;
- background-color: var(--active-icon-color) !important;
- }
-
- &.foxdebug {
- background-image: url(https://localhost/__cdvfile_assets__/www/res/logo/favicon.ico);
- }
-
- &.no-icon {
- max-width: 5px;
- margin-right: 5px;
- border-radius: 0;
- }
-
- &.letters::before {
- content: attr(data-letters);
- text-transform: uppercase;
- font-size: 0.6em;
- font-weight: bolder;
- }
-
- &.verified {
- background-image: url(https://localhost/__cdvfile_assets__/www/res/verified.svg);
- }
-}
-
-.mask {
- position: fixed;
- left: 0;
- top: 0;
- display: block;
- height: 100vh;
- width: 100vw;
- background-color: black;
- opacity: 0;
-}
-
-footer {
-
- &.button-container,
- .button-container {
- overflow-x: auto;
-
- .section {
- max-width: 100%;
- min-width: 100%;
-
- .icon.active {
- @include active-icon;
- }
- }
-
- background-color: #9999ff;
- background-color: var(--primary-color);
- color: white;
- color: var(--primary-text-color);
- }
-}
-
-.section,
-.button-container {
- display: flex;
- min-height: 40px;
- background-color: inherit;
- color: inherit;
- user-select: none;
- width: 100%;
-
- &.primary {
- button {
- color: white !important;
- color: var(--button-text-color) !important;
- background-color: #39f !important;
- background-color: var(--button-background-color) !important;
- box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
- box-shadow: 0 0 4px var(--box-shadow-color);
- border-radius: 4px;
-
- &:active {
- background-color: #2c8ef0 !important;
- background-color: var(--button-active-color) !important;
- box-shadow: 0 0 2px rgba(0, 0, 0, 0.4);
- box-shadow: inset 0 0 2px var(--box-shadow-color);
- }
- }
- }
-
- &.disabled {
- pointer-events: none;
-
- .icon,
- input,
- button {
- opacity: 0.6;
- }
- }
-
- >button {
- flex: 1;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- border: none;
- text-transform: uppercase;
- background-color: inherit;
- color: inherit;
-
- * {
- pointer-events: none;
- }
-
- &.disabled {
- pointer-events: none;
- opacity: 0.6;
- }
-
- &:active {
- transition: all 100ms ease;
- box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.2);
- box-shadow: inset 0 0 4px var(--box-shadow-color);
- }
-
- &:disabled {
- opacity: 0.6;
- }
- }
-
- textarea,
- input {
- flex: 2;
- height: auto;
- color: inherit;
- border-bottom: 1px solid currentColor;
- margin: 5px;
- background-color: inherit;
-
- &::placeholder {
- color: rgba(255, 255, 255, 0.6);
- }
- }
-
- .icon {
- color: inherit;
- font-size: 1.3em;
- }
-
- .search,
- .save {
- font-size: 1em;
- }
-}
-
-input {
- height: 40px;
- outline: none;
- border: none;
- background-color: inherit;
- border-bottom: solid 1px #252525;
- border-bottom: solid 1px var(--secondary-text-color);
- padding: 0;
- box-sizing: border-box;
- color: #252525;
- color: var(--secondary-text-color);
- caret-color: currentColor;
- text-indent: 10px;
-
- &:focus {
- border-bottom-color: #a90000 !important;
- border-bottom-color: var(--active-color) !important;
- }
-}
-
-input,
-textarea {
- &::placeholder {
- color: inherit;
- opacity: 0.8;
- }
-}
-
-.search-status {
- flex: 1;
- display: flex;
- color: white;
- color: var(--primary-text-color);
- align-items: center;
- justify-content: center;
-
- span:not(:nth-child(2)) {
- margin: 0 5px;
- color: white;
- color: var(--primary-text-color);
- }
-}
-
-.cursor {
- position: absolute;
- top: 0;
- left: 0;
- display: block;
- border-radius: 50%;
- background-color: white;
- background-color: var(--primary-text-color);
- border: solid 1px #666;
- box-sizing: border-box;
- transform-origin: left top;
- z-index: 4;
- pointer-events: none;
-
- &[data-size='60'] {
- width: 60px;
- height: 60px;
- }
-
- &[data-size='30'] {
- width: 30px;
- height: 30px;
- }
-
- &[data-size='20'] {
- width: 20px;
- height: 20px;
- }
-
- &.end {
- border-radius: 0% 50% 50% 50%;
- }
-
- &.start {
- border-radius: 50% 0 50% 50%;
- }
-
- &.single {
- transform: rotate(45deg);
- border-radius: 0 50% 50% 50%;
- }
-}
-
-.cursor-menu {
- position: absolute;
- top: 0;
- left: 0;
- height: 40px;
- background-color: #ffffff;
- background-color: var(--secondary-color);
- display: flex;
- border-radius: 4px;
- box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
- box-shadow: 0 0 8px var(--box-shadow-color);
- border: none;
- border: solid 1px var(--popup-border-color);
- color: #252525;
- color: var(--secondary-text-color);
- transform-origin: left center;
- z-index: 4;
-
- >span,
- >div {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- height: 100%;
- font-size: 0.9em;
- min-width: 50px;
- color: inherit;
- user-select: none;
- white-space: nowrap;
-
- &.disabled {
- opacity: 0.6;
- pointer-events: none;
- }
- }
-}
-
-.file {
- display: flex;
- align-items: center;
- justify-content: center;
- background-repeat: no-repeat;
- background-position: 6px center;
- background-size: 18px;
- width: 30px;
- height: 30px;
-}
-
-.hr {
- display: flex;
- align-items: center;
- margin: auto auto 15px auto;
-
- &::after,
- &::before {
- content: '';
- height: 1px;
- width: 60px;
- background-color: #252525;
- background-color: var(--secondary-text-color);
- margin: auto 15px;
- opacity: 0.5;
- }
-}
-
-.d-none {
- display: none !important;
-}
-
-.floating.icon {
- position: fixed;
- height: 50px;
- width: 50px;
- font-size: 1.6rem;
- border: 1px solid;
- background-color: #9999ff;
- background-color: var(--primary-color);
- top: 10px;
- right: 10px;
- opacity: 0.2;
- box-sizing: border-box;
- color: white;
- color: var(--primary-text-color);
- transition: all 300ms ease;
- box-shadow: -5px 5px 20px 0px rgba(0, 0, 0, 0.5);
-
- &:active {
- transition: all 100ms ease;
- box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.5);
- }
-
- &.hide {
- opacity: 0 !important;
- }
-}
-
-button {
- &.floating.icon {
- z-index: 1;
- opacity: 1;
-
- &:disabled {
- opacity: 0.2;
- }
- }
-}
-
-#social-links {
- position: relative;
- height: 60px;
- font-size: 1.2em;
- width: 100%;
- text-align: center;
-
- &::after {
- display: block;
- width: 100%;
- content: attr(title);
- text-align: center;
- font-size: 0.5em;
- text-transform: none;
- }
-
- a {
- display: inline-flex;
- min-height: 40px;
- min-width: 40px;
- text-shadow: 0 0 1px white;
-
- &.github {
- color: black;
- }
- }
-}
-
-#header-toggler {
- display: none;
- top: 10px;
- right: 10px;
- z-index: 1;
- height: 40px;
- width: 40px;
-}
-
-#sidebar-toggler {
- display: none;
- top: 10px;
- left: 10px;
- z-index: 1;
- height: 40px;
- width: 40px;
-}
-
-#quicktools-toggler {
- top: auto;
- bottom: 10px;
- right: 10px;
- z-index: 1;
-}
-
-.sake {
- animation: sake 3s ease-out infinite;
-}
-
-.flex-center {
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.link {
- text-decoration: underline;
-}
-
-.w-resize {
- cursor: w-resize;
-}
-
-.note {
- margin: 20px 0;
-
- .note-title {
- background-color: rgba(0, 0, 0, 0.2);
- display: flex;
- align-items: center;
- justify-content: center;
- height: 30px;
- text-transform: uppercase;
-
- .icon {
- margin: 0 10px;
- }
- }
-
- p {
- padding: 10px;
- box-sizing: border-box;
- opacity: 0.8;
- font-size: 0.9rem;
- }
-}
-
-input[type="search"]::-webkit-search-decoration,
-input[type="search"]::-webkit-search-cancel-button,
-input[type="search"]::-webkit-search-results-button,
-input[type="search"]::-webkit-search-results-decoration {
- -webkit-appearance: none;
-}
-
-.notification-toast-container {
- position: absolute;
- bottom: 20px;
- right: 20px;
- display: flex;
- flex-direction: column;
- gap: 8px;
- z-index: 1000;
-
- .notification-toast {
- padding: 12px;
- border-radius: 6px;
- background: var(--secondary-color);
- min-width: 300px;
- max-width: 400px;
- display: flex;
- gap: 12px;
- align-items: flex-start;
- box-shadow: 0 4px 12px var(--box-shadow-color);
- animation: toastSlideIn 0.3s ease-out;
- transition: all 0.3s ease;
- border: 1px solid var(--border-color);
- word-break: break-word;
- white-space: normal;
-
- &.hiding {
- transform: translateX(120%);
- opacity: 0;
- }
-
- .close-icon {
- cursor: pointer;
- font-size: 14px;
- color: var(--secondary-text-color);
- margin-left: auto;
-
- &:hover {
- color: var(--button-background-color);
- }
- }
-
- .notification-icon {
- width: 20px;
- height: 20px;
- display: flex;
- align-items: center;
- justify-content: center;
- flex-shrink: 0;
- color: var(--primary-text-color);
- }
-
- .notification-content {
- flex: 1;
- min-width: 0;
-
- .notification-title {
- font-size: 13px;
- font-weight: 500;
- margin-bottom: 4px;
- color: var(--primary-text-color);
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
-
- .notification-message {
- font-size: 12px;
- color: var(--secondary-text-color);
- line-height: 1.4;
- overflow-wrap: break-word;
- hyphens: auto;
- }
- }
-
- &.success {
- .notification-icon {
- color: #48c158;
- }
- }
-
- &.warning {
- .notification-icon {
- color: var(--danger-text-color);
- }
- }
-
- &.error {
- .notification-icon {
- color: var(--error-text-color);
- }
- }
-
- &.info {
- .notification-icon {
- color: var(--primary-text-color);
- }
- }
- }
-
- @media (max-width: 768px) {
- .notification-toast {
- min-width: auto;
- max-width: calc(100vw - 40px);
- }
- }
-}
-
-@keyframes toastSlideIn {
- from {
- transform: translateX(120%);
- opacity: 0;
- }
- to {
- transform: translateX(0);
- opacity: 1;
- }
-}
+@import "./mixins.scss";
+@import "./keyframes.scss";
+@import "./fileInfo.scss";
+@import "./markdown.scss";
+
+:root {
+ --scrollbar-width: 4px;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+
+ &:focus {
+ outline: none;
+ }
+}
+
+html {
+ overflow: auto;
+}
+
+html,
+body {
+ width: 100%;
+ height: 100%;
+ font-size: 14px;
+}
+
+body {
+ user-select: none;
+ font-family: "Roboto", sans-serif;
+ -webkit-tap-highlight-color: transparent;
+ background-color: #9999ff;
+ background-color: var(--primary-color);
+ color: #252525;
+ color: var(--secondary-text-color);
+
+ &.no-animation * {
+ animation: none !important;
+ transition: none !important;
+ box-shadow: none !important;
+ }
+
+ &:not(.loading).title-loading {
+ &.title-loading-hide {
+ &::after {
+ background-image: none;
+ transform: translateX(-50%) translateY(-100%) scale3d(0.5, 0.5, 1);
+ opacity: 0;
+ animation: hide-loader 100ms ease-in 1;
+ }
+ }
+
+ &::after {
+ content: "";
+ background-color: #3333ff;
+ background-color: var(--primary-color);
+ border-radius: 50%;
+ position: fixed;
+ height: 40px;
+ width: 40px;
+ top: 6px;
+ left: 50%;
+ transform: translateX(-50%);
+ background-image: url(https://localhost/__cdvfile_assets__/www/res/tail-spin.svg);
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size: 30px;
+ box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.2);
+ box-shadow: 0 0 4px 0 var(--box-shadow-color);
+ border: solid 1px transparent;
+ border: solid 1px var(--popup-border-color);
+ animation: appear 100ms ease-out 1;
+ box-sizing: border-box;
+ z-index: 999;
+ }
+ }
+
+ .main {
+ position: relative;
+ }
+}
+
+a {
+ color: #615efd;
+ color: var(--link-text-color);
+}
+
+.open-file-list {
+ position: relative;
+ height: 30px;
+ width: 100%;
+ background-color: #9999ff;
+ background-color: var(--primary-color);
+ overflow-x: auto !important;
+ overflow-y: hidden !important;
+ display: flex;
+ flex-direction: row !important;
+ color: white;
+ color: var(--primary-text-color);
+ z-index: 5;
+
+ li.tile {
+ $width: 120px;
+ height: 100%;
+ overflow: hidden;
+ font-size: 0.8em;
+ align-items: center;
+ margin: 0;
+ padding: 0;
+ color: inherit;
+ min-width: $width;
+ min-width: var(--file-tab-width);
+ max-width: $width;
+ max-width: var(--file-tab-width);
+
+ .text {
+ display: inline-block;
+ white-space: nowrap;
+ max-width: $width;
+ max-width: var(--file-tab-width);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ margin: 0;
+ padding: 0;
+ color: inherit;
+ }
+
+ &.notice {
+ &::before {
+ content: "•";
+ color: #ffda0c;
+ font-size: 1.5em;
+ margin-left: 2.5px;
+ text-shadow: 0px 0px 2px rgba(0, 0, 0, 0.5);
+ }
+ }
+
+ &.active {
+ border-top: solid 2px gold;
+ background-color: rgba(0, 0, 0, 0.2);
+ }
+
+ .file,
+ .icon {
+ height: 24px;
+ width: 24px;
+ font-size: 1em;
+ background-size: 22px;
+ background-position: center;
+ color: inherit;
+ }
+ }
+}
+
+a.icon {
+ pointer-events: all !important;
+ color: white;
+
+ &:focus,
+ &:active {
+ border: none;
+ outline: none;
+ }
+}
+
+.no-scroll {
+ &::-webkit-scrollbar {
+ width: 0px;
+ height: 0px;
+ }
+}
+
+.list,
+.prompt,
+.scroll {
+ &::-webkit-scrollbar {
+ width: var(--scrollbar-width);
+ height: var(--scrollbar-width);
+ }
+
+ &::-webkit-scrollbar-track {
+ background: transparent;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: rgba(0, 0, 0, 0.333);
+ background: var(--scrollbar-color);
+ border-radius: calc(var(--scrollbar-width) / 2);
+ }
+}
+
+.icon {
+ user-select: none;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ text-decoration: none;
+ text-rendering: auto;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ background-position: center;
+ background-size: 24px;
+ background-repeat: no-repeat;
+
+ &.hidden {
+ display: none !important;
+ }
+
+ &.color {
+ display: flex;
+
+ &::before {
+ content: "";
+ height: 16px;
+ width: 16px;
+ border: solid 1px #a90000;
+ border: solid 1px var(--active-color);
+ background-color: currentColor;
+ color: inherit !important;
+ }
+
+ &.dark {
+ color: #252525;
+ }
+
+ &.light {
+ color: #ffffff;
+ }
+ }
+
+ &.notice {
+ @include icon-badge;
+ }
+
+ &.angularjs::before {
+ content: "\e92f";
+ color: #dd0031;
+ }
+
+ &.html::before {
+ content: "\e939";
+ color: #e34f26;
+ }
+
+ &.disabled {
+ opacity: 0.6;
+ pointer-events: none;
+ }
+
+ &.dull {
+ opacity: 0.6;
+ }
+
+ &:focus {
+ border: rgba(0, 0, 0, 0.1);
+ }
+
+ &:not(.floating):active {
+ transition: all 100ms ease;
+ background-color: rgba(0, 0, 0, 0.2) !important;
+ background-color: var(--active-icon-color) !important;
+ }
+
+ &.active {
+ background-color: rgba(0, 0, 0, 0.2) !important;
+ background-color: var(--active-icon-color) !important;
+ }
+
+ &.foxdebug {
+ background-image: url(https://localhost/__cdvfile_assets__/www/res/logo/favicon.ico);
+ }
+
+ &.no-icon {
+ max-width: 5px;
+ margin-right: 5px;
+ border-radius: 0;
+ }
+
+ &.letters::before {
+ content: attr(data-letters);
+ text-transform: uppercase;
+ font-size: 0.6em;
+ font-weight: bolder;
+ }
+
+ &.verified {
+ background-image: url(https://localhost/__cdvfile_assets__/www/res/verified.svg);
+ }
+}
+
+.mask {
+ position: fixed;
+ left: 0;
+ top: 0;
+ display: block;
+ height: 100vh;
+ width: 100vw;
+ background-color: black;
+ opacity: 0;
+}
+
+footer {
+ &.button-container,
+ .button-container {
+ overflow-x: auto;
+
+ .section {
+ max-width: 100%;
+ min-width: 100%;
+
+ .icon.active {
+ @include active-icon;
+ }
+ }
+
+ background-color: #9999ff;
+ background-color: var(--primary-color);
+ color: white;
+ color: var(--primary-text-color);
+ }
+}
+
+.section,
+.button-container {
+ display: flex;
+ min-height: 40px;
+ background-color: inherit;
+ color: inherit;
+ user-select: none;
+ width: 100%;
+
+ &.primary {
+ button {
+ color: white !important;
+ color: var(--button-text-color) !important;
+ background-color: #39f !important;
+ background-color: var(--button-background-color) !important;
+ box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
+ box-shadow: 0 0 4px var(--box-shadow-color);
+ border-radius: 4px;
+
+ &:active {
+ background-color: #2c8ef0 !important;
+ background-color: var(--button-active-color) !important;
+ box-shadow: 0 0 2px rgba(0, 0, 0, 0.4);
+ box-shadow: inset 0 0 2px var(--box-shadow-color);
+ }
+ }
+ }
+
+ &.disabled {
+ pointer-events: none;
+
+ .icon,
+ input,
+ button {
+ opacity: 0.6;
+ }
+ }
+
+ > button {
+ flex: 1;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border: none;
+ text-transform: uppercase;
+ background-color: inherit;
+ color: inherit;
+
+ * {
+ pointer-events: none;
+ }
+
+ &.disabled {
+ pointer-events: none;
+ opacity: 0.6;
+ }
+
+ &:active {
+ transition: all 100ms ease;
+ box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.2);
+ box-shadow: inset 0 0 4px var(--box-shadow-color);
+ }
+
+ &:disabled {
+ opacity: 0.6;
+ }
+ }
+
+ textarea,
+ input {
+ flex: 2;
+ height: auto;
+ color: inherit;
+ border-bottom: 1px solid currentColor;
+ margin: 5px;
+ background-color: inherit;
+
+ &::placeholder {
+ color: rgba(255, 255, 255, 0.6);
+ }
+ }
+
+ .icon {
+ color: inherit;
+ font-size: 1.3em;
+ }
+
+ .search,
+ .save {
+ font-size: 1em;
+ }
+}
+
+input {
+ height: 40px;
+ outline: none;
+ border: none;
+ background-color: inherit;
+ border-bottom: solid 1px #252525;
+ border-bottom: solid 1px var(--secondary-text-color);
+ padding: 0;
+ box-sizing: border-box;
+ color: #252525;
+ color: var(--secondary-text-color);
+ caret-color: currentColor;
+ text-indent: 10px;
+
+ &:focus {
+ border-bottom-color: #a90000 !important;
+ border-bottom-color: var(--active-color) !important;
+ }
+}
+
+input,
+textarea {
+ &::placeholder {
+ color: inherit;
+ opacity: 0.8;
+ }
+}
+
+.search-status {
+ flex: 1;
+ display: flex;
+ color: white;
+ color: var(--primary-text-color);
+ align-items: center;
+ justify-content: center;
+
+ span:not(:nth-child(2)) {
+ margin: 0 5px;
+ color: white;
+ color: var(--primary-text-color);
+ }
+}
+
+.cursor {
+ position: absolute;
+ top: 0;
+ left: 0;
+ display: block;
+ border-radius: 50%;
+ background-color: white;
+ background-color: var(--primary-text-color);
+ border: solid 1px #666;
+ box-sizing: border-box;
+ transform-origin: left top;
+ z-index: 4;
+ pointer-events: none;
+
+ &[data-size="60"] {
+ width: 60px;
+ height: 60px;
+ }
+
+ &[data-size="30"] {
+ width: 30px;
+ height: 30px;
+ }
+
+ &[data-size="20"] {
+ width: 20px;
+ height: 20px;
+ }
+
+ &.end {
+ border-radius: 0% 50% 50% 50%;
+ }
+
+ &.start {
+ border-radius: 50% 0 50% 50%;
+ }
+
+ &.single {
+ transform: rotate(45deg);
+ border-radius: 0 50% 50% 50%;
+ }
+}
+
+.cursor-menu {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 40px;
+ background-color: #ffffff;
+ background-color: var(--secondary-color);
+ display: flex;
+ border-radius: 4px;
+ box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
+ box-shadow: 0 0 8px var(--box-shadow-color);
+ border: none;
+ border: solid 1px var(--popup-border-color);
+ color: #252525;
+ color: var(--secondary-text-color);
+ transform-origin: left center;
+ z-index: 4;
+
+ > span,
+ > div {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ font-size: 0.9em;
+ min-width: 50px;
+ color: inherit;
+ user-select: none;
+ white-space: nowrap;
+
+ &.disabled {
+ opacity: 0.6;
+ pointer-events: none;
+ }
+ }
+}
+
+.file {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-repeat: no-repeat;
+ background-position: 6px center;
+ background-size: 18px;
+ width: 30px;
+ height: 30px;
+}
+
+.hr {
+ display: flex;
+ align-items: center;
+ margin: auto auto 15px auto;
+
+ &::after,
+ &::before {
+ content: "";
+ height: 1px;
+ width: 60px;
+ background-color: #252525;
+ background-color: var(--secondary-text-color);
+ margin: auto 15px;
+ opacity: 0.5;
+ }
+}
+
+.d-none {
+ display: none !important;
+}
+
+.floating.icon {
+ position: fixed;
+ height: 50px;
+ width: 50px;
+ font-size: 1.6rem;
+ border: 1px solid;
+ background-color: #9999ff;
+ background-color: var(--primary-color);
+ top: 10px;
+ right: 10px;
+ opacity: 0.2;
+ box-sizing: border-box;
+ color: white;
+ color: var(--primary-text-color);
+ transition: all 300ms ease;
+ box-shadow: -5px 5px 20px 0px rgba(0, 0, 0, 0.5);
+
+ &:active {
+ transition: all 100ms ease;
+ box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.5);
+ }
+
+ &.hide {
+ opacity: 0 !important;
+ }
+}
+
+button {
+ &.floating.icon {
+ z-index: 1;
+ opacity: 1;
+
+ &:disabled {
+ opacity: 0.2;
+ }
+ }
+}
+
+#social-links {
+ position: relative;
+ height: 60px;
+ font-size: 1.2em;
+ width: 100%;
+ text-align: center;
+
+ &::after {
+ display: block;
+ width: 100%;
+ content: attr(title);
+ text-align: center;
+ font-size: 0.5em;
+ text-transform: none;
+ }
+
+ a {
+ display: inline-flex;
+ min-height: 40px;
+ min-width: 40px;
+ text-shadow: 0 0 1px white;
+
+ &.github {
+ color: black;
+ }
+ }
+}
+
+#header-toggler {
+ display: none;
+ top: 10px;
+ right: 10px;
+ z-index: 1;
+ height: 40px;
+ width: 40px;
+}
+
+#sidebar-toggler {
+ display: none;
+ top: 10px;
+ left: 10px;
+ z-index: 1;
+ height: 40px;
+ width: 40px;
+}
+
+#quicktools-toggler {
+ top: auto;
+ bottom: 10px;
+ right: 10px;
+ z-index: 1;
+}
+
+.sake {
+ animation: sake 3s ease-out infinite;
+}
+
+.flex-center {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.link {
+ text-decoration: underline;
+}
+
+.w-resize {
+ cursor: w-resize;
+}
+
+.note {
+ margin: 20px 0;
+
+ .note-title {
+ background-color: rgba(0, 0, 0, 0.2);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 30px;
+ text-transform: uppercase;
+
+ .icon {
+ margin: 0 10px;
+ }
+ }
+
+ p {
+ padding: 10px;
+ box-sizing: border-box;
+ opacity: 0.8;
+ font-size: 0.9rem;
+ }
+}
+
+input[type="search"]::-webkit-search-decoration,
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-results-button,
+input[type="search"]::-webkit-search-results-decoration {
+ -webkit-appearance: none;
+}
+
+.tab-page-container {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ overflow: hidden;
+}
+
+.tab-page-content {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ overflow: auto;
+}
+
+.notification-toast-container {
+ position: absolute;
+ bottom: 20px;
+ right: 20px;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ z-index: 1000;
+
+ .notification-toast {
+ padding: 12px;
+ border-radius: 6px;
+ background: var(--secondary-color);
+ min-width: 300px;
+ max-width: 400px;
+ display: flex;
+ gap: 12px;
+ align-items: flex-start;
+ box-shadow: 0 4px 12px var(--box-shadow-color);
+ animation: toastSlideIn 0.3s ease-out;
+ transition: all 0.3s ease;
+ border: 1px solid var(--border-color);
+ word-break: break-word;
+ white-space: normal;
+
+ &.hiding {
+ transform: translateX(120%);
+ opacity: 0;
+ }
+
+ .close-icon {
+ cursor: pointer;
+ font-size: 14px;
+ color: var(--secondary-text-color);
+ margin-left: auto;
+
+ &:hover {
+ color: var(--button-background-color);
+ }
+ }
+
+ .notification-icon {
+ width: 20px;
+ height: 20px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ color: var(--primary-text-color);
+ }
+
+ .notification-content {
+ flex: 1;
+ min-width: 0;
+
+ .notification-title {
+ font-size: 13px;
+ font-weight: 500;
+ margin-bottom: 4px;
+ color: var(--primary-text-color);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ .notification-message {
+ font-size: 12px;
+ color: var(--secondary-text-color);
+ line-height: 1.4;
+ overflow-wrap: break-word;
+ hyphens: auto;
+ }
+ }
+
+ &.success {
+ .notification-icon {
+ color: #48c158;
+ }
+ }
+
+ &.warning {
+ .notification-icon {
+ color: var(--danger-text-color);
+ }
+ }
+
+ &.error {
+ .notification-icon {
+ color: var(--error-text-color);
+ }
+ }
+
+ &.info {
+ .notification-icon {
+ color: var(--primary-text-color);
+ }
+ }
+ }
+
+ @media (max-width: 768px) {
+ .notification-toast {
+ min-width: auto;
+ max-width: calc(100vw - 40px);
+ }
+ }
+}
+
+@keyframes toastSlideIn {
+ from {
+ transform: translateX(120%);
+ opacity: 0;
+ }
+ to {
+ transform: translateX(0);
+ opacity: 1;
+ }
+}
diff --git a/src/views/file-info.hbs b/src/views/file-info.hbs
index e30cc62d1..c8ddc377f 100644
--- a/src/views/file-info.hbs
+++ b/src/views/file-info.hbs
@@ -10,14 +10,16 @@
{{lang.last modified}}
{{lastModified}}
-
- {{lang.line count}}
- {{lineCount}}
-
-
- {{lang.word count}}
- {{wordCount}}
-
+{{#isEditor}}
+
+ {{lang.line count}}
+ {{lineCount}}
+
+
+ {{lang.word count}}
+ {{wordCount}}
+
+{{/isEditor}}
{{lang.type}}
{{type}}
@@ -26,4 +28,4 @@
{{lang.path}}
{{showUri}}
-
\ No newline at end of file
+
diff --git a/src/views/file-menu.hbs b/src/views/file-menu.hbs
index ee32817b3..734e2a5cb 100644
--- a/src/views/file-menu.hbs
+++ b/src/views/file-menu.hbs
@@ -6,6 +6,7 @@
{{rename}}
+{{#is_editor}}
{{syntax highlighting}}
@@ -24,6 +25,9 @@
{{file_eol}}
+{{/is_editor}}
+
+{{#is_editor}}
{{read only}}
@@ -38,6 +42,7 @@
{{format}}
+{{/is_editor}}
{{#file_on_disk}}
@@ -53,6 +58,8 @@
{{/file_on_disk}}
+
+{{#is_editor}}
{{search}}
@@ -93,4 +100,5 @@
{{select all}}
-
\ No newline at end of file
+
+{{/is_editor}}