mirror of
https://github.com/gapmiss/iconoir-icons.git
synced 2026-07-22 08:00:25 +00:00
feat: Modernize plugin, update Iconoir to v7.11.0
- Update ESLint to flat config - Add GitHub release workflow - Fix CSS conflicts and suggester icons - Update release scripts - Add package-lock.json Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
d4e8b56398
commit
203986a926
17 changed files with 7104 additions and 2342 deletions
|
|
@ -1,3 +0,0 @@
|
|||
node_modules/
|
||||
|
||||
main.js
|
||||
23
.eslintrc
23
.eslintrc
|
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"env": { "node": true },
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/no-empty-function": "off"
|
||||
}
|
||||
}
|
||||
49
.github/workflows/release.yml
vendored
Normal file
49
.github/workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*.*.*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Attest main.js
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-path: main.js
|
||||
|
||||
- name: Attest styles.css
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-path: styles.css
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
main.js
|
||||
manifest.json
|
||||
styles.css
|
||||
generate_release_notes: true
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -10,8 +10,5 @@ node_modules/
|
|||
|
||||
.DS_Store
|
||||
|
||||
package-lock.json
|
||||
|
||||
archive
|
||||
|
||||
#main.js
|
||||
main.js
|
||||
.claude
|
||||
777
dist/main.js
vendored
777
dist/main.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -1,6 +1,6 @@
|
|||
import esbuild from "esbuild";
|
||||
import process from "process";
|
||||
import builtins from 'builtin-modules'
|
||||
import { builtinModules } from "module";
|
||||
|
||||
const banner =
|
||||
`/*
|
||||
|
|
@ -31,12 +31,12 @@ esbuild.build({
|
|||
'@lezer/common',
|
||||
'@lezer/highlight',
|
||||
'@lezer/lr',
|
||||
...builtins],
|
||||
...builtinModules],
|
||||
format: 'cjs',
|
||||
watch: !prod,
|
||||
target: 'es2018',
|
||||
logLevel: "info",
|
||||
sourcemap: prod ? false : false,
|
||||
treeShaking: true,
|
||||
outfile: './dist/main.js',
|
||||
outfile: 'main.js',
|
||||
}).catch(() => process.exit(1));
|
||||
|
|
|
|||
30
eslint.config.mjs
Normal file
30
eslint.config.mjs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import tsParser from "@typescript-eslint/parser";
|
||||
import tseslint from "typescript-eslint";
|
||||
import obsidianmd from "eslint-plugin-obsidianmd";
|
||||
|
||||
export default [
|
||||
{ ignores: ["node_modules/**", "main.js", "*.mjs", "scripts/**", "dist/**", "package.json", "package-lock.json", "versions.json", "tsconfig.json"] },
|
||||
...tseslint.configs.recommendedTypeChecked.map(config => ({
|
||||
...config,
|
||||
files: ["src/**/*.ts"],
|
||||
})),
|
||||
...obsidianmd.configs.recommended,
|
||||
{
|
||||
files: ["src/**/*.ts"],
|
||||
languageOptions: {
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
project: "./tsconfig.json",
|
||||
sourceType: "module",
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
"obsidianmd/prefer-active-doc": "error",
|
||||
"no-console": ["error", { allow: ["warn", "error", "debug"] }],
|
||||
"@typescript-eslint/no-unused-vars": ["error", {
|
||||
argsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_",
|
||||
}],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
@ -5,6 +5,6 @@
|
|||
"minAppVersion": "0.15.0",
|
||||
"description": "Create & display customized SVG Iconoir icons.",
|
||||
"author": "@gapmiss",
|
||||
"authorUrl": "https://gihub.com/gapmiss",
|
||||
"authorUrl": "https://github.com/gapmiss",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
|
|
|
|||
5041
package-lock.json
generated
Normal file
5041
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
20
package.json
20
package.json
|
|
@ -6,22 +6,26 @@
|
|||
"scripts": {
|
||||
"dev": "node esbuild.config.mjs",
|
||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
||||
"version": "node version-bump.mjs && git add manifest.json versions.json"
|
||||
"version": "node version-bump.mjs && git add manifest.json versions.json",
|
||||
"update-icons": "node scripts/update-icons.mjs",
|
||||
"lint": "eslint src/",
|
||||
"release": "node release.mjs",
|
||||
"release:minor": "node release.mjs minor",
|
||||
"release:major": "node release.mjs major"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "https://github.com/gapmiss",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "5.29.0",
|
||||
"@typescript-eslint/parser": "5.29.0",
|
||||
"builtin-modules": "3.3.0",
|
||||
"@typescript-eslint/parser": "^8.59.4",
|
||||
"esbuild": "0.14.47",
|
||||
"eslint": "^9.39.4",
|
||||
"eslint-plugin-obsidianmd": "^0.3.0",
|
||||
"iconoir": "^7.11.0",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"lit": "^2.6.1"
|
||||
"typescript": "5.4.5",
|
||||
"typescript-eslint": "^8.59.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
332
release.mjs
Normal file
332
release.mjs
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
import { readFileSync, writeFileSync } from 'fs';
|
||||
import { execSync } from 'child_process';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Version Update and Deployment Automation Script
|
||||
*
|
||||
* 1. Update version in package.json
|
||||
* 2. Synchronize version in manifest.json, versions.json
|
||||
* 3. Run build
|
||||
* 4. Create Git commit
|
||||
* 5. Create Git tag
|
||||
* 6. Push changes to GitHub (REQUIRES Github CLI: https://cli.github.com)
|
||||
*/
|
||||
|
||||
// Version type definitions
|
||||
const VERSION_TYPES = {
|
||||
PATCH: 'patch',
|
||||
MINOR: 'minor',
|
||||
MAJOR: 'major'
|
||||
};
|
||||
|
||||
// Default settings
|
||||
const DEFAULT_VERSION_TYPE = VERSION_TYPES.PATCH;
|
||||
const RELEASE_FILES = ['main.js', 'manifest.json', 'styles.css'];
|
||||
const MIN_APP_VERSION = "0.15.0"
|
||||
|
||||
// Store original versions for rollback if needed
|
||||
let originalPackageVersion = '';
|
||||
let originalManifestVersion = '';
|
||||
|
||||
/**
|
||||
* Updates version value from the version string.
|
||||
* @param {string} version - Current version (e.g., '0.2.2')
|
||||
* @param {string} type - Update type ('patch', 'minor', 'major')
|
||||
* @returns {string} Updated version
|
||||
*/
|
||||
const updateVersion = (version, type = DEFAULT_VERSION_TYPE) => {
|
||||
const [major, minor, patch] = version.split('.').map(Number);
|
||||
|
||||
switch (type) {
|
||||
case VERSION_TYPES.MAJOR:
|
||||
return `${major + 1}.0.0`;
|
||||
case VERSION_TYPES.MINOR:
|
||||
return `${major}.${minor + 1}.0`;
|
||||
case VERSION_TYPES.PATCH:
|
||||
default:
|
||||
return `${major}.${minor}.${patch + 1}`;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets version information before any changes are made.
|
||||
* @returns {string} Previous version
|
||||
*/
|
||||
const getPreviousVersion = () => {
|
||||
const manifestPath = path.resolve(process.cwd(), 'manifest.json');
|
||||
const manifestData = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
||||
return manifestData.version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates version information in package.json file.
|
||||
* @param {string} versionType - Version type to update
|
||||
* @returns {string} New version
|
||||
*/
|
||||
const updatePackageVersion = (versionType) => {
|
||||
const packagePath = path.resolve(process.cwd(), 'package.json');
|
||||
const packageData = JSON.parse(readFileSync(packagePath, 'utf8'));
|
||||
|
||||
const currentVersion = packageData.version;
|
||||
originalPackageVersion = currentVersion; // Store original version for possible rollback
|
||||
const newVersion = updateVersion(currentVersion, versionType);
|
||||
|
||||
packageData.version = newVersion;
|
||||
writeFileSync(packagePath, JSON.stringify(packageData, null, '\t') + '\n');
|
||||
|
||||
console.log(`📦 Updated package.json version: ${currentVersion} → ${newVersion}`);
|
||||
return newVersion;
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates version information in manifest.json file.
|
||||
* @param {string} newVersion - Version to update
|
||||
*/
|
||||
const updateManifestVersion = (newVersion) => {
|
||||
const manifestPath = path.resolve(process.cwd(), 'manifest.json');
|
||||
const manifestData = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
||||
|
||||
const currentVersion = manifestData.version;
|
||||
originalManifestVersion = currentVersion; // Store original version for possible rollback
|
||||
manifestData.version = newVersion;
|
||||
|
||||
writeFileSync(manifestPath, JSON.stringify(manifestData, null, '\t') + '\n');
|
||||
console.log(`📋 Updated manifest.json version: ${currentVersion} → ${newVersion}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates version information in versions.json file.
|
||||
* @param {string} previousVersion - Previous version
|
||||
* @param {string} newVersion - Version to update
|
||||
*/
|
||||
const updateVersionsVersion = (previousVersion, newVersion, minAppVersion) => {
|
||||
const versionsPath = path.resolve(process.cwd(), 'versions.json');
|
||||
const versionsData = JSON.parse(readFileSync(versionsPath, 'utf8'));
|
||||
|
||||
const manifestPath = path.resolve(process.cwd(), 'manifest.json');
|
||||
const manifestData = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
||||
|
||||
const currentVersion = manifestData.version;
|
||||
versionsData[newVersion] = minAppVersion;
|
||||
|
||||
writeFileSync(versionsPath, JSON.stringify(versionsData, null, '\t') + '\n');
|
||||
console.log(`📋 Updated versions.json version: ${previousVersion} → ${newVersion}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Run project build
|
||||
*/
|
||||
const buildProject = () => {
|
||||
try {
|
||||
console.log('🔨 Starting project build...');
|
||||
execSync('npm run build', { stdio: 'inherit' });
|
||||
console.log('✅ Build completed');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('❌ Build failed:', error.message);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Rollback version changes if the release process fails
|
||||
*/
|
||||
const rollbackVersions = () => {
|
||||
if (originalPackageVersion) {
|
||||
try {
|
||||
const packagePath = path.resolve(process.cwd(), 'package.json');
|
||||
const packageData = JSON.parse(readFileSync(packagePath, 'utf8'));
|
||||
const currentVersion = packageData.version;
|
||||
|
||||
packageData.version = originalPackageVersion;
|
||||
writeFileSync(packagePath, JSON.stringify(packageData, null, '\t') + '\n');
|
||||
console.log(`♻️ Rolled back package.json version: ${currentVersion} → ${originalPackageVersion}`);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to rollback package.json version:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
if (originalManifestVersion) {
|
||||
try {
|
||||
const manifestPath = path.resolve(process.cwd(), 'manifest.json');
|
||||
const manifestData = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
||||
const currentVersion = manifestData.version;
|
||||
|
||||
const versionsPath = path.resolve(process.cwd(), 'versions.json');
|
||||
const versionsData = JSON.parse(readFileSync(versionsPath, 'utf8'));
|
||||
|
||||
// remove last version from JSON
|
||||
let keys = Object.keys(versionsData)
|
||||
delete versionsData[keys[keys.length-1]]
|
||||
|
||||
writeFileSync(versionsPath, JSON.stringify(versionsData, null, '\t') + '\n');
|
||||
console.log(`♻️ Rolled back versions.json version: ${currentVersion} → ${originalManifestVersion}`);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to rollback versions.json version:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
if (originalManifestVersion) {
|
||||
try {
|
||||
const manifestPath = path.resolve(process.cwd(), 'manifest.json');
|
||||
const manifestData = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
||||
const currentVersion = manifestData.version;
|
||||
|
||||
manifestData.version = originalManifestVersion;
|
||||
writeFileSync(manifestPath, JSON.stringify(manifestData, null, '\t') + '\n');
|
||||
console.log(`♻️ Rolled back manifest.json version: ${currentVersion} → ${originalManifestVersion}`);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to rollback manifest.json version:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Create Git commit and tag
|
||||
* @param {string} version - New version
|
||||
*/
|
||||
const createGitCommitAndTag = (version) => {
|
||||
try {
|
||||
// Stage changed files
|
||||
try {
|
||||
execSync('git add package.json manifest.json versions.json', { stdio: 'inherit' });
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to stage package.json, versions.json and manifest.json:', error.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to stage release files
|
||||
try {
|
||||
execSync(`git add ${RELEASE_FILES.join(' ')}`, { stdio: 'inherit' });
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Note: Some release files could not be staged. This may be normal if they are gitignored.');
|
||||
}
|
||||
|
||||
// Create commit
|
||||
const commitMessage = `chore: release ${version}`;
|
||||
execSync(`git commit -m "${commitMessage}"`, { stdio: 'inherit' });
|
||||
console.log(`✅ Commit created: ${commitMessage}`);
|
||||
|
||||
// Create tag
|
||||
const tagName = `${version}`;
|
||||
execSync(`git tag -a ${tagName} -m "Release ${tagName}"`, { stdio: 'inherit' });
|
||||
console.log(`🏷️ Tag created: ${tagName}`);
|
||||
|
||||
// Push changes
|
||||
execSync('git push', { stdio: 'inherit' });
|
||||
execSync('git push --tags', { stdio: 'inherit' });
|
||||
console.log('🚀 Changes pushed to GitHub');
|
||||
console.log('📦 GitHub Actions will create the release with artifact attestations.');
|
||||
return true; // Successfully created commit, tag, and pushed
|
||||
} catch (error) {
|
||||
console.error('❌ Error during Git operations:', error.message);
|
||||
return false; // Failed to complete Git operations
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if Git working tree is clean
|
||||
* @returns {boolean} Whether the working tree is clean
|
||||
*/
|
||||
const isGitWorkingTreeClean = () => {
|
||||
try {
|
||||
// Check for uncommitted changes
|
||||
const output = execSync('git status --porcelain', { encoding: 'utf-8' });
|
||||
return output.trim() === '';
|
||||
} catch (error) {
|
||||
console.error('❌ Error checking Git status:', error.message);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Main function
|
||||
*/
|
||||
const main = () => {
|
||||
let success = true;
|
||||
let newVersion = '';
|
||||
|
||||
try {
|
||||
// Check for uncommitted changes
|
||||
if (!isGitWorkingTreeClean()) {
|
||||
console.error('❌ Cannot proceed with release: You have uncommitted changes.');
|
||||
console.log('Please commit or stash your changes before running the release script.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check command line arguments
|
||||
const args = process.argv.slice(2);
|
||||
const versionType = args[0] || DEFAULT_VERSION_TYPE;
|
||||
|
||||
if (!Object.values(VERSION_TYPES).includes(versionType)) {
|
||||
console.error(`❌ Invalid version type: ${versionType}`);
|
||||
console.log(`Valid options: ${Object.values(VERSION_TYPES).join(', ')}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let previousVersion = getPreviousVersion()
|
||||
|
||||
// Step 1: Update package.json version
|
||||
try {
|
||||
newVersion = updatePackageVersion(versionType);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to update package.json version:', error.message);
|
||||
success = false;
|
||||
}
|
||||
|
||||
// Step 2: Update manifest.json version
|
||||
if (success) {
|
||||
try {
|
||||
updateManifestVersion(newVersion);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to update manifest.json version:', error.message);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2.5: Update versions.json version
|
||||
if (success) {
|
||||
try {
|
||||
updateVersionsVersion(previousVersion, newVersion, MIN_APP_VERSION);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to update versions.json version:', error.message);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: Build the project
|
||||
if (success) {
|
||||
if (!buildProject()) {
|
||||
console.error('❌ Build process failed.');
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: Git operations
|
||||
if (success) {
|
||||
if (!createGitCommitAndTag(newVersion)) {
|
||||
console.error('❌ Git operations failed.');
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check overall success
|
||||
if (success) {
|
||||
console.log(`\n🎉 Release ${newVersion} completed successfully!`);
|
||||
} else {
|
||||
console.error('❌ Release process failed. Rolling back version changes...');
|
||||
rollbackVersions();
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Unexpected error during release process:', error.message);
|
||||
rollbackVersions();
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
// Run script
|
||||
main();
|
||||
61
scripts/update-icons.mjs
Normal file
61
scripts/update-icons.mjs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import { readdirSync, readFileSync, writeFileSync, copyFileSync } from "fs";
|
||||
import { join, dirname } from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = join(__dirname, "..");
|
||||
const iconsDir = join(rootDir, "node_modules/iconoir/icons/regular");
|
||||
const cssSource = join(rootDir, "node_modules/iconoir/css/iconoir.css");
|
||||
|
||||
console.log("Updating Iconoir icons...\n");
|
||||
|
||||
const iconNames = readdirSync(iconsDir)
|
||||
.filter((f) => f.endsWith(".svg"))
|
||||
.map((f) => f.replace(".svg", ""))
|
||||
.sort();
|
||||
|
||||
console.log(`Found ${iconNames.length} icons`);
|
||||
|
||||
const tsContent = `export const iconoirNames: string[] = [
|
||||
${iconNames.map((name) => ` "${name}",`).join("\n")}
|
||||
];
|
||||
|
||||
export const iconoir: Record<string, string> = Object.fromEntries(
|
||||
iconoirNames.map(name => [name, \`iconoir-\${name}\`])
|
||||
);
|
||||
`;
|
||||
|
||||
writeFileSync(join(rootDir, "src/iconoirNames.ts"), tsContent);
|
||||
console.log("Updated src/iconoirNames.ts");
|
||||
|
||||
const cssContent = readFileSync(cssSource, "utf-8");
|
||||
const pluginCss = `
|
||||
/* Plugin-specific styles */
|
||||
.obsidian-iconoir-icon {
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Override iconoir defaults with custom properties when set */
|
||||
.obsidian-iconoir-icon i[class^='iconoir-']::before,
|
||||
.obsidian-iconoir-icon i[class*=' iconoir-']::before {
|
||||
background: var(--iconoir-stroke, currentColor);
|
||||
width: var(--iconoir-width, 1em);
|
||||
height: var(--iconoir-height, 1em);
|
||||
}
|
||||
|
||||
.icon-suggester-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.suggester-icon-name {
|
||||
font-family: var(--font-monospace);
|
||||
}
|
||||
`;
|
||||
|
||||
writeFileSync(join(rootDir, "styles.css"), cssContent + pluginCss);
|
||||
console.log("Updated styles.css");
|
||||
|
||||
console.log("\nDone!");
|
||||
1390
src/iconoirNames.ts
1390
src/iconoirNames.ts
File diff suppressed because one or more lines are too long
299
src/main.ts
299
src/main.ts
|
|
@ -1,187 +1,158 @@
|
|||
import { Plugin, TFile,
|
||||
Editor, EditorPosition,
|
||||
import {
|
||||
Plugin,
|
||||
TFile,
|
||||
Editor,
|
||||
EditorPosition,
|
||||
EditorSuggestTriggerInfo,
|
||||
EditorSuggest, EditorSuggestContext,
|
||||
MarkdownPostProcessor } from 'obsidian';
|
||||
import { html, LitElement } from 'lit';
|
||||
import { iconoir } from './iconoirNames';
|
||||
|
||||
enum ComponentChoice {
|
||||
Default = "Default",
|
||||
}
|
||||
EditorSuggest,
|
||||
EditorSuggestContext,
|
||||
MarkdownPostProcessor,
|
||||
} from "obsidian";
|
||||
import { iconoirNames, iconoir } from "./iconoirNames";
|
||||
|
||||
export default class IconoirPlugin extends Plugin {
|
||||
iconoirNames: string[];
|
||||
isListItem: any;
|
||||
|
||||
async litBlockHandler(type: ComponentChoice, source: string, el: HTMLElement, ctx: any): Promise<any> {
|
||||
const element:any = document.createRange().createContextualFragment(source);
|
||||
let input = element
|
||||
if (el.instanceOf(HTMLElement)) {
|
||||
const blk = el.createEl("div", {cls: "lit-block"});
|
||||
let inputElement: HTMLElement = blk.createEl("div", {text: input, cls: "lit-innerblock"});
|
||||
}
|
||||
}
|
||||
|
||||
async onload() {
|
||||
async onload(): Promise<void> {
|
||||
this.registerEditorSuggest(new IconoirSuggester(this));
|
||||
this.registerMarkdownCodeBlockProcessor("iconoir", this.litBlockHandler.bind(this, null));
|
||||
this.registerMarkdownPostProcessor(buildPostProcessor());
|
||||
this.iconoirNames = Object.keys(iconoir);
|
||||
this.isListItem = false;
|
||||
let isRegistered = window.customElements.get('iconoir-icon');
|
||||
|
||||
const isRegistered = activeWindow.customElements.get("iconoir-icon");
|
||||
if (isRegistered === undefined) {
|
||||
window.customElements.define('iconoir-icon', IconoirIcon);
|
||||
activeWindow.customElements.define("iconoir-icon", IconoirIcon);
|
||||
}
|
||||
console.log('iconoir-icons loaded');
|
||||
}
|
||||
onunload() {
|
||||
console.log('iconoir-icons unloaded');
|
||||
}
|
||||
}
|
||||
|
||||
export function buildPostProcessor(): MarkdownPostProcessor {
|
||||
return (el) => {
|
||||
return (el) => {
|
||||
el.findAll("code").forEach((code) => {
|
||||
let text = code.innerText.trim();
|
||||
if (text.startsWith('~![')) {
|
||||
let frag = text.substring(2).trim();
|
||||
if (frag.endsWith(']')) {
|
||||
let content = frag.substring(frag.length-1,1).trim();
|
||||
const arr = (code.parentElement?.tagName === 'TD' || code.parentElement?.tagName === 'TH')
|
||||
? content.split('\\|')
|
||||
: content.split('|');
|
||||
if (arr[0] === '' || arr[0] === undefined) {
|
||||
return '';
|
||||
}
|
||||
if (code.parentElement?.tagName === 'LI') {
|
||||
code.parentElement?.addClass('special-iconoir-list-callout');
|
||||
code.parentElement?.setAttr("data-icon", arr[0]);
|
||||
}
|
||||
if (code.parentElement?.tagName === 'TH') {
|
||||
code.parentElement?.addClass('special-iconoir-th-callout');
|
||||
code.parentElement?.setAttr("data-icon", arr[0]);
|
||||
}
|
||||
if (code.parentElement?.tagName === 'TD') {
|
||||
code.parentElement?.addClass('special-iconoir-td-callout');
|
||||
code.parentElement?.setAttr("data-icon", arr[0]);
|
||||
}
|
||||
let newEl = document.createElement("iconoir-icon");
|
||||
newEl.setAttribute('name',arr[0]);
|
||||
newEl.setAttribute('aria-label',arr[0]+' icon');
|
||||
newEl.setAttribute('aria-label-position', 'top');
|
||||
if (arr[1] !== undefined) {
|
||||
newEl.setAttribute('stroke',arr[1]);
|
||||
}
|
||||
if (arr[2] !== undefined) {
|
||||
newEl.setAttribute('width',arr[2]);
|
||||
}
|
||||
if (arr[3] !== undefined) {
|
||||
newEl.setAttribute('height',arr[3]);
|
||||
}
|
||||
if (arr[4] !== undefined) {
|
||||
newEl.setAttribute('style',arr[4]);
|
||||
}
|
||||
code.parentNode?.replaceChild(newEl, code);
|
||||
}
|
||||
const text = code.innerText.trim();
|
||||
if (!text.startsWith("~![")) return;
|
||||
|
||||
const frag = text.substring(2).trim();
|
||||
if (!frag.endsWith("]")) return;
|
||||
|
||||
const content = frag.slice(1, -1).trim();
|
||||
const isTableCell =
|
||||
code.parentElement?.tagName === "TD" ||
|
||||
code.parentElement?.tagName === "TH";
|
||||
const arr = isTableCell ? content.split("\\|") : content.split("|");
|
||||
|
||||
if (!arr[0]) return;
|
||||
|
||||
const iconName = arr[0];
|
||||
const parentTag = code.parentElement?.tagName;
|
||||
|
||||
if (parentTag === "LI") {
|
||||
code.parentElement?.addClass("special-iconoir-list-callout");
|
||||
code.parentElement?.setAttr("data-icon", iconName);
|
||||
}
|
||||
})
|
||||
}
|
||||
if (parentTag === "TH") {
|
||||
code.parentElement?.addClass("special-iconoir-th-callout");
|
||||
code.parentElement?.setAttr("data-icon", iconName);
|
||||
}
|
||||
if (parentTag === "TD") {
|
||||
code.parentElement?.addClass("special-iconoir-td-callout");
|
||||
code.parentElement?.setAttr("data-icon", iconName);
|
||||
}
|
||||
|
||||
const newEl = activeDocument.createElement("iconoir-icon");
|
||||
newEl.setAttribute("name", iconName);
|
||||
newEl.setAttribute("aria-label", `${iconName} icon`);
|
||||
newEl.setAttribute("data-tooltip-position", "top");
|
||||
|
||||
if (arr[1]) newEl.setAttribute("stroke", arr[1]);
|
||||
if (arr[2]) newEl.setAttribute("width", arr[2]);
|
||||
if (arr[3]) newEl.setAttribute("height", arr[3]);
|
||||
if (arr[4]) newEl.setAttribute("style", arr[4]);
|
||||
|
||||
code.parentNode?.replaceChild(newEl, code);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
class IconoirSuggester extends EditorSuggest<string> {
|
||||
plugin: IconoirPlugin;
|
||||
plugin: IconoirPlugin;
|
||||
|
||||
constructor(plugin: IconoirPlugin) {
|
||||
super(plugin.app);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
onTrigger(cursor: EditorPosition, editor: Editor, _: TFile): EditorSuggestTriggerInfo | null {
|
||||
// let foo='bar';
|
||||
// if (foo==='bar') {
|
||||
const sub = editor.getLine(cursor.line).substring(0, cursor.ch);
|
||||
const match = sub.match(/&&\S+$/)?.first();
|
||||
if (match) {
|
||||
return {
|
||||
end: cursor,
|
||||
start: {
|
||||
ch: sub.lastIndexOf(match),
|
||||
line: cursor.line,
|
||||
},
|
||||
query: match,
|
||||
}
|
||||
}
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
getSuggestions(context: EditorSuggestContext): string[] {
|
||||
let iconoir_query = context.query.replace('&&', '').toLowerCase();
|
||||
return this.plugin.iconoirNames.filter(p => p.includes(iconoir_query));
|
||||
constructor(plugin: IconoirPlugin) {
|
||||
super(plugin.app);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
renderSuggestion(suggestion: string, el: HTMLElement): void {
|
||||
const outer = el.createDiv({ cls: "icon-suggester-container" });
|
||||
outer.createDiv({ cls: "iconoir-icon-name" }).setText(suggestion);
|
||||
}
|
||||
|
||||
selectSuggestion(suggestion: string): void {
|
||||
if(this.context) {
|
||||
(this.context.editor as Editor).replaceRange('`~!['+iconoir[suggestion]+']`', this.context.start, this.context.end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class IconoirIcon extends LitElement {
|
||||
name: string;
|
||||
stroke: string;
|
||||
width: string;
|
||||
height: string;
|
||||
css: string;
|
||||
static get properties() {
|
||||
return {
|
||||
name: { type: String },
|
||||
stroke: { type: String },
|
||||
width: { type: String },
|
||||
height: { type: String },
|
||||
css: { type: String }
|
||||
}
|
||||
}
|
||||
constructor() {
|
||||
super();
|
||||
this.name = 'iconoir-1st-medal';
|
||||
this.stroke = 'currentColor';
|
||||
this.width = '1.2em';
|
||||
this.height = '1.2em';
|
||||
this.css = '';
|
||||
onTrigger(
|
||||
cursor: EditorPosition,
|
||||
editor: Editor,
|
||||
_file: TFile
|
||||
): EditorSuggestTriggerInfo | null {
|
||||
const sub = editor.getLine(cursor.line).substring(0, cursor.ch);
|
||||
const match = sub.match(/&&\S+$/)?.first();
|
||||
if (match) {
|
||||
return {
|
||||
end: cursor,
|
||||
start: {
|
||||
ch: sub.lastIndexOf(match),
|
||||
line: cursor.line,
|
||||
},
|
||||
query: match,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getSuggestions(context: EditorSuggestContext): string[] {
|
||||
const query = context.query.replace("&&", "").toLowerCase();
|
||||
return iconoirNames.filter((name) => name.includes(query));
|
||||
}
|
||||
|
||||
renderSuggestion(suggestion: string, el: HTMLElement): void {
|
||||
const outer = el.createDiv({ cls: "icon-suggester-container" });
|
||||
outer.createEl("i", { cls: `iconoir-${suggestion}` });
|
||||
outer.createDiv({ cls: "suggester-icon-name" }).setText(suggestion);
|
||||
}
|
||||
|
||||
selectSuggestion(suggestion: string): void {
|
||||
if (this.context) {
|
||||
const replacement = "`~![" + iconoir[suggestion] + "]`";
|
||||
this.context.editor.replaceRange(
|
||||
replacement,
|
||||
this.context.start,
|
||||
this.context.end
|
||||
);
|
||||
}
|
||||
}
|
||||
render() {
|
||||
return html`
|
||||
<i class="${this.name}" style="${this.css}"></i>
|
||||
<style>
|
||||
i[class^="iconoir-"]::before,
|
||||
i[class*=" iconoir-"]::before {
|
||||
content: " ";
|
||||
display: var(--special-display);
|
||||
-webkit-mask-image:var(--${this.name});
|
||||
mask-image:var(--${this.name});
|
||||
background: ${this.stroke};
|
||||
mask-size: cover;
|
||||
-webkit-mask-size: cover;
|
||||
width: ${this.width};
|
||||
height: ${this.height};
|
||||
}
|
||||
i[class^="iconoir-"],
|
||||
i[class*=" iconoir-"] {
|
||||
display:inline-flex !important;
|
||||
border: var(--special-border);
|
||||
margin: var(--special-margin);
|
||||
padding: var(--special-padding);
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
class IconoirIcon extends HTMLElement {
|
||||
static get observedAttributes(): string[] {
|
||||
return ["name", "stroke", "width", "height"];
|
||||
}
|
||||
|
||||
connectedCallback(): void {
|
||||
this.render();
|
||||
}
|
||||
|
||||
attributeChangedCallback(): void {
|
||||
this.render();
|
||||
}
|
||||
|
||||
private render(): void {
|
||||
const name = this.getAttribute("name") ?? "iconoir-star";
|
||||
const stroke = this.getAttribute("stroke") ?? "currentColor";
|
||||
const width = this.getAttribute("width") ?? "1.2em";
|
||||
const height = this.getAttribute("height") ?? "1.2em";
|
||||
|
||||
this.classList.add("obsidian-iconoir-icon");
|
||||
|
||||
if (!this.querySelector("i")) {
|
||||
const icon = activeDocument.createElement("i");
|
||||
this.appendChild(icon);
|
||||
}
|
||||
|
||||
const icon = this.querySelector("i") as HTMLElement;
|
||||
if (icon) {
|
||||
icon.className = name;
|
||||
icon.style.setProperty("--iconoir-stroke", stroke);
|
||||
icon.style.setProperty("--iconoir-width", width);
|
||||
icon.style.setProperty("--iconoir-height", height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1399
styles.css
1399
styles.css
File diff suppressed because one or more lines are too long
|
|
@ -19,6 +19,6 @@
|
|||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
"src/**/*.ts"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
{
|
||||
"1.0.1": "0.15.0",
|
||||
"1.0.0": "0.15.0"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue