Apply global styles for visual consistency
This commit centralizes the styling of key UI elements across the project to ensure: - Consistent look and feel. - Enhanced code reusability. - Simpified maintenance, improving development speed. It establishes a uniform foundation that can be leveraged across different parts of the project, even enabling the styling to be shared across different websites (supporting issue #49). Key changes: - Apply the following shared styles globally: * Styling of code, blockquotes, superscripts, horizontal rules and anchors. * Vertical and horizontal spacing. - Segregate base styling into dedicated SCSS files for clearer structure and increased maintainability. - Remove custom styling from affected components, enabling global style reuse for visual uniformity, reduced redundancy, and enhanced semantics. Other supporting changes: - Rename `globals.scss` to `base.scss` for better clarity. - Add `.editorconfig` for `.scss` files to ensure consistent whitespace usage. - Remove `2` file from the project root, that was included in the source code by mistake. - Remove unused font-face imports
This commit is contained in:
@@ -3,7 +3,7 @@ root = true # Top-most EditorConfig file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
|
||||
[*.{js,jsx,ts,tsx,vue,sh}]
|
||||
[*.{js,jsx,ts,tsx,vue,sh,scss}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
@@ -24,3 +24,10 @@ indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{scss}] # SASS guidelines: https://archive.today/2024.02.16-232553/https://sass-guidelin.es/
|
||||
indent_style = space
|
||||
indent_size = 2 # Recommended by SASS guidelines
|
||||
max_line_length = 100 # Recommended by SASS guidelines
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
31
2
31
2
@@ -1,31 +0,0 @@
|
||||
Show error on AV removal on desktop $264, $304
|
||||
|
||||
This solves $264 where users do not get error messages when running
|
||||
script file fails due to antivirus intervention (it being blocking the
|
||||
script file as soon as privacy.sexy generates it to run it). Now if the
|
||||
desktop app users tries to save or run a script file and it afils due to
|
||||
antivirus removal, they'll get a special error message with guiding next
|
||||
steps.
|
||||
|
||||
- Add additional check to able to fail if the file writing fails. This
|
||||
includes trying to reading the written file back as suggested in $304.
|
||||
This successfully detects antivirus (Defender) intervation as read
|
||||
file operation triggers the antivirus scan that deletes the file.
|
||||
- Show directory and file path in error messages as suggested in $304.
|
||||
- Show an error message with more detailed information if an antivirus
|
||||
is detected.
|
||||
|
||||
# Please enter the commit message for your changes. Lines starting
|
||||
# with '#' will be ignored, and an empty message aborts the commit.
|
||||
#
|
||||
# Date: Tue Jan 16 16:23:08 2024 +0100
|
||||
#
|
||||
# On branch master
|
||||
# Your branch is ahead of 'origin/master' by 1 commit.
|
||||
# (use "git push" to publish your local commits)
|
||||
#
|
||||
# Changes to be committed:
|
||||
# modified: ../../application/CodeRunner/CodeRunner.ts
|
||||
# new file: NodeReliableFileWriter.ts
|
||||
# new file: ReliableFileWriter.ts
|
||||
#
|
||||
@@ -6,7 +6,7 @@
|
||||
/* slabo-27px-regular - latin_latin-ext */
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
|
||||
|
||||
font-family: 'Slabo 27px';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
@@ -24,16 +24,6 @@
|
||||
url('#{$base-assets-path}/fonts/yesteryear-v18-latin-regular.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
|
||||
}
|
||||
|
||||
/* roboto-slab-regular - latin */
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Roboto Slab';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('#{$base-assets-path}/fonts/roboto-slab-v34-latin-regular.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
url('#{$base-assets-path}/fonts/roboto-slab-v34-latin-regular.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
|
||||
}
|
||||
|
||||
/* roboto-slab-regular - cyrillic_cyrillic-ext_greek_greek-ext_latin_latin-ext_vietnamese */
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
@@ -62,13 +52,3 @@
|
||||
src: url('#{$base-assets-path}/fonts/source-code-pro-v23-latin-regular.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
url('#{$base-assets-path}/fonts/source-code-pro-v23-latin-regular.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
|
||||
}
|
||||
|
||||
/* roboto-mono-regular - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('#{$base-assets-path}/fonts/roboto-mono-v23-latin-regular.woff2') format('woff2'), /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
url('#{$base-assets-path}/fonts/roboto-mono-v23-latin-regular.ttf') format('truetype'); /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
Defines global styles that applies to globally defined tags by default (body, main, article, div etc.)
|
||||
*/
|
||||
|
||||
@use "@/presentation/assets/styles/colors" as *;
|
||||
@use "@/presentation/assets/styles/mixins" as *;
|
||||
@use "@/presentation/assets/styles/vite-path" as *;
|
||||
@use "@/presentation/assets/styles/typography" as *;
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
@include flat-button($disabled: false);
|
||||
}
|
||||
|
||||
body {
|
||||
background: $color-background;
|
||||
font-family: $font-family-main;
|
||||
font-size: $font-size-absolute-normal;
|
||||
}
|
||||
|
||||
input {
|
||||
font-family: unset; // Reset browser default
|
||||
}
|
||||
|
||||
@@ -118,3 +118,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin set-property-ch-value-with-fallback($property, $value-in-ch) {
|
||||
@supports (width: 1ch) {
|
||||
#{$property}: #{$value-in-ch}ch;
|
||||
}
|
||||
// For browsers that does not support `ch` unit (e.g., Opera Mini):
|
||||
$estimated-width-per-character-in-em: calc(1em / 2); // 1 character is approximately half the font size
|
||||
$calculated-width-in-em: calc(#{$estimated-width-per-character-in-em} * #{$value-in-ch});
|
||||
#{$property}: $calculated-width-in-em;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
@use "@/presentation/assets/styles/colors" as *;
|
||||
@use "@/presentation/assets/styles/mixins" as *;
|
||||
@use "@/presentation/assets/styles/vite-path" as *;
|
||||
@use "@/presentation/assets/styles/typography" as *;
|
||||
@use 'sass:math';
|
||||
|
||||
@mixin code-block() {
|
||||
@@ -23,13 +26,14 @@
|
||||
$color-background,
|
||||
$code-block-padding,
|
||||
) {
|
||||
$font-size-code: $font-size-relative-smaller; // Keep relative size to scale right with different text sizes around.
|
||||
$font-size-code: $font-size-relative-smaller; // Keep relative size to scale right with different text sizes around.
|
||||
$border-radius: 2px; // Subtle rounding still maintaining sharp design.
|
||||
|
||||
@include base-code {
|
||||
font-family: $font-family-monospace;
|
||||
border-radius: $border-radius;
|
||||
font-size: $font-size-code;
|
||||
color: $color-on-primary;
|
||||
}
|
||||
|
||||
@include inline-code {
|
||||
53
src/presentation/assets/styles/base/_index.scss
Normal file
53
src/presentation/assets/styles/base/_index.scss
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Defines global styles that applies to globally defined tags by default (body, main, article, div etc.).
|
||||
Styles Fundamental HTML elements.
|
||||
Contains foundational CSS rules that have a broad impact on the project's styling.
|
||||
CSS Base applies a style foundation for HTML elements that is consistent for baseline browsers
|
||||
*/
|
||||
|
||||
@use "@/presentation/assets/styles/colors" as *;
|
||||
@use "@/presentation/assets/styles/mixins" as *;
|
||||
@use "@/presentation/assets/styles/vite-path" as *;
|
||||
@use "@/presentation/assets/styles/typography" as *;
|
||||
@use "_code-styling" as *;
|
||||
@use "_margin-padding" as *;
|
||||
@use "_link-styling" as *;
|
||||
|
||||
$base-spacing: 1em;
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
background: $color-background;
|
||||
font-family: $font-family-main;
|
||||
font-size: $font-size-absolute-normal;
|
||||
|
||||
@include apply-uniform-spacing($base-spacing: $base-spacing)
|
||||
}
|
||||
|
||||
input {
|
||||
font-family: unset; // Reset browser default
|
||||
}
|
||||
|
||||
blockquote {
|
||||
padding: 0 $base-spacing;
|
||||
border-left: .25em solid $color-primary;
|
||||
}
|
||||
|
||||
@include style-code-elements(
|
||||
$code-block-padding: $base-spacing,
|
||||
$color-background: $color-primary-darker,
|
||||
);
|
||||
|
||||
hr {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
sup {
|
||||
@include reset-sup;
|
||||
|
||||
vertical-align: super;
|
||||
font-size: $font-size-relative-smallest;
|
||||
}
|
||||
42
src/presentation/assets/styles/base/_link-styling.scss
Normal file
42
src/presentation/assets/styles/base/_link-styling.scss
Normal file
@@ -0,0 +1,42 @@
|
||||
@use "@/presentation/assets/styles/mixins" as *;
|
||||
@use "@/presentation/assets/styles/typography" as *;
|
||||
@use 'sass:math';
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
@include flat-button($disabled: false);
|
||||
|
||||
&[href] {
|
||||
word-break: break-word; // Enables long URLs to wrap within the container, preventing horizontal overflow.
|
||||
}
|
||||
&[href^="http"]{
|
||||
&:after {
|
||||
display: inline-block;
|
||||
content: '';
|
||||
|
||||
/*
|
||||
Use mask element instead of content/background-image etc.
|
||||
This way we can apply current font color to it to match the theme
|
||||
*/
|
||||
mask: url(@/presentation/assets/icons/external-link.svg) no-repeat 50% 50%;
|
||||
mask-size: cover;
|
||||
background-color: currentColor;
|
||||
|
||||
/*
|
||||
Use absolute sizing instead of relative. Relative sizing looks bad and inconsistent if there are external elements
|
||||
inside small text (such as inside `<sup>`) and bigger elements like in bigger text. Making them always have same size
|
||||
make the text read and flow better.
|
||||
*/
|
||||
width: $font-size-absolute-x-small;
|
||||
height: $font-size-absolute-x-small;
|
||||
|
||||
vertical-align: text-top;
|
||||
|
||||
@include set-property-ch-value-with-fallback(
|
||||
$property: margin-left,
|
||||
$value-in-ch: 0.25,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
64
src/presentation/assets/styles/base/_margin-padding.scss
Normal file
64
src/presentation/assets/styles/base/_margin-padding.scss
Normal file
@@ -0,0 +1,64 @@
|
||||
@use 'sass:math';
|
||||
|
||||
@mixin no-margin($selectors) {
|
||||
#{$selectors} {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin no-padding($selectors) {
|
||||
#{$selectors} {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin left-padding($selectors, $horizontal-spacing) {
|
||||
#{$selectors} {
|
||||
padding-inline-start: $horizontal-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin bottom-margin($selectors, $vertical-spacing) {
|
||||
#{$selectors} {
|
||||
&:not(:last-child) {
|
||||
margin-bottom: $vertical-spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin apply-uniform-vertical-spacing($base-vertical-spacing) {
|
||||
/* Reset default top/bottom margins added by browser. */
|
||||
@include no-margin('p');
|
||||
@include no-margin('h1, h2, h3, h4, h5, h6');
|
||||
@include no-margin('blockquote');
|
||||
@include no-margin('pre');
|
||||
@include no-margin('hr');
|
||||
@include no-margin('ul, ol');
|
||||
|
||||
/* Add spacing between elements using `margin-bottom` only (bottom-up instead of top-down strategy). */
|
||||
$small-vertical-spacing: math.div($base-vertical-spacing, 2);
|
||||
@include bottom-margin('p', $base-vertical-spacing);
|
||||
@include bottom-margin('li > p', $small-vertical-spacing); // Reduce margin for paragraphs directly within list items to visually group related content.
|
||||
@include bottom-margin('h1, h2, h3, h4, h5, h6', $small-vertical-spacing);
|
||||
@include bottom-margin('ul, ol', $base-vertical-spacing);
|
||||
@include bottom-margin('li', $small-vertical-spacing);
|
||||
@include bottom-margin('table', $base-vertical-spacing);
|
||||
@include bottom-margin('blockquote', $base-vertical-spacing);
|
||||
@include bottom-margin('pre', $base-vertical-spacing);
|
||||
@include bottom-margin('article', $base-vertical-spacing);
|
||||
@include bottom-margin('hr', $base-vertical-spacing);
|
||||
}
|
||||
|
||||
@mixin apply-uniform-horizontal-spacing($base-horizontal-spacing) {
|
||||
/* Reset default left/right paddings added by browser. */
|
||||
@include no-padding('ul, ol');
|
||||
|
||||
/* Add spacing for list items. */
|
||||
$large-horizontal-spacing: $base-horizontal-spacing * 2;
|
||||
@include left-padding('ul, ol', $large-horizontal-spacing);
|
||||
}
|
||||
|
||||
@mixin apply-uniform-spacing($base-spacing) {
|
||||
@include apply-uniform-vertical-spacing($base-spacing);
|
||||
@include apply-uniform-horizontal-spacing($base-spacing);
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
@forward "./typography";
|
||||
@forward "./media";
|
||||
@forward "./colors";
|
||||
@forward "./globals";
|
||||
@forward "./base";
|
||||
@forward "./mixins";
|
||||
|
||||
@forward "./components/card";
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<div class="info-container">
|
||||
<span class="info-container">
|
||||
<TooltipWrapper>
|
||||
<AppIcon icon="circle-info" />
|
||||
<template #tooltip>
|
||||
<slot />
|
||||
</template>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -23,9 +23,23 @@ export default defineComponent({
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
|
||||
@mixin apply-style-when-placed-after-non-text {
|
||||
* + & {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
.info-container {
|
||||
display: inline-block;
|
||||
margin-left: 0.15em; // Do not style icon itself to ensure correct tooltip alignment
|
||||
vertical-align: middle;
|
||||
vertical-align: text-top;
|
||||
|
||||
* + & { // If it's followed by any other element
|
||||
vertical-align: middle;
|
||||
@include set-property-ch-value-with-fallback(
|
||||
$property: margin-left,
|
||||
$value-in-ch: 0.5,
|
||||
)
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,32 +1,37 @@
|
||||
<template>
|
||||
<div class="instructions">
|
||||
<section>
|
||||
<p>
|
||||
You have two alternatives to apply your selection.
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<strong>1. The easy alternative</strong>. Run your script without any manual steps by
|
||||
<a :href="downloadUrl">downloading desktop version</a> of {{ appName }} on the
|
||||
{{ osName }} system you wish to configure, and then click on the Run button. This is
|
||||
recommended for most users.
|
||||
</p>
|
||||
<hr />
|
||||
<p>
|
||||
<strong>2. The hard (manual) alternative</strong>. This requires you to do additional manual
|
||||
steps. If you are unsure how to follow the instructions, tap or hover on information
|
||||
<InfoTooltip>Engage with icons like this for extra wisdom!</InfoTooltip>
|
||||
icons near the steps, or follow the easy alternative described above.
|
||||
</p>
|
||||
<p>
|
||||
<PlatformInstructionSteps :filename="filename" />
|
||||
</p>
|
||||
</div>
|
||||
<article>
|
||||
<h3>1. The Easy Alternative</h3>
|
||||
<p>
|
||||
Run your script without any manual steps by
|
||||
<a :href="downloadUrl">downloading desktop version</a> of {{ appName }} on the
|
||||
{{ osName }} system you wish to configure, and then click on the Run button. This is
|
||||
recommended for most users.
|
||||
</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>2. The Hard (Manual) Alternative</h3>
|
||||
<p>
|
||||
This requires you to do additional manual
|
||||
steps. If you are unsure how to follow the instructions, tap or hover on information
|
||||
<InfoTooltip>Engage with icons like this for extra wisdom!</InfoTooltip>
|
||||
icons near the steps, or follow the easy alternative described above.
|
||||
</p>
|
||||
<p>
|
||||
<PlatformInstructionSteps :filename="filename" />
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { injectKey } from '@/presentation/injectionSymbols';
|
||||
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||
import { getOperatingSystemDisplayName } from '@/presentation/components/Shared/OperatingSystemNames';
|
||||
import InfoTooltip from './InfoTooltip.vue';
|
||||
import PlatformInstructionSteps from './Steps/PlatformInstructionSteps.vue';
|
||||
|
||||
@@ -55,7 +60,7 @@ export default defineComponent({
|
||||
);
|
||||
|
||||
const osName = computed<string>(
|
||||
() => renderOsName(operatingSystem.value),
|
||||
() => getOperatingSystemDisplayName(operatingSystem.value),
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -65,21 +70,7 @@ export default defineComponent({
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
function renderOsName(os: OperatingSystem): string {
|
||||
switch (os) {
|
||||
case OperatingSystem.Windows: return 'Windows';
|
||||
case OperatingSystem.macOS: return 'macOS';
|
||||
case OperatingSystem.Linux: return 'Linux';
|
||||
default: throw new RangeError(`Cannot render os name: ${OperatingSystem[os]}`);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
|
||||
.step {
|
||||
margin: 10px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<span class="code-wrapper">
|
||||
<code class="copyable-command">
|
||||
<span class="dollar">$</span>
|
||||
<code ref="codeElement"><slot /></code>
|
||||
<div class="copy-action-container">
|
||||
<span ref="copyableTextHolder"><slot /></span>
|
||||
<span class="copy-action-container">
|
||||
<TooltipWrapper>
|
||||
<FlatButton icon="copy" @click="copyCode" />
|
||||
<template #tooltip>
|
||||
Copy
|
||||
</template>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</code>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -27,10 +27,10 @@ export default defineComponent({
|
||||
setup() {
|
||||
const { copyText } = injectKey((keys) => keys.useClipboard);
|
||||
|
||||
const codeElementRef = shallowRef<HTMLElement | undefined>();
|
||||
const copyableTextHolderRef = shallowRef<HTMLElement | undefined>();
|
||||
|
||||
async function copyCode() {
|
||||
const element = codeElementRef.value;
|
||||
const element = copyableTextHolderRef.value;
|
||||
if (!element) {
|
||||
throw new Error('Code element could not be found.');
|
||||
}
|
||||
@@ -43,7 +43,7 @@ export default defineComponent({
|
||||
|
||||
return {
|
||||
copyCode,
|
||||
codeElement: codeElementRef,
|
||||
copyableTextHolder: copyableTextHolderRef,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -52,25 +52,16 @@ export default defineComponent({
|
||||
<style scoped lang="scss">
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
|
||||
.code-wrapper {
|
||||
.copyable-command {
|
||||
display: inline-flex;
|
||||
white-space: nowrap;
|
||||
justify-content: space-between;
|
||||
font-family: $font-family-monospace;
|
||||
background-color: $color-primary-darker;
|
||||
color: $color-on-primary;
|
||||
align-items: center;
|
||||
padding: 0.2rem;
|
||||
padding: 0.25em;
|
||||
font-size: $font-size-absolute-small;
|
||||
.dollar {
|
||||
margin-right: 0.5rem;
|
||||
font-size: $font-size-absolute-x-small;
|
||||
user-select: none;
|
||||
}
|
||||
.copy-action-container {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
code {
|
||||
font-size: $font-size-absolute-small;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -13,7 +13,4 @@ export default defineComponent({
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.step {
|
||||
margin: 10px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -46,9 +46,7 @@
|
||||
Navigate to the folder where you downloaded the file e.g.:
|
||||
</p>
|
||||
<p>
|
||||
<CopyableCommand>
|
||||
cd ~/Downloads
|
||||
</CopyableCommand>
|
||||
<CopyableCommand>cd ~/Downloads</CopyableCommand>
|
||||
<InfoTooltip>
|
||||
<p>
|
||||
Press on <code>enter/return</code> key after running the command.
|
||||
@@ -72,9 +70,7 @@
|
||||
Give the file execute permissions:
|
||||
</p>
|
||||
<p>
|
||||
<CopyableCommand>
|
||||
chmod +x {{ filename }}
|
||||
</CopyableCommand>
|
||||
<CopyableCommand>chmod +x {{ filename }}</CopyableCommand>
|
||||
<InfoTooltip>
|
||||
<p>
|
||||
Press on <code>enter/return</code> key after running the command.
|
||||
@@ -101,11 +97,11 @@
|
||||
Execute the file:
|
||||
</p>
|
||||
<p>
|
||||
<CopyableCommand>
|
||||
./{{ filename }}
|
||||
</CopyableCommand>
|
||||
<CopyableCommand>./{{ filename }}</CopyableCommand>
|
||||
<InfoTooltip>
|
||||
If you have desktop environment, instead of running this command you can alternatively:
|
||||
<p>
|
||||
If you have desktop environment, instead of running this command you can alternatively:
|
||||
</p>
|
||||
<ol>
|
||||
<li>Locate the file using your file manager.</li>
|
||||
<li>Right click on the file, select "Run as program".</li>
|
||||
|
||||
@@ -49,9 +49,7 @@
|
||||
Give the file execute permissions:
|
||||
</p>
|
||||
<p>
|
||||
<CopyableCommand>
|
||||
chmod +x {{ filename }}
|
||||
</CopyableCommand>
|
||||
<CopyableCommand>chmod +x {{ filename }}</CopyableCommand>
|
||||
<InfoTooltip>
|
||||
<p>
|
||||
Press on <code>enter/return</code> key after running the command.
|
||||
@@ -67,9 +65,7 @@
|
||||
Execute the file:
|
||||
</p>
|
||||
<p>
|
||||
<CopyableCommand>
|
||||
./{{ filename }}
|
||||
</CopyableCommand>
|
||||
<CopyableCommand>./{{ filename }}</CopyableCommand>
|
||||
<InfoTooltip>
|
||||
Alternatively you can locate the file in <strong>Finder</strong> and double click on it.
|
||||
</InfoTooltip>
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
</p>
|
||||
<p>
|
||||
In <strong>Edge</strong>:
|
||||
<ol>
|
||||
<li>Select <strong>Keep</strong> from the downloads section.</li>
|
||||
<li>Click <strong>Show more</strong> on the next warning.</li>
|
||||
<li>Select <strong>Keep anyway</strong>.</li>
|
||||
</ol>
|
||||
</p>
|
||||
<ol>
|
||||
<li>Select <strong>Keep</strong> from the downloads section.</li>
|
||||
<li>Click <strong>Show more</strong> on the next warning.</li>
|
||||
<li>Select <strong>Keep anyway</strong>.</li>
|
||||
</ol>
|
||||
<p>
|
||||
For <strong>Firefox</strong> and <strong>Chrome</strong>, typically no additional
|
||||
action is needed.
|
||||
@@ -53,25 +53,26 @@
|
||||
</p>
|
||||
<p>
|
||||
To handle false warnings in Microsoft Defender:
|
||||
<ol>
|
||||
<li>
|
||||
Open <strong>Virus & threat protection</strong> from
|
||||
the <strong>Start</strong> menu.
|
||||
</li>
|
||||
<li>
|
||||
Locate the event in <strong>Protection history</strong>
|
||||
that pertains to the script.
|
||||
</li>
|
||||
<li>In the event details, select <strong>Actions</strong> > <strong>Allow</strong>.</li>
|
||||
<li>If the script was deleted, please re-download it.</li>
|
||||
</ol>
|
||||
</p>
|
||||
<ol>
|
||||
<li>
|
||||
Open <strong>Virus & threat protection</strong> from
|
||||
the <strong>Start</strong> menu.
|
||||
</li>
|
||||
<li>
|
||||
Locate the event in <strong>Protection history</strong>
|
||||
that pertains to the script.
|
||||
</li>
|
||||
<li>In the event details, select <strong>Actions</strong> > <strong>Allow</strong>.</li>
|
||||
<li>If the script was deleted, please re-download it.</li>
|
||||
</ol>
|
||||
<blockquote>
|
||||
<strong>Caution:</strong> For your security, remember to:
|
||||
<strong>Caution:</strong>
|
||||
<p>For your security, remember to</p>
|
||||
<ul>
|
||||
<li>Only allow scripts from trusted sources.</li>
|
||||
<li>Avoid broad exclusions in your antivirus settings.</li>
|
||||
<li>Keep real-time protection enabled whenever possible.</li>
|
||||
<li>only allow scripts from trusted sources,</li>
|
||||
<li>avoid broad exclusions in your antivirus settings,</li>
|
||||
<li>and keep real-time protection enabled whenever possible.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
</InfoTooltip>
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
<template>
|
||||
<div v-if="isOpen" class="dev-toolkit-container">
|
||||
<div class="dev-toolkit">
|
||||
<div class="toolkit-header">
|
||||
<div class="title">
|
||||
<h3 class="toolkit-header">
|
||||
<span class="title">
|
||||
Tools
|
||||
</div>
|
||||
</span>
|
||||
<FlatButton icon="xmark" class="close-button" @click="close" />
|
||||
</div>
|
||||
</h3>
|
||||
<hr />
|
||||
<div class="action-buttons">
|
||||
<button
|
||||
<ul class="action-buttons">
|
||||
<li
|
||||
v-for="action in devActions"
|
||||
:key="action.name"
|
||||
type="button"
|
||||
class="action-button"
|
||||
@click="action.handler"
|
||||
>
|
||||
{{ action.name }}
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="action-button"
|
||||
@click="action.handler"
|
||||
>
|
||||
{{ action.name }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -91,10 +94,6 @@ interface DevAction {
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
|
||||
hr {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.toolkit-header {
|
||||
display:flex;
|
||||
flex-direction: row;
|
||||
@@ -108,7 +107,6 @@ interface DevAction {
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -116,8 +114,11 @@ interface DevAction {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
@include reset-ul;
|
||||
|
||||
.action-button {
|
||||
@include reset-button;
|
||||
|
||||
button {
|
||||
display: block;
|
||||
padding: 5px 10px;
|
||||
background-color: $color-primary;
|
||||
|
||||
@@ -1,53 +1,51 @@
|
||||
<template>
|
||||
<div>
|
||||
<section>
|
||||
<p class="privacy-rating">
|
||||
Privacy: <CircleRating :rating="privacyRating" />
|
||||
</p>
|
||||
<hr />
|
||||
<div class="sections">
|
||||
<section>
|
||||
{{ description }}
|
||||
</section>
|
||||
<section class="recommendation">
|
||||
<AppIcon icon="lightbulb" class="icon" />
|
||||
<span class="text">{{ recommendation }}</span>
|
||||
</section>
|
||||
<section
|
||||
v-if="includes?.length > 0"
|
||||
class="includes"
|
||||
>
|
||||
<AppIcon icon="square-check" class="icon" />
|
||||
<span class="text">
|
||||
Includes:
|
||||
<ul>
|
||||
<li
|
||||
v-for="inclusionItem in includes"
|
||||
:key="inclusionItem"
|
||||
>
|
||||
{{ inclusionItem }}
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</section>
|
||||
<section
|
||||
v-if="considerations?.length > 0"
|
||||
class="considerations"
|
||||
>
|
||||
<AppIcon icon="triangle-exclamation" class="icon" />
|
||||
<span class="text">
|
||||
Considerations:
|
||||
<ul>
|
||||
<li
|
||||
v-for="considerationItem in considerations"
|
||||
:key="considerationItem"
|
||||
>
|
||||
{{ considerationItem }}
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
{{ description }}
|
||||
</p>
|
||||
<p class="recommendation">
|
||||
<AppIcon icon="lightbulb" class="icon" />
|
||||
<span>{{ recommendation }}</span>
|
||||
</p>
|
||||
<p
|
||||
v-if="includes?.length > 0"
|
||||
class="includes"
|
||||
>
|
||||
<AppIcon icon="square-check" class="icon" />
|
||||
<span>
|
||||
Includes:
|
||||
<ul>
|
||||
<li
|
||||
v-for="inclusionItem in includes"
|
||||
:key="inclusionItem"
|
||||
>
|
||||
{{ inclusionItem }}
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</p>
|
||||
<p
|
||||
v-if="considerations?.length > 0"
|
||||
class="considerations"
|
||||
>
|
||||
<AppIcon icon="triangle-exclamation" class="icon" />
|
||||
<span>
|
||||
<strong>Considerations:</strong>
|
||||
<ul>
|
||||
<li
|
||||
v-for="considerationItem in considerations"
|
||||
:key="considerationItem"
|
||||
>
|
||||
{{ considerationItem }}
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</p>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -88,48 +86,32 @@ export default defineComponent({
|
||||
<style scoped lang="scss">
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
|
||||
@mixin horizontal-stack {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
@mixin apply-icon-color($color) {
|
||||
.icon {
|
||||
color: $color;
|
||||
}
|
||||
}
|
||||
|
||||
.privacy-rating {
|
||||
margin: 0.5em;
|
||||
text-align: center;
|
||||
}
|
||||
hr {
|
||||
margin: 1em 0;
|
||||
opacity: 0.6;
|
||||
}
|
||||
ul {
|
||||
@include reset-ul;
|
||||
padding-left: 0em;
|
||||
margin-top: 0.25em;
|
||||
list-style: disc;
|
||||
}
|
||||
.sections {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75em;
|
||||
margin-bottom: 0.75em;
|
||||
.includes {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
.icon {
|
||||
color: $color-success;
|
||||
}
|
||||
}
|
||||
|
||||
.considerations {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
font-weight: bold;
|
||||
.icon {
|
||||
color: $color-danger;
|
||||
}
|
||||
}
|
||||
.recommendation {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
.icon {
|
||||
color: $color-caution;
|
||||
}
|
||||
}
|
||||
.includes {
|
||||
@include horizontal-stack;
|
||||
@include apply-icon-color($color-success);
|
||||
}
|
||||
.considerations {
|
||||
@include horizontal-stack;
|
||||
@include apply-icon-color($color-danger);
|
||||
}
|
||||
.recommendation {
|
||||
@include horizontal-stack;
|
||||
@include apply-icon-color($color-caution);
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="sections">
|
||||
<section class="description">
|
||||
<AppIcon :icon="icon" class="icon" />
|
||||
<span class="text">{{ description }}</span>
|
||||
</section>
|
||||
<section
|
||||
v-if="considerations.length > 0"
|
||||
class="considerations"
|
||||
>
|
||||
<AppIcon icon="triangle-exclamation" class="icon" />
|
||||
<span class="text">
|
||||
Considerations:
|
||||
<ul>
|
||||
<li
|
||||
v-for="considerationItem in considerations"
|
||||
:key="considerationItem"
|
||||
>
|
||||
{{ considerationItem }}
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<section>
|
||||
<p class="description">
|
||||
<AppIcon :icon="icon" class="icon" />
|
||||
<span>{{ description }}</span>
|
||||
</p>
|
||||
<p
|
||||
v-if="considerations.length > 0"
|
||||
class="considerations"
|
||||
>
|
||||
<AppIcon icon="triangle-exclamation" class="icon" />
|
||||
<span>
|
||||
Considerations:
|
||||
<ul>
|
||||
<li
|
||||
v-for="considerationItem in considerations"
|
||||
:key="considerationItem"
|
||||
>
|
||||
{{ considerationItem }}
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</p>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -55,33 +53,24 @@ export default defineComponent({
|
||||
<style scoped lang="scss">
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
|
||||
ul {
|
||||
@include reset-ul;
|
||||
padding-left: 0em;
|
||||
margin-top: 0.25em;
|
||||
list-style: disc;
|
||||
li {
|
||||
line-height: 1.2em;
|
||||
@mixin horizontal-stack {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
@mixin apply-icon-color($color) {
|
||||
.icon {
|
||||
color: $color;
|
||||
}
|
||||
}
|
||||
.sections {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75em;
|
||||
.considerations {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
.icon {
|
||||
color: $color-caution;
|
||||
}
|
||||
}
|
||||
.description {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
.icon {
|
||||
color: $color-success;
|
||||
}
|
||||
}
|
||||
|
||||
.considerations {
|
||||
@include horizontal-stack;
|
||||
@include apply-icon-color($color-caution);
|
||||
}
|
||||
.description {
|
||||
@include horizontal-stack;
|
||||
@include apply-icon-color($color-success);
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<template #tooltip>
|
||||
<RevertStatusDocumentation
|
||||
icon="rotate-left"
|
||||
description="Revert selected scripts back to their default settings where possible, balancing system functionality with privacy."
|
||||
description="Reverts selected scripts back to their default settings where possible, balancing system functionality with privacy."
|
||||
:considerations="createConsiderationsConditionally({
|
||||
warnAlways: ['Reverting changes may reduce the level of privacy protection.'],
|
||||
warnIrreversibleScripts: (irreversibleCount) =>
|
||||
|
||||
@@ -34,13 +34,18 @@ function convertMarkdownToHtml(markdownText: string): string {
|
||||
|
||||
<style lang="scss"> /* Not scoped due to element styling such as "a". */
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
@import './markdown-styles.scss';
|
||||
|
||||
$text-color: $color-on-primary;
|
||||
|
||||
.markdown-text {
|
||||
color: $text-color;
|
||||
font-size: $font-size-absolute-normal;
|
||||
@include markdown-text-styles;
|
||||
ul {
|
||||
/*
|
||||
Set list style explicitly, because otherwise it changes based on parent <ul>s.
|
||||
We reset the style from here.
|
||||
*/
|
||||
list-style: square;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
@use "_code-styling" as *;
|
||||
@use 'sass:math';
|
||||
|
||||
@mixin no-margin($selectors) {
|
||||
#{$selectors} {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin no-padding($selectors) {
|
||||
#{$selectors} {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin left-padding($selectors, $horizontal-spacing) {
|
||||
#{$selectors} {
|
||||
padding-inline-start: $horizontal-spacing;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin bottom-margin($selectors, $vertical-spacing) {
|
||||
#{$selectors} {
|
||||
&:not(:last-child) {
|
||||
margin-bottom: $vertical-spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin apply-uniform-vertical-spacing($base-vertical-spacing) {
|
||||
/* Reset default top/bottom margins added by browser. */
|
||||
@include no-margin('p');
|
||||
@include no-margin('h1, h2, h3, h4, h5, h6');
|
||||
@include no-margin('blockquote');
|
||||
@include no-margin('pre');
|
||||
|
||||
/* Add spacing between elements using `margin-bottom` only (bottom-up instead of top-down strategy). */
|
||||
$small-vertical-spacing: math.div($base-vertical-spacing, 2);
|
||||
@include bottom-margin('p', $base-vertical-spacing);
|
||||
@include bottom-margin('h1, h2, h3, h4, h5, h6', $base-vertical-spacing);
|
||||
@include bottom-margin('ul, ol', $base-vertical-spacing);
|
||||
@include bottom-margin('li', $small-vertical-spacing);
|
||||
@include bottom-margin('table', $base-vertical-spacing);
|
||||
@include bottom-margin('blockquote', $base-vertical-spacing);
|
||||
@include bottom-margin('pre', $base-vertical-spacing);
|
||||
}
|
||||
|
||||
@mixin apply-uniform-horizontal-spacing($base-horizontal-spacing) {
|
||||
/* Reset default left/right paddings added by browser. */
|
||||
@include no-padding('ul, ol');
|
||||
|
||||
/* Add spacing for list items. */
|
||||
$large-horizontal-spacing: $base-horizontal-spacing * 2;
|
||||
@include left-padding('ul, ol', $large-horizontal-spacing);
|
||||
}
|
||||
|
||||
@mixin markdown-text-styles {
|
||||
$base-spacing: 1em;
|
||||
|
||||
a {
|
||||
&[href] {
|
||||
word-break: break-word; // Enables long URLs to wrap within the container, preventing horizontal overflow.
|
||||
}
|
||||
&[href^="http"]{
|
||||
&:after {
|
||||
/*
|
||||
Use mask element instead of content/background-image etc.
|
||||
This way we can apply current font color to it to match the theme
|
||||
*/
|
||||
mask: url(@/presentation/assets/icons/external-link.svg) no-repeat 50% 50%;
|
||||
mask-size: cover;
|
||||
content: '';
|
||||
|
||||
display: inline-block;
|
||||
|
||||
/*
|
||||
Use absolute sizing instead of relative. Relative sizing looks bad and inconsistent if there are external elements
|
||||
inside small text (such as inside `<sup>`) and bigger elements like in bigger text. Making them always have same size
|
||||
make the text read and flow better.
|
||||
*/
|
||||
width: $font-size-absolute-x-small;
|
||||
height: $font-size-absolute-x-small;
|
||||
|
||||
vertical-align: text-top;
|
||||
|
||||
background-color: $text-color;
|
||||
margin-left: math.div(1em, 4);
|
||||
}
|
||||
/*
|
||||
Match color of global hover behavior. We need to do it manually because global hover sets
|
||||
`color` property but here we need to modify `background-color` property because color only
|
||||
works if SVG is embedded as HTML element (as `<svg/>`) not as `url(..)` as we do. Then the
|
||||
only option is to use `mask` and `background-color` properties.
|
||||
*/
|
||||
@include hover-or-touch {
|
||||
&::after{
|
||||
background-color: $color-highlight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include apply-uniform-vertical-spacing($base-spacing);
|
||||
@include apply-uniform-horizontal-spacing($base-spacing);
|
||||
|
||||
ul {
|
||||
/*
|
||||
Set list style explicitly, because otherwise it changes based on parent <ul>s in tree view.
|
||||
We reset the style from here.
|
||||
*/
|
||||
list-style: square;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
padding: 0 $base-spacing;
|
||||
border-left: .25em solid $color-primary;
|
||||
}
|
||||
|
||||
@include style-code-elements(
|
||||
$code-block-padding: $base-spacing,
|
||||
$color-background: $color-primary-darker,
|
||||
);
|
||||
|
||||
sup {
|
||||
@include reset-sup;
|
||||
|
||||
vertical-align: super;
|
||||
font-size: $font-size-relative-smallest;
|
||||
}
|
||||
}
|
||||
@@ -158,7 +158,7 @@ $gap-between-circle-and-text : 0.25em;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-weight: bold; // TODO: Babaya sor
|
||||
font-weight: bold;
|
||||
transition: all 0.3s ease-out, color 0s;
|
||||
&.label-off {
|
||||
@include locateNearCircle('left');
|
||||
|
||||
@@ -129,7 +129,6 @@ function getCounterpartBoxOffsetProperty(placement: Placement): keyof CSSPropert
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use 'sass:math';
|
||||
@use "@/presentation/assets/styles/main" as *;
|
||||
|
||||
$color-tooltip-background: $color-primary-darkest;
|
||||
@@ -210,21 +209,11 @@ $color-tooltip-background: $color-primary-darkest;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin set-max-width($total-characters) {
|
||||
@supports (width: 1ch) {
|
||||
max-width: #{$total-characters}ch;
|
||||
}
|
||||
// For browsers that does not support `ch` unit (e.g., Opera Mini):
|
||||
$estimated-character-size: calc(1em / 2); // 1 character is approximately half the font size
|
||||
$estimated-width: calc(#{$estimated-character-size} * #{$total-characters});
|
||||
max-width: $estimated-width;
|
||||
}
|
||||
|
||||
.tooltip__content {
|
||||
background: $color-tooltip-background;
|
||||
color: $color-on-primary;
|
||||
border-radius: 16px;
|
||||
padding: 5px 10px 4px;
|
||||
padding: 12px 10px;
|
||||
font-size: $font-size-absolute-normal;
|
||||
|
||||
/*
|
||||
@@ -237,13 +226,14 @@ $color-tooltip-background: $color-primary-darkest;
|
||||
margin-right: 2px;
|
||||
|
||||
// Setting max-width increases readability and consistency reducing overlap and clutter.
|
||||
@include set-max-width(
|
||||
@include set-property-ch-value-with-fallback(
|
||||
$property: max-width,
|
||||
/*
|
||||
Research in typography suggests that an optimal line length for text readability is between 50-75 characters per line.
|
||||
Tooltips should be brief, so aiming for the for the lower end of this range (around 50 characters).
|
||||
*/
|
||||
$total-characters: 50
|
||||
);
|
||||
$value-in-ch: 50,
|
||||
)
|
||||
}
|
||||
|
||||
.tooltip__arrow {
|
||||
|
||||
@@ -1,56 +1,46 @@
|
||||
<template>
|
||||
<div class="privacy-policy">
|
||||
<div v-if="!isRunningAsDesktopApplication" class="line">
|
||||
<div class="line__emoji">
|
||||
🚫🍪
|
||||
</div>
|
||||
<div>No cookies!</div>
|
||||
</div>
|
||||
<div v-if="isRunningAsDesktopApplication" class="line">
|
||||
<div class="line__emoji">
|
||||
🚫🌐
|
||||
</div>
|
||||
<div>
|
||||
Everything is offline, except single request GitHub
|
||||
to check for updates on application start.
|
||||
</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="line__emoji">
|
||||
🚫👀
|
||||
</div>
|
||||
<div>No user behavior / IP address collection!</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="line__emoji">
|
||||
🤖
|
||||
</div>
|
||||
<div>
|
||||
All transparent: Deployed automatically from the master branch
|
||||
of the <a :href="repositoryUrl" target="_blank" rel="noopener noreferrer">source code</a> with no changes.
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!isRunningAsDesktopApplication" class="line">
|
||||
<div class="line__emoji">
|
||||
📈
|
||||
</div>
|
||||
<div>
|
||||
Basic <a href="https://aws.amazon.com/cloudfront/reporting/" target="_blank" rel="noopener noreferrer">CDN statistics</a>
|
||||
are collected by AWS but they cannot be traced to you or your behavior.
|
||||
You can download the offline version if you don't want any CDN data collection.
|
||||
</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="line__emoji">
|
||||
🎉
|
||||
</div>
|
||||
<div>
|
||||
As almost no data is collected, the application gets better
|
||||
only with your active feedback.
|
||||
Feel free to <a :href="feedbackUrl" target="_blank" rel="noopener noreferrer">create an issue</a> 😊
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section class="privacy-policy">
|
||||
<ul>
|
||||
<li v-if="!isRunningAsDesktopApplication">
|
||||
<span class="emoji">🚫🍪</span>
|
||||
<span>No cookies!</span>
|
||||
</li>
|
||||
<li v-if="isRunningAsDesktopApplication">
|
||||
<span class="emoji">🚫🌐</span>
|
||||
<span>
|
||||
Everything is offline, except single request GitHub
|
||||
to check for updates on application start.
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="emoji">🚫👀</span>
|
||||
<span>No user behavior / IP address collection!</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="emoji">🤖</span>
|
||||
<span>
|
||||
All transparent: Deployed automatically from the master branch
|
||||
of the <a :href="repositoryUrl" target="_blank" rel="noopener noreferrer">source code</a> with no changes.
|
||||
</span>
|
||||
</li>
|
||||
<li v-if="!isRunningAsDesktopApplication">
|
||||
<span class="emoji">📈</span>
|
||||
<span>
|
||||
Basic <a href="https://aws.amazon.com/cloudfront/reporting/" target="_blank" rel="noopener noreferrer">CDN statistics</a>
|
||||
are collected by AWS but they cannot be traced to you or your behavior.
|
||||
You can download the offline version if you don't want any CDN data collection.
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="emoji">🎉</span>
|
||||
<span>
|
||||
As almost no data is collected, the application gets better
|
||||
only with your active feedback.
|
||||
Feel free to <a :href="feedbackUrl" target="_blank" rel="noopener noreferrer">create an issue</a> 😊
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -81,14 +71,13 @@ export default defineComponent({
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.line {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
ul {
|
||||
@include reset-ul;
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top:0.2rem;
|
||||
}
|
||||
}
|
||||
.emoji {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import CodeInstruction from '@/presentation/components/Code/CodeButtons/Save/RunInstructions/Steps/CopyableCommand.vue';
|
||||
import { VueWrapper, shallowMount } from '@vue/test-utils';
|
||||
import { ComponentPublicInstance } from 'vue';
|
||||
import CopyableCommand from '@/presentation/components/Code/CodeButtons/Save/RunInstructions/Steps/CopyableCommand.vue';
|
||||
import { expectThrowsAsync } from '@tests/shared/Assertions/ExpectThrowsAsync';
|
||||
import { InjectionKeys } from '@/presentation/injectionSymbols';
|
||||
import { Clipboard } from '@/presentation/components/Shared/Hooks/Clipboard/Clipboard';
|
||||
@@ -9,10 +10,10 @@ import { ClipboardStub } from '@tests/unit/shared/Stubs/ClipboardStub';
|
||||
import { expectExists } from '@tests/shared/Assertions/ExpectExists';
|
||||
import FlatButton from '@/presentation/components/Shared/FlatButton.vue';
|
||||
|
||||
const DOM_SELECTOR_CODE_SLOT = 'code';
|
||||
const DOM_SELECTOR_CODE_SLOT = 'code > span:nth-of-type(2)';
|
||||
const COMPONENT_TOOLTIP_WRAPPER_NAME = 'TooltipWrapper';
|
||||
|
||||
describe('CodeInstruction.vue', () => {
|
||||
describe('CopyableCommand.vue', () => {
|
||||
it('renders a slot content inside a <code> element', () => {
|
||||
// arrange
|
||||
const expectedSlotContent = 'Example Code';
|
||||
@@ -33,7 +34,8 @@ describe('CodeInstruction.vue', () => {
|
||||
const wrapper = mountComponent({
|
||||
clipboard: clipboardStub,
|
||||
});
|
||||
wrapper.vm.codeElement = { textContent: expectedCode } as HTMLElement;
|
||||
const referencedElement = createElementWithTextContent(expectedCode);
|
||||
setSlotContainerElement(wrapper, referencedElement);
|
||||
// act
|
||||
const copyButton = wrapper.findComponent(FlatButton);
|
||||
await copyButton.trigger('click');
|
||||
@@ -45,21 +47,23 @@ describe('CodeInstruction.vue', () => {
|
||||
const [actualCode] = call.args;
|
||||
expect(actualCode).to.equal(expectedCode);
|
||||
});
|
||||
it('throws an error when codeElement is not found during copy', async () => {
|
||||
it('throws an error when referenced element is undefined during copy', async () => {
|
||||
// arrange
|
||||
const expectedError = 'Code element could not be found.';
|
||||
const wrapper = mountComponent();
|
||||
wrapper.vm.codeElement = undefined;
|
||||
const referencedElement = undefined;
|
||||
setSlotContainerElement(wrapper, referencedElement);
|
||||
// act
|
||||
const act = () => wrapper.vm.copyCode();
|
||||
// assert
|
||||
await expectThrowsAsync(act, expectedError);
|
||||
});
|
||||
it('throws an error when codeElement has no textContent during copy', async () => {
|
||||
it('throws an error when reference element has no textContent during copy', async () => {
|
||||
// arrange
|
||||
const expectedError = 'Code element does not contain any text.';
|
||||
const wrapper = mountComponent();
|
||||
wrapper.vm.codeElement = { textContent: '' } as HTMLElement;
|
||||
const referencedElement = createElementWithTextContent('');
|
||||
setSlotContainerElement(wrapper, referencedElement);
|
||||
// act
|
||||
const act = () => wrapper.vm.copyCode();
|
||||
// assert
|
||||
@@ -72,7 +76,7 @@ function mountComponent(options?: {
|
||||
readonly clipboard?: Clipboard,
|
||||
readonly slotContent?: string,
|
||||
}) {
|
||||
return shallowMount(CodeInstruction, {
|
||||
return shallowMount(CopyableCommand, {
|
||||
global: {
|
||||
provide: {
|
||||
[InjectionKeys.useClipboard.key]:
|
||||
@@ -95,3 +99,16 @@ function mountComponent(options?: {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function setSlotContainerElement(
|
||||
wrapper: VueWrapper<unknown>,
|
||||
element?: HTMLElement,
|
||||
) {
|
||||
(wrapper.vm as ComponentPublicInstance<typeof CopyableCommand>).copyableTextHolder = element;
|
||||
}
|
||||
|
||||
function createElementWithTextContent(textContent: string): HTMLElement {
|
||||
const element = document.createElement('span');
|
||||
element.textContent = textContent;
|
||||
return element;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user